updated Bank service routine email sender and wag managment application page completed
This commit is contained in:
parent
090567ade8
commit
346b132f4c
|
|
@ -109,7 +109,6 @@ def set_account_records_to_send_email() -> bool:
|
||||||
|
|
||||||
if balance_error:
|
if balance_error:
|
||||||
print(f"Balance error detected {expected_second_balance} != {second_record.bank_balance}")
|
print(f"Balance error detected {expected_second_balance} != {second_record.bank_balance}")
|
||||||
return False
|
|
||||||
|
|
||||||
# Format rows for the email template
|
# Format rows for the email template
|
||||||
list_of_rows = []
|
list_of_rows = []
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ class Applications(CrudCollection):
|
||||||
String, nullable=False, comment="Application Code"
|
String, nullable=False, comment="Application Code"
|
||||||
)
|
)
|
||||||
application_type: Mapped[str] = mapped_column(String, comment="Application Type")
|
application_type: Mapped[str] = mapped_column(String, comment="Application Type")
|
||||||
|
application_for: Mapped[str] = mapped_column(String, server_default="EMP", comment="Application For")
|
||||||
description: Mapped[str] = mapped_column(String, comment="Application Description")
|
description: Mapped[str] = mapped_column(String, comment="Application Description")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ npm install next-crypto@^1.0.8 --legacy-peer-deps
|
||||||
npm install flatpickr@^4.6.13 --legacy-peer-deps
|
npm install flatpickr@^4.6.13 --legacy-peer-deps
|
||||||
npm install date-fns@^4.1.0 --legacy-peer-deps
|
npm install date-fns@^4.1.0 --legacy-peer-deps
|
||||||
npm install react-day-picker@^8.10.1 --legacy-peer-deps
|
npm install react-day-picker@^8.10.1 --legacy-peer-deps
|
||||||
|
npm install lucide/react --legacy-peer-deps
|
||||||
|
|
||||||
echo "✨ Setup complete! You can now use shadcn/ui components in your project."
|
echo "✨ Setup complete! You can now use shadcn/ui components in your project."
|
||||||
echo "📚 Documentation: https://ui.shadcn.com/docs"
|
echo "📚 Documentation: https://ui.shadcn.com/docs"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
import React from "react";
|
||||||
|
import Header from "@/components/header/Header";
|
||||||
|
import ClientMenu from "@/components/menu/menu";
|
||||||
|
import { retrievePageByUrl } from "@/components/Pages/pageRetriever";
|
||||||
|
|
||||||
|
async function DashboardPage({
|
||||||
|
searchParams,
|
||||||
|
}: {
|
||||||
|
searchParams: Promise<{ [key: string]: string | undefined }>;
|
||||||
|
}) {
|
||||||
|
const activePage = "/application";
|
||||||
|
const searchParamsInstance = await searchParams;
|
||||||
|
const lang = (searchParamsInstance?.lang as "en" | "tr") || "en";
|
||||||
|
const PageComponent = retrievePageByUrl(activePage);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="min-h-screen min-w-screen flex h-screen w-screen">
|
||||||
|
{/* Sidebar */}
|
||||||
|
<aside className="w-1/4 border-r p-4 overflow-y-auto">
|
||||||
|
<ClientMenu lang={lang} activePage={activePage} />
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
{/* Main Content Area */}
|
||||||
|
<div className="flex flex-col w-3/4 overflow-y-auto">
|
||||||
|
{/* Header Component */}
|
||||||
|
<Header lang={lang} />
|
||||||
|
<PageComponent lang={lang} queryParams={searchParamsInstance} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DashboardPage;
|
||||||
|
|
@ -1,8 +1,370 @@
|
||||||
import React from "react";
|
"use client";
|
||||||
import { PageProps } from "@/components/validations/translations/translation";
|
import React, { useState } from "react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
import { User, Building, Save, Filter, Search, Link } from "lucide-react";
|
||||||
|
import {
|
||||||
|
PageProps,
|
||||||
|
LanguageTranslation,
|
||||||
|
} from "@/components/validations/translations/translation";
|
||||||
|
|
||||||
const ApplicationPage: React.FC<PageProps> = () => {
|
interface ApplicationData {
|
||||||
return <div>ApplicationPage</div>;
|
name: string;
|
||||||
|
application_code: string;
|
||||||
|
site_url: string;
|
||||||
|
application_type: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const translations: Record<string, LanguageTranslation> = {
|
||||||
|
typeSelection: {
|
||||||
|
en: "Type Selection",
|
||||||
|
tr: "Tür Seçimi",
|
||||||
|
},
|
||||||
|
filterSelection: {
|
||||||
|
en: "Filter Selection",
|
||||||
|
tr: "Filtre Seçimi",
|
||||||
|
},
|
||||||
|
employee: {
|
||||||
|
en: "Employee",
|
||||||
|
tr: "Çalışan",
|
||||||
|
},
|
||||||
|
occupant: {
|
||||||
|
en: "Occupant",
|
||||||
|
tr: "Sakin",
|
||||||
|
},
|
||||||
|
search: {
|
||||||
|
en: "Search",
|
||||||
|
tr: "Ara",
|
||||||
|
},
|
||||||
|
siteUrl: {
|
||||||
|
en: "Site URL",
|
||||||
|
tr: "Site URL",
|
||||||
|
},
|
||||||
|
applicationType: {
|
||||||
|
en: "Application Type",
|
||||||
|
tr: "Uygulama Türü",
|
||||||
|
},
|
||||||
|
availableApplications: {
|
||||||
|
en: "Available Applications",
|
||||||
|
tr: "Mevcut Uygulamalar",
|
||||||
|
},
|
||||||
|
code: {
|
||||||
|
en: "Code",
|
||||||
|
tr: "Kod",
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
en: "URL",
|
||||||
|
tr: "URL",
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
en: "Type",
|
||||||
|
tr: "Tür",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const ApplicationPage: React.FC<PageProps> = ({ lang = "en" }) => {
|
||||||
|
const [selectedType, setSelectedType] = useState<"employee" | "occupant">(
|
||||||
|
"employee"
|
||||||
|
);
|
||||||
|
const [selectedUrl, setSelectedUrl] = useState<string>("");
|
||||||
|
const [selectedAppType, setSelectedAppType] = useState<string>("");
|
||||||
|
const [searchQuery, setSearchQuery] = useState<string>("");
|
||||||
|
const [applicationData, setApplicationData] = useState<ApplicationData>({
|
||||||
|
name: "",
|
||||||
|
application_code: "",
|
||||||
|
site_url: "",
|
||||||
|
application_type: "",
|
||||||
|
description: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Available options for dropdowns
|
||||||
|
const urlOptions = [
|
||||||
|
"/dashboard",
|
||||||
|
"/individual",
|
||||||
|
"/user",
|
||||||
|
"/settings",
|
||||||
|
"/reports",
|
||||||
|
];
|
||||||
|
const typeOptions = ["info", "Dash", "Admin"];
|
||||||
|
|
||||||
|
// Handle selection button click
|
||||||
|
const handleTypeSelect = (type: "employee" | "occupant") => {
|
||||||
|
setSelectedType(type);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle application data input changes
|
||||||
|
const handleInputChange = (name: string, value: string) => {
|
||||||
|
setApplicationData({
|
||||||
|
...applicationData,
|
||||||
|
[name]: value,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Sample application data for the grid
|
||||||
|
const sampleApplications = [
|
||||||
|
{
|
||||||
|
name: "Dashboard",
|
||||||
|
application_code: "app000001",
|
||||||
|
site_url: "/dashboard",
|
||||||
|
application_type: "info",
|
||||||
|
description: "Dashboard Page",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Individual",
|
||||||
|
application_code: "app000003",
|
||||||
|
site_url: "/individual",
|
||||||
|
application_type: "Dash",
|
||||||
|
description: "Individual Page for people",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "User",
|
||||||
|
application_code: "app000004",
|
||||||
|
site_url: "/user",
|
||||||
|
application_type: "Dash",
|
||||||
|
description: "Individual Page for user",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Settings",
|
||||||
|
application_code: "app000005",
|
||||||
|
site_url: "/settings",
|
||||||
|
application_type: "Admin",
|
||||||
|
description: "Settings Page",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Reports",
|
||||||
|
application_code: "app000006",
|
||||||
|
site_url: "/reports",
|
||||||
|
application_type: "info",
|
||||||
|
description: "Reports Page",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// Generate grid of application cards
|
||||||
|
const renderApplicationGrid = () => {
|
||||||
|
return sampleApplications.map((app, index) => (
|
||||||
|
<div key={index} className="w-full sm:w-1/5 p-1">
|
||||||
|
<Card className="h-full hover:bg-accent/50 cursor-pointer transition-colors">
|
||||||
|
<CardContent className="p-3">
|
||||||
|
<div className="font-medium text-sm mb-1">{app.name}</div>
|
||||||
|
<div className="space-y-0.5 text-xs">
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-muted-foreground w-10">
|
||||||
|
{translations.code[lang]}:
|
||||||
|
</span>
|
||||||
|
<span className="truncate">{app.application_code}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-muted-foreground w-10">
|
||||||
|
{translations.url[lang]}:
|
||||||
|
</span>
|
||||||
|
<span className="truncate">{app.site_url}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<span className="text-muted-foreground w-10">
|
||||||
|
{translations.type[lang]}:
|
||||||
|
</span>
|
||||||
|
<span className="truncate">{app.application_type}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="container mx-auto p-4 space-y-6">
|
||||||
|
{/* Selection Buttons */}
|
||||||
|
<Card>
|
||||||
|
<CardContent className="pt-6">
|
||||||
|
<div className="flex flex-row">
|
||||||
|
{/* User type selection - vertical on the left (w-1/2) */}
|
||||||
|
<div className="w-1/2 flex flex-col space-y-4 pr-4">
|
||||||
|
<div className="font-medium text-sm mb-2 flex items-center">
|
||||||
|
<User className="mr-2 h-4 w-4" />
|
||||||
|
{translations.typeSelection[lang]}
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
variant={selectedType === "employee" ? "default" : "outline"}
|
||||||
|
size="lg"
|
||||||
|
onClick={() => handleTypeSelect("employee")}
|
||||||
|
className="w-full h-14 mb-2"
|
||||||
|
>
|
||||||
|
<User className="mr-2 h-4 w-4" />
|
||||||
|
{translations.employee[lang]}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant={selectedType === "occupant" ? "default" : "outline"}
|
||||||
|
size="lg"
|
||||||
|
onClick={() => handleTypeSelect("occupant")}
|
||||||
|
className="w-full h-14"
|
||||||
|
>
|
||||||
|
<Building className="mr-2 h-4 w-4" />
|
||||||
|
{translations.occupant[lang]}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Filters on the right (w-1/2) */}
|
||||||
|
<div className="w-1/2 flex flex-col space-y-4 pl-4">
|
||||||
|
<div className="font-medium text-sm mb-2 flex items-center">
|
||||||
|
<Filter className="mr-2 h-4 w-4" />
|
||||||
|
{translations.filterSelection[lang]}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Search input */}
|
||||||
|
<div className="w-full">
|
||||||
|
<label className="block text-xs font-medium mb-1">
|
||||||
|
{translations.search[lang]}
|
||||||
|
</label>
|
||||||
|
<div className="relative w-full">
|
||||||
|
<Input
|
||||||
|
placeholder={`${translations.search[lang]}...`}
|
||||||
|
value={searchQuery}
|
||||||
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
|
className="pl-8 w-full h-10"
|
||||||
|
/>
|
||||||
|
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Site URL dropdown */}
|
||||||
|
<div className="w-full">
|
||||||
|
<label className="block text-xs font-medium mb-1">
|
||||||
|
{translations.siteUrl[lang]}
|
||||||
|
</label>
|
||||||
|
<div className="w-full">
|
||||||
|
<Select value={selectedUrl} onValueChange={setSelectedUrl}>
|
||||||
|
<SelectTrigger className="w-full h-10">
|
||||||
|
<SelectValue
|
||||||
|
placeholder={`${translations.siteUrl[lang]}...`}
|
||||||
|
/>
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{urlOptions.map((url) => (
|
||||||
|
<SelectItem key={url} value={url}>
|
||||||
|
<div className="flex items-center">
|
||||||
|
<Link className="mr-2 h-3 w-3" />
|
||||||
|
{url}
|
||||||
|
</div>
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* Grid of Application Cards */}
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>{translations.availableApplications[lang]}</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="flex flex-wrap -mx-2">{renderApplicationGrid()}</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* Application Data Form */}
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Application Details</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium mb-1">Name</label>
|
||||||
|
<Input
|
||||||
|
name="name"
|
||||||
|
value={applicationData.name}
|
||||||
|
onChange={(e) => handleInputChange("name", e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium mb-1">
|
||||||
|
Application Code
|
||||||
|
</label>
|
||||||
|
<Input
|
||||||
|
name="application_code"
|
||||||
|
value={applicationData.application_code}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleInputChange("application_code", e.target.value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium mb-1">Site URL</label>
|
||||||
|
<Input
|
||||||
|
name="site_url"
|
||||||
|
value={applicationData.site_url}
|
||||||
|
onChange={(e) => handleInputChange("site_url", e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium mb-1">
|
||||||
|
Application Type
|
||||||
|
</label>
|
||||||
|
<Select
|
||||||
|
value={applicationData.application_type}
|
||||||
|
onValueChange={(value) =>
|
||||||
|
handleInputChange("application_type", value)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder="Select application type" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="info">Info</SelectItem>
|
||||||
|
<SelectItem value="Dash">Dash</SelectItem>
|
||||||
|
<SelectItem value="Admin">Admin</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mb-4">
|
||||||
|
<label className="block text-sm font-medium mb-1">
|
||||||
|
Description
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
name="description"
|
||||||
|
className="w-full min-h-[100px] rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm"
|
||||||
|
value={applicationData.description}
|
||||||
|
onChange={(e) => handleInputChange("description", e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-end">
|
||||||
|
<Button>
|
||||||
|
<Save className="mr-2 h-4 w-4" />
|
||||||
|
Save Application
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* Display current application data */}
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Current Application Data</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<pre className="bg-muted p-4 rounded-md overflow-auto">
|
||||||
|
{JSON.stringify(applicationData, null, 2)}
|
||||||
|
</pre>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ApplicationPage;
|
export default ApplicationPage;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue