From 0052c9297427c24575c9dcac62db58b9cbd961e8 Mon Sep 17 00:00:00 2001 From: Berkay Date: Tue, 29 Apr 2025 20:44:39 +0300 Subject: [PATCH] Card Component implemented --- .../InitialService/init_app_defaults.py | 7 +- .../InitialService/init_occ_defaults.py | 81 +++-- WebServices/client-frontend/setup-shadcn.sh | 30 +- .../management-frontend/setup-shadcn.sh | 30 +- .../src/app/api/applications/route.ts | 86 +++++ .../src/app/api/data/route.ts | 146 ++++++++ .../src/app/card-example/page.tsx | 313 ++++++++++++++++++ .../src/app/example/page.tsx | 208 ++++++++++++ .../Pages/application/SearchComponent.tsx | 22 +- .../commons/ActionButtonsComponent.tsx | 49 +++ .../commons/CardDisplay/CardDisplay.tsx | 73 ++++ .../commons/CardDisplay/CardItem.tsx | 132 ++++++++ .../commons/CardDisplay/CardSkeleton.tsx | 46 +++ .../components/commons/CardDisplay/index.tsx | 1 + .../components/commons/CardDisplay/schema.ts | 117 +++++++ .../components/commons/CardDisplay/utils.ts | 46 +++ .../src/components/commons/FormDisplay.tsx | 39 +++ .../commons/PaginationToolsComponent.tsx | 199 +++++++++++ .../components/commons/SearchComponent.tsx | 221 +++++++++++++ .../components/commons/hooks/useApiData.ts | 75 +++++ .../commons/hooks/useDataFetching.ts | 193 +++++++++++ .../src/components/commons/index.ts | 9 + .../componentGroups/CardDisplay/ReadMe.md | 86 +++++ .../Screenshot from 2025-04-29 19-36-45.png | Bin 0 -> 68479 bytes .../src/components/ui/skeleton.tsx | 13 + .../src/components/ui/table.tsx | 116 +++++++ 26 files changed, 2273 insertions(+), 65 deletions(-) create mode 100644 WebServices/management-frontend/src/app/api/applications/route.ts create mode 100644 WebServices/management-frontend/src/app/api/data/route.ts create mode 100644 WebServices/management-frontend/src/app/card-example/page.tsx create mode 100644 WebServices/management-frontend/src/app/example/page.tsx create mode 100644 WebServices/management-frontend/src/components/commons/ActionButtonsComponent.tsx create mode 100644 WebServices/management-frontend/src/components/commons/CardDisplay/CardDisplay.tsx create mode 100644 WebServices/management-frontend/src/components/commons/CardDisplay/CardItem.tsx create mode 100644 WebServices/management-frontend/src/components/commons/CardDisplay/CardSkeleton.tsx create mode 100644 WebServices/management-frontend/src/components/commons/CardDisplay/index.tsx create mode 100644 WebServices/management-frontend/src/components/commons/CardDisplay/schema.ts create mode 100644 WebServices/management-frontend/src/components/commons/CardDisplay/utils.ts create mode 100644 WebServices/management-frontend/src/components/commons/FormDisplay.tsx create mode 100644 WebServices/management-frontend/src/components/commons/PaginationToolsComponent.tsx create mode 100644 WebServices/management-frontend/src/components/commons/SearchComponent.tsx create mode 100644 WebServices/management-frontend/src/components/commons/hooks/useApiData.ts create mode 100644 WebServices/management-frontend/src/components/commons/hooks/useDataFetching.ts create mode 100644 WebServices/management-frontend/src/components/commons/index.ts create mode 100644 WebServices/management-frontend/src/components/componentGroups/CardDisplay/ReadMe.md create mode 100644 WebServices/management-frontend/src/components/componentGroups/CardDisplay/Screenshot from 2025-04-29 19-36-45.png create mode 100644 WebServices/management-frontend/src/components/ui/skeleton.tsx create mode 100644 WebServices/management-frontend/src/components/ui/table.tsx diff --git a/ApiServices/InitialService/init_app_defaults.py b/ApiServices/InitialService/init_app_defaults.py index 8f3094b..65fa709 100644 --- a/ApiServices/InitialService/init_app_defaults.py +++ b/ApiServices/InitialService/init_app_defaults.py @@ -525,22 +525,23 @@ def create_application_defaults(db_session): sup_manager_employee.password_token = PasswordModule.generate_refresher_token() with mongo_handler.collection(collection_name) as mongo_engine: existing_record = mongo_engine.find_one({"user_uu_id": str(sup_manager_employee.uu_id)}) - if not existing_record: + print('insert sup existing record',existing_record) mongo_engine.insert_one( document={ "user_uu_id": str(sup_manager_employee.uu_id), - "other_domains_list": [main_domain], + "other_domains_list": [main_domain, "management.com.tr"], "main_domain": main_domain, "modified_at": arrow.now().timestamp(), } ) else: + print('update sup existing record',existing_record) # Optionally update the existing record if needed mongo_engine.update_one( {"user_uu_id": str(sup_manager_employee.uu_id)}, {"$set": { - "other_domains_list": [main_domain], + "other_domains_list": [main_domain, "management.com.tr"], "main_domain": main_domain, "modified_at": arrow.now().timestamp(), }} diff --git a/ApiServices/InitialService/init_occ_defaults.py b/ApiServices/InitialService/init_occ_defaults.py index 23ddfb8..fd27063 100644 --- a/ApiServices/InitialService/init_occ_defaults.py +++ b/ApiServices/InitialService/init_occ_defaults.py @@ -239,34 +239,67 @@ def create_occupant_defaults(db_session): user_tenant.password_token = PasswordModule.generate_refresher_token() with mongo_handler.collection(collection_name) as mongo_engine: - mongo_engine.insert_one( - document={ - "user_uu_id": str(user_build_manager.uu_id), - "other_domains_list": [main_domain], - "main_domain": main_domain, - "modified_at": arrow.now().timestamp(), - } - ) + existing_record = mongo_engine.find_one({"user_uu_id": str(user_build_manager.uu_id)}) + if not existing_record: + mongo_engine.insert_one( + document={ + "user_uu_id": str(user_build_manager.uu_id), + "other_domains_list": [main_domain], + "main_domain": main_domain, + "modified_at": arrow.now().timestamp(), + } + ) + else: + mongo_engine.update_one( + {"user_uu_id": str(user_build_manager.uu_id)}, + {"$set": { + "other_domains_list": [main_domain], + "main_domain": main_domain, + "modified_at": arrow.now().timestamp(), + }} + ) with mongo_handler.collection(collection_name) as mongo_engine: - mongo_engine.insert_one( - document={ - "user_uu_id": str(user_owner.uu_id), - "other_domains_list": [main_domain], - "main_domain": main_domain, - "modified_at": arrow.now().timestamp(), - } - ) + existing_record = mongo_engine.find_one({"user_uu_id": str(user_owner.uu_id)}) + if not existing_record: + mongo_engine.insert_one( + document={ + "user_uu_id": str(user_owner.uu_id), + "other_domains_list": [main_domain], + "main_domain": main_domain, + "modified_at": arrow.now().timestamp(), + } + ) + else: + mongo_engine.update_one( + {"user_uu_id": str(user_owner.uu_id)}, + {"$set": { + "other_domains_list": [main_domain], + "main_domain": main_domain, + "modified_at": arrow.now().timestamp(), + }} + ) with mongo_handler.collection(collection_name) as mongo_engine: - mongo_engine.insert_one( - document={ - "user_uu_id": str(user_tenant.uu_id), - "other_domains_list": [main_domain], - "main_domain": main_domain, - "modified_at": arrow.now().timestamp(), - } - ) + existing_record = mongo_engine.find_one({"user_uu_id": str(user_tenant.uu_id)}) + if not existing_record: + mongo_engine.insert_one( + document={ + "user_uu_id": str(user_tenant.uu_id), + "other_domains_list": [main_domain], + "main_domain": main_domain, + "modified_at": arrow.now().timestamp(), + } + ) + else: + mongo_engine.update_one( + {"user_uu_id": str(user_tenant.uu_id)}, + {"$set": { + "other_domains_list": [main_domain], + "main_domain": main_domain, + "modified_at": arrow.now().timestamp(), + }} + ) created_build_living_space_prs = BuildLivingSpace.find_or_create( build_id=created_build.id, diff --git a/WebServices/client-frontend/setup-shadcn.sh b/WebServices/client-frontend/setup-shadcn.sh index b3c8d15..52dec08 100755 --- a/WebServices/client-frontend/setup-shadcn.sh +++ b/WebServices/client-frontend/setup-shadcn.sh @@ -18,20 +18,22 @@ npm config set legacy-peer-deps true # Install base components echo "🧩 Installing base shadcn/ui components..." -npx shadcn@latest add button --yes -npx shadcn@latest add form --yes -npx shadcn@latest add input --yes -npx shadcn@latest add label --yes -npx shadcn@latest add select --yes -npx shadcn@latest add checkbox --yes -npx shadcn@latest add card --yes -npx shadcn@latest add dialog --yes -npx shadcn@latest add popover --yes -npx shadcn@latest add sonner --yes -npx shadcn@latest add table --yes -npx shadcn@latest add pagination --yes -npx shadcn@latest add calendar --yes -npx shadcn@latest add date-picker --yes +npx shadcn@latest add button -y +npx shadcn@latest add form -y +npx shadcn@latest add input -y +npx shadcn@latest add label -y +npx shadcn@latest add select -y +npx shadcn@latest add checkbox -y +npx shadcn@latest add card -y +npx shadcn@latest add dialog -y +npx shadcn@latest add popover -y +npx shadcn@latest add sonner -y +npx shadcn@latest add table -y +npx shadcn@latest add pagination -y +npx shadcn@latest add calendar -y +npx shadcn@latest add date-picker -y +npx shadcn@latest add skeleton -y +npx shadcn@latest add table -y # Update any dependencies with legacy peer deps echo "🔄 Updating dependencies..." diff --git a/WebServices/management-frontend/setup-shadcn.sh b/WebServices/management-frontend/setup-shadcn.sh index 0ba99ad..7897184 100755 --- a/WebServices/management-frontend/setup-shadcn.sh +++ b/WebServices/management-frontend/setup-shadcn.sh @@ -18,20 +18,22 @@ npm config set legacy-peer-deps true # Install base components echo "🧩 Installing base shadcn/ui components..." -npx shadcn@latest add button --yes -npx shadcn@latest add form --yes -npx shadcn@latest add input --yes -npx shadcn@latest add label --yes -npx shadcn@latest add select --yes -npx shadcn@latest add checkbox --yes -npx shadcn@latest add card --yes -npx shadcn@latest add dialog --yes -npx shadcn@latest add popover --yes -npx shadcn@latest add sonner --yes -npx shadcn@latest add table --yes -npx shadcn@latest add pagination --yes -npx shadcn@latest add calendar --yes -npx shadcn@latest add date-picker --yes +npx shadcn@latest add button -y +npx shadcn@latest add form -y +npx shadcn@latest add input -y +npx shadcn@latest add label -y +npx shadcn@latest add select -y +npx shadcn@latest add checkbox -y +npx shadcn@latest add card -y +npx shadcn@latest add dialog -y +npx shadcn@latest add popover -y +npx shadcn@latest add sonner -y +npx shadcn@latest add table -y +npx shadcn@latest add pagination -y +npx shadcn@latest add calendar -y +npx shadcn@latest add date-picker -y +npx shadcn@latest add skeleton -y +npx shadcn@latest add table -y # Update any dependencies with legacy peer deps echo "🔄 Updating dependencies..." diff --git a/WebServices/management-frontend/src/app/api/applications/route.ts b/WebServices/management-frontend/src/app/api/applications/route.ts new file mode 100644 index 0000000..3a06901 --- /dev/null +++ b/WebServices/management-frontend/src/app/api/applications/route.ts @@ -0,0 +1,86 @@ +import { NextRequest, NextResponse } from "next/server"; +import { listApplications } from "@/apicalls/application/application"; + +export async function GET(request: NextRequest) { + try { + // Get query parameters + const searchParams = request.nextUrl.searchParams; + + // Extract pagination parameters + const page = parseInt(searchParams.get("page") || "1"); + const size = parseInt(searchParams.get("size") || "10"); + + // Extract sorting parameters + const orderField = searchParams.getAll("orderField") || ["name"]; + const orderType = searchParams.getAll("orderType") || ["asc"]; + + // Extract query filters + const query: Record = {}; + for (const [key, value] of searchParams.entries()) { + if (!["page", "size", "orderField", "orderType"].includes(key)) { + query[key] = value; + } + } + + // Call the actual API function + const response = await listApplications({ + page, + size, + orderField, + orderType, + query, + }); + + // Return the response + return NextResponse.json({ + data: response.data || [], + pagination: response.pagination || { + page, + size, + totalCount: 0, + totalItems: 0, + totalPages: 0, + pageCount: 0, + orderField, + orderType, + query, + next: false, + back: false, + }, + }); + } catch (error) { + console.error("API error:", error); + return NextResponse.json( + { error: "Internal Server Error" }, + { status: 500 } + ); + } +} + +export async function POST(request: NextRequest) { + try { + const body = await request.json(); + + // Here you would call your actual API function to create a new application + // For example: const result = await createApplication(body); + + // For now, we'll return a mock response + return NextResponse.json( + { + success: true, + data: { + id: Math.floor(Math.random() * 1000), + ...body, + createdAt: new Date().toISOString(), + }, + }, + { status: 201 } + ); + } catch (error) { + console.error("API error:", error); + return NextResponse.json( + { error: "Internal Server Error" }, + { status: 500 } + ); + } +} diff --git a/WebServices/management-frontend/src/app/api/data/route.ts b/WebServices/management-frontend/src/app/api/data/route.ts new file mode 100644 index 0000000..a9a46b9 --- /dev/null +++ b/WebServices/management-frontend/src/app/api/data/route.ts @@ -0,0 +1,146 @@ +import { NextRequest, NextResponse } from "next/server"; + +// Generic API handler that can be extended for different data types +export async function GET(request: NextRequest) { + try { + // Get query parameters + const searchParams = request.nextUrl.searchParams; + + // Extract pagination parameters + const page = parseInt(searchParams.get("page") || "1"); + const size = parseInt(searchParams.get("size") || "10"); + + // Extract sorting parameters + const orderField = searchParams.getAll("orderField") || ["name"]; + const orderType = searchParams.getAll("orderType") || ["asc"]; + + // Extract query filters + const query: Record = {}; + for (const [key, value] of searchParams.entries()) { + if (!["page", "size", "orderField", "orderType"].includes(key)) { + query[key] = value; + } + } + + // This is where you would call your actual data service + // For example: const result = await dataService.getData(page, size, orderField, orderType, query); + + // Define the data type for our mock items + interface MockItem { + id: number; + name: string; + description: string; + createdAt: string; + application_code: string; + site_url: string; + application_type: string; + [key: string]: string | number; // Index signature to allow string indexing + } + + // Generate mock data with application-specific fields + const allMockData: MockItem[] = Array.from({ length: 100 }, (_, i) => ({ + id: i + 1, + name: `Application ${i + 1}`, + description: `Description for application ${i + 1}`, + createdAt: new Date().toISOString(), + application_code: `APP-${1000 + i}`, + site_url: `/app-${i + 1}`, + application_type: i % 3 === 0 ? 'Web' : i % 3 === 1 ? 'Mobile' : 'Desktop', + })); + + // Apply filtering based on query parameters + let filteredData = [...allMockData]; + + // Apply simple filtering for demonstration + if (Object.keys(query).length > 0) { + filteredData = filteredData.filter(item => { + return Object.entries(query).every(([key, value]) => { + // Handle special operators like __ilike + if (key.includes('__ilike')) { + const actualKey = key.split('__')[0]; + const searchValue = String(value).replace(/%/g, ''); + return String(item[actualKey]).toLowerCase().includes(searchValue.toLowerCase()); + } + + // Handle exact match + return String(item[key]).toLowerCase() === String(value).toLowerCase(); + }); + }); + } + + // Apply sorting + if (orderField.length > 0 && orderType.length > 0) { + const field = orderField[0]; + const direction = orderType[0]; + + filteredData.sort((a, b) => { + if (direction === 'asc') { + return String(a[field]).localeCompare(String(b[field])); + } else { + return String(b[field]).localeCompare(String(a[field])); + } + }); + } + + // Calculate pagination metadata + const totalCount = filteredData.length; + const totalPages = Math.ceil(totalCount / size); + + // Apply pagination + const startIndex = (page - 1) * size; + const endIndex = startIndex + size; + const paginatedData = filteredData.slice(startIndex, endIndex); + + return NextResponse.json({ + data: paginatedData, + pagination: { + page, + size, + totalCount, + totalItems: totalCount, + totalPages, + pageCount: paginatedData.length, + orderField, + orderType, + query, + next: page < totalPages, + back: page > 1, + }, + }); + } catch (error) { + console.error("API error:", error); + return NextResponse.json( + { error: "Internal Server Error" }, + { status: 500 } + ); + } +} + +// POST handler for creating new items +export async function POST(request: NextRequest) { + try { + const body = await request.json(); + + // This is where you would call your actual data service to create a new item + // For example: const result = await dataService.createItem(body); + + // For now, we'll return a mock response + return NextResponse.json( + { + success: true, + data: { + id: Math.floor(Math.random() * 1000), + ...body, + createdAt: new Date().toISOString(), + }, + }, + { status: 201 } + ); + } catch (error) { + console.error("API error:", error); + return NextResponse.json( + { error: "Internal Server Error" }, + { status: 500 } + ); + } +} diff --git a/WebServices/management-frontend/src/app/card-example/page.tsx b/WebServices/management-frontend/src/app/card-example/page.tsx new file mode 100644 index 0000000..ed1988a --- /dev/null +++ b/WebServices/management-frontend/src/app/card-example/page.tsx @@ -0,0 +1,313 @@ +"use client"; +import React, { useState } from "react"; +import { CardDisplay } from "@/components/commons/CardDisplay"; +import { SearchComponent } from "@/components/commons/SearchComponent"; +import { ActionButtonsComponent } from "@/components/commons/ActionButtonsComponent"; +import { PaginationToolsComponent } from "@/components/commons/PaginationToolsComponent"; +import { useApiData } from "@/components/commons/hooks/useApiData"; +import { User, Building } from "lucide-react"; + +// Example translations +const translations = { + en: { + create: "Create", + update: "Update", + delete: "Delete", + view: "View", + search: "Search", + typeSelection: "Type Selection", + filterSelection: "Filter Selection", + siteUrl: "Site URL", + employee: "Employee", + occupant: "Occupant", + showing: "Showing", + of: "of", + items: "items", + total: "Total", + filtered: "Filtered", + previous: "Previous", + next: "Next", + page: "Page", + itemsPerPage: "Items per page", + noData: "No data found", + // Field labels + id: "ID", + name: "Name", + description: "Description", + createdAt: "Created At", + type: "Type", + status: "Status", + application_code: "Code", + site_url: "URL", + application_type: "Type" + }, + tr: { + create: "Oluştur", + update: "Güncelle", + delete: "Sil", + view: "Görüntüle", + search: "Ara", + typeSelection: "Tür Seçimi", + filterSelection: "Filtre Seçimi", + siteUrl: "Site URL", + employee: "Çalışan", + occupant: "Sakin", + showing: "Gösteriliyor", + of: "of", + items: "öğeler", + total: "Toplam", + filtered: "Filtreli", + previous: "Önceki", + next: "Sonraki", + page: "Sayfa", + itemsPerPage: "Sayfa başına öğeler", + noData: "Veri bulunamadı", + // Field labels + id: "ID", + name: "Ad", + description: "Açıklama", + createdAt: "Oluşturulma Tarihi", + type: "Tür", + status: "Durum", + application_code: "Kod", + site_url: "URL", + application_type: "Tür" + } +}; + +// Define the data type +interface ApplicationData { + id: number; + name: string; + description: string; + createdAt: string; + application_code: string; + site_url: string; + application_type: string; +} + +// Form component for create/update +const FormComponent: React.FC<{ + initialData?: ApplicationData; + mode: "create" | "update"; + refetch?: () => void; + setMode: React.Dispatch>; + setSelectedItem: React.Dispatch>; + onCancel: () => void; + lang: string; +}> = ({ initialData, mode, refetch, setMode, onCancel, lang }) => { + // In a real application, you would implement form fields and submission logic here + return ( +
+

+ {mode === "create" ? translations[lang as "en" | "tr"].create : translations[lang as "en" | "tr"].update} +

+

This is a placeholder for the {mode} form.

+
+ + +
+
+ ); +}; + +export default function CardExamplePage() { + const [lang, setLang] = useState<"en" | "tr">("en"); + const [mode, setMode] = useState<"list" | "create" | "update">("list"); + const [selectedItem, setSelectedItem] = useState(null); + const [gridCols, setGridCols] = useState<1 | 2 | 3 | 4 | 5 | 6>(3); + + // Use the API data hook + const { + data, + pagination, + loading, + error, + updatePagination, + refetch + } = useApiData("/api/data"); + + // Fields to display in the cards + const showFields = ["application_code", "site_url", "application_type"]; + + // Search options + const searchOptions = { + typeOptions: [ + { + value: "employee", + label: translations[lang].employee, + icon: + }, + { + value: "occupant", + label: translations[lang].occupant, + icon: + } + ], + urlOptions: [ + "/dashboard", + "/individual", + "/user", + "/settings", + "/reports", + ], + additionalFields: [ + { + name: "status", + label: translations[lang as "en" | "tr"].status, + type: "select", + options: [ + { value: "active", label: "Active" }, + { value: "inactive", label: "Inactive" }, + { value: "pending", label: "Pending" } + ] + } + ] + }; + + // Handle search + const handleSearch = (query: Record) => { + updatePagination({ + page: 1, // Reset to first page on new search + query: query, + }); + }; + + // Handle card actions + const handleCardClick = (item: ApplicationData) => { + console.log("Card clicked:", item); + }; + + const handleViewClick = (item: ApplicationData) => { + console.log("View clicked:", item); + // Example: Open a modal to view details + }; + + const handleUpdateClick = (item: ApplicationData) => { + console.log("Update clicked:", item); + setSelectedItem(item); + setMode("update"); + }; + + // Handle create button click + const handleCreateClick = () => { + setSelectedItem(null); + setMode("create"); + }; + + // Handle cancel + const handleCancel = () => { + setMode("list"); + setSelectedItem(null); + }; + + return ( +
+
+

Card Example Page

+
+
+ Grid Size: + +
+
+ +
+
+
+ + {mode === "list" ? ( + <> + {/* Search Component */} + + + {/* Action Buttons Component */} + + + {/* Card Display Component */} +
+ +
+ + {/* Pagination Tools Component */} +
+ +
+ + ) : ( + + )} +
+ ); +} diff --git a/WebServices/management-frontend/src/app/example/page.tsx b/WebServices/management-frontend/src/app/example/page.tsx new file mode 100644 index 0000000..5e74981 --- /dev/null +++ b/WebServices/management-frontend/src/app/example/page.tsx @@ -0,0 +1,208 @@ +"use client"; +import React, { useState } from "react"; +import { CardDisplay, useApiData } from "@/components/commons"; +import { User, Building } from "lucide-react"; + +// Example translations +const translations = { + en: { + create: "Create", + update: "Update", + delete: "Delete", + view: "View", + search: "Search", + typeSelection: "Type Selection", + filterSelection: "Filter Selection", + siteUrl: "Site URL", + employee: "Employee", + occupant: "Occupant", + showing: "Showing", + of: "of", + items: "items", + total: "Total", + filtered: "Filtered", + previous: "Previous", + next: "Next", + page: "Page", + itemsPerPage: "Items per page", + noData: "No data found", + // Field labels + id: "ID", + name: "Name", + description: "Description", + createdAt: "Created At", + type: "Type", + status: "Status" + }, + tr: { + create: "Oluştur", + update: "Güncelle", + delete: "Sil", + view: "Görüntüle", + search: "Ara", + typeSelection: "Tür Seçimi", + filterSelection: "Filtre Seçimi", + siteUrl: "Site URL", + employee: "Çalışan", + occupant: "Sakin", + showing: "Gösteriliyor", + of: "of", + items: "öğeler", + total: "Toplam", + filtered: "Filtreli", + previous: "Önceki", + next: "Sonraki", + page: "Sayfa", + itemsPerPage: "Sayfa başına öğeler", + noData: "Veri bulunamadı", + // Field labels + id: "ID", + name: "Ad", + description: "Açıklama", + createdAt: "Oluşturulma Tarihi", + type: "Tür", + status: "Durum" + } +}; + +// Define the data type +interface ExampleData { + id: number; + name: string; + description: string; + createdAt: string; + type?: string; + status?: string; +} + +// Form component for create/update +const FormComponent: React.FC<{ + initialData?: ExampleData; + mode: "create" | "update"; + refetch?: () => void; + setMode: React.Dispatch>; + setSelectedItem: React.Dispatch>; + onCancel: () => void; + lang: string; +}> = ({ initialData, mode, refetch, setMode, onCancel, lang }) => { + // In a real application, you would implement form fields and submission logic here + return ( +
+

+ {mode === "create" ? translations[lang as "en" | "tr"].create : translations[lang as "en" | "tr"].update} +

+

This is a placeholder for the {mode} form.

+
+ + +
+
+ ); +}; + +export default function ExamplePage() { + const [lang, setLang] = useState<"en" | "tr">("en"); + + // Use the API data hook + const { + data, + pagination, + loading, + error, + updatePagination, + refetch + } = useApiData("/api/data"); + + // Fields to display in the table + const showFields = ["id", "name", "description", "createdAt"]; + + // Search options + const searchOptions = { + typeOptions: [ + { + value: "employee", + label: translations[lang as "en" | "tr"].employee, + icon: + }, + { + value: "occupant", + label: translations[lang as "en" | "tr"].occupant, + icon: + } + ], + urlOptions: [ + "/dashboard", + "/individual", + "/user", + "/settings", + "/reports", + ], + additionalFields: [ + { + name: "status", + label: translations[lang as "en" | "tr"].status, + type: "select", + options: [ + { value: "active", label: "Active" }, + { value: "inactive", label: "Inactive" }, + { value: "pending", label: "Pending" } + ] + } + ] + }; + + // Custom cell renderer example + const renderCustomCell = (item: ExampleData, field: string) => { + if (field === "createdAt") { + return new Date(item.createdAt).toLocaleDateString(); + } + return item[field as keyof ExampleData]; + }; + + return ( +
+
+

Example Page

+
+ +
+
+ + + showFields={showFields} + data={data} + lang={lang} + translations={translations} + pagination={pagination} + updatePagination={updatePagination} + error={error} + loading={loading} + refetch={refetch} + searchOptions={searchOptions} + renderCustomCell={renderCustomCell} + FormComponent={FormComponent} + /> +
+ ); +} diff --git a/WebServices/management-frontend/src/components/Pages/application/SearchComponent.tsx b/WebServices/management-frontend/src/components/Pages/application/SearchComponent.tsx index 14840b1..cbd64ce 100644 --- a/WebServices/management-frontend/src/components/Pages/application/SearchComponent.tsx +++ b/WebServices/management-frontend/src/components/Pages/application/SearchComponent.tsx @@ -27,7 +27,7 @@ export const SearchComponent: React.FC = ({ // Handle selection button click const handleTypeSelect = (type: "employee" | "occupant") => { setSelectedType(type); - + // Include type in search query handleSearch(searchQuery, selectedUrl, type); }; @@ -35,13 +35,15 @@ export const SearchComponent: React.FC = ({ // Handle search with all parameters const handleSearch = (query: string, url: string, type: "employee" | "occupant") => { const searchParams: Record = {}; - + if (url) { searchParams.site_url = url; } - searchParams.name = query + if (query) { + searchParams.name = query + } searchParams.application_for = type === "employee" ? "EMP" : "OCC"; - + // Call onSearch with the search parameters // The parent component will handle resetting pagination onSearch(searchParams); @@ -102,12 +104,12 @@ export const SearchComponent: React.FC = ({ className="pl-8 w-full h-10" /> - + ))} + + )} + + {/* Filters on the right (w-1/2) */} +
0 ? 'md:w-1/2 md:pl-4' : ''} flex flex-col space-y-4`}> +
+ + {t.filterSelection || "Filter Selection"} +
+ + {/* Search input */} +
+ +
+ setSearchQuery(e.target.value)} + onKeyUp={(e) => { + if (e.key === 'Enter') { + handleSearch(searchQuery, selectedUrl, selectedType, additionalValues); + } + }} + className="pl-8 w-full h-10" + /> + + +
+
+ + {/* Site URL dropdown */} + {urlOptions.length > 0 && ( +
+ +
+ +
+
+ )} + + {/* Additional fields */} + {additionalFields.map((field) => ( +
+ + {field.type === "text" ? ( + handleAdditionalFieldChange(field.name, e.target.value)} + className="w-full h-10" + /> + ) : ( + + )} +
+ ))} +
+ + + + ); +}; diff --git a/WebServices/management-frontend/src/components/commons/hooks/useApiData.ts b/WebServices/management-frontend/src/components/commons/hooks/useApiData.ts new file mode 100644 index 0000000..085fbb0 --- /dev/null +++ b/WebServices/management-frontend/src/components/commons/hooks/useApiData.ts @@ -0,0 +1,75 @@ +import { useDataFetching, RequestParams, ApiResponse } from "./useDataFetching"; + +/** + * Hook for fetching data from Next.js API routes + * @param endpoint The API endpoint to fetch data from (e.g., '/api/applications') + * @param initialParams Initial request parameters + * @returns Object containing data, pagination, loading, error, updatePagination, and refetch + */ +export function useApiData( + endpoint: string, + initialParams: Partial = {} +) { + // Define the fetch function that will be passed to useDataFetching + const fetchFromApi = async (params: RequestParams): Promise> => { + try { + // Construct query parameters + const queryParams = new URLSearchParams(); + + // Add pagination parameters + queryParams.append("page", params.page.toString()); + queryParams.append("size", params.size.toString()); + + // Add sorting parameters + if (params.orderField && params.orderField.length > 0) { + params.orderField.forEach((field, index) => { + queryParams.append("orderField", field); + if (params.orderType && params.orderType[index]) { + queryParams.append("orderType", params.orderType[index]); + } + }); + } + + // Add query filters + if (params.query && Object.keys(params.query).length > 0) { + Object.entries(params.query).forEach(([key, value]) => { + if (value !== undefined && value !== null && value !== "") { + queryParams.append(key, value.toString()); + } + }); + } + + // Make the API request + const response = await fetch(`${endpoint}?${queryParams.toString()}`); + + if (!response.ok) { + throw new Error(`API request failed with status ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error("Error fetching data from API:", error); + + // Return empty data with pagination info on error + return { + data: [], + pagination: { + page: params.page, + size: params.size, + totalCount: 0, + totalItems: 0, + totalPages: 0, + pageCount: 0, + orderField: params.orderField, + orderType: params.orderType, + query: params.query, + next: false, + back: false, + }, + }; + } + }; + + // Use the generic data fetching hook with our API-specific fetch function + return useDataFetching(fetchFromApi, initialParams); +} diff --git a/WebServices/management-frontend/src/components/commons/hooks/useDataFetching.ts b/WebServices/management-frontend/src/components/commons/hooks/useDataFetching.ts new file mode 100644 index 0000000..4f733d6 --- /dev/null +++ b/WebServices/management-frontend/src/components/commons/hooks/useDataFetching.ts @@ -0,0 +1,193 @@ +import { useState, useEffect, useCallback, useRef } from "react"; + +export interface RequestParams { + page: number; + size: number; + orderField: string[]; + orderType: string[]; + query: Record; +} + +export interface ResponseMetadata { + totalCount: number; + totalItems: number; + totalPages: number; + pageCount: number; + allCount?: number; + next: boolean; + back: boolean; +} + +export interface PagePagination extends RequestParams, ResponseMetadata {} + +export interface ApiResponse { + data: T[]; + pagination: PagePagination; +} + +/** + * Generic data fetching hook that can be used with any API endpoint + * @param fetchFunction - The API function to call for fetching data + * @param initialParams - Initial request parameters + * @returns Object containing data, pagination, loading, error, updatePagination, and refetch + */ +export function useDataFetching( + fetchFunction: (params: RequestParams) => Promise>, + initialParams: Partial = {} +) { + const [data, setData] = useState([]); + + // Request parameters - these are controlled by the user + const [requestParams, setRequestParams] = useState({ + page: initialParams.page || 1, + size: initialParams.size || 10, + orderField: initialParams.orderField || ["name"], + orderType: initialParams.orderType || ["asc"], + query: initialParams.query || {}, + }); + + // Response metadata - these come from the API + const [responseMetadata, setResponseMetadata] = useState({ + totalCount: 0, + totalItems: 0, + totalPages: 0, + pageCount: 0, + next: true, + back: false, + }); + + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const fetchDataFromApi = useCallback(async () => { + setLoading(true); + try { + const result = await fetchFunction({ + page: requestParams.page, + size: requestParams.size, + orderField: requestParams.orderField, + orderType: requestParams.orderType, + query: requestParams.query, + }); + + if (result && result.data) { + setData(result.data); + + // Update response metadata from API response + if (result.pagination) { + setResponseMetadata({ + totalCount: result.pagination.totalCount || 0, + totalItems: result.pagination.totalCount || 0, + totalPages: result.pagination.totalPages || 1, + pageCount: result.pagination.pageCount || 0, + allCount: result.pagination.allCount || 0, + next: result.pagination.next || false, + back: result.pagination.back || false, + }); + } + } + + setError(null); + } catch (err) { + setError(err instanceof Error ? err : new Error("Unknown error")); + } finally { + setLoading(false); + } + }, [ + fetchFunction, + requestParams.page, + requestParams.size, + requestParams.orderField, + requestParams.orderType, + requestParams.query, + ]); + + // Track if this is the initial mount + const initialMountRef = useRef(true); + + // Track previous request params to avoid unnecessary fetches + const prevRequestParamsRef = useRef(requestParams); + + useEffect(() => { + // Only fetch on mount or when request params actually change + const paramsChanged = JSON.stringify(prevRequestParamsRef.current) !== JSON.stringify(requestParams); + + if (initialMountRef.current || paramsChanged) { + const timer = setTimeout(() => { + fetchDataFromApi(); + initialMountRef.current = false; + prevRequestParamsRef.current = {...requestParams}; + }, 300); // Debounce + + return () => clearTimeout(timer); + } + }, [fetchDataFromApi, requestParams]); + + const updatePagination = useCallback((updates: Partial) => { + // Transform query parameters to use __ilike with %value% format + if (updates.query) { + const transformedQuery: Record = {}; + + Object.entries(updates.query).forEach(([key, value]) => { + // Only transform string values that aren't already using a special operator + if ( + typeof value === "string" && + !key.includes("__") && + value.trim() !== "" + ) { + transformedQuery[`${key}__ilike`] = `%${value}%`; + } else { + transformedQuery[key] = value; + } + }); + + updates.query = transformedQuery; + + // Always reset to page 1 when search query changes + if (!updates.hasOwnProperty("page")) { + updates.page = 1; + } + + // Reset response metadata when search changes to avoid stale pagination data + setResponseMetadata({ + totalCount: 0, + totalItems: 0, + totalPages: 0, + pageCount: 0, + allCount: 0, + next: true, + back: false, + }); + } + + setRequestParams((prev) => ({ + ...prev, + ...updates, + })); + }, []); + + // Create a combined refetch function + const refetch = useCallback(() => { + // Reset pagination to page 1 when manually refetching + setRequestParams((prev) => ({ + ...prev, + page: 1, + })); + fetchDataFromApi(); + }, [fetchDataFromApi]); + + // Combine request params and response metadata + const pagination: PagePagination = { + ...requestParams, + ...responseMetadata, + }; + + return { + data, + pagination, + loading, + error, + updatePagination, + refetch, + }; +} diff --git a/WebServices/management-frontend/src/components/commons/index.ts b/WebServices/management-frontend/src/components/commons/index.ts new file mode 100644 index 0000000..3d2e32a --- /dev/null +++ b/WebServices/management-frontend/src/components/commons/index.ts @@ -0,0 +1,9 @@ +// Export all components from the commons directory +export { CardDisplay } from './CardDisplay'; +export { SearchComponent } from './SearchComponent'; +export { ActionButtonsComponent } from './ActionButtonsComponent'; +export { PaginationToolsComponent } from './PaginationToolsComponent'; + +// Export hooks +export { useDataFetching, type RequestParams, type ResponseMetadata, type PagePagination, type ApiResponse } from './hooks/useDataFetching'; +export { useApiData } from './hooks/useApiData'; diff --git a/WebServices/management-frontend/src/components/componentGroups/CardDisplay/ReadMe.md b/WebServices/management-frontend/src/components/componentGroups/CardDisplay/ReadMe.md new file mode 100644 index 0000000..ecf713e --- /dev/null +++ b/WebServices/management-frontend/src/components/componentGroups/CardDisplay/ReadMe.md @@ -0,0 +1,86 @@ +Card Display which includes + +/api/... +async POST somefunction() => /api/... + +/page.tsx +I want create a nextjs api that fecth data instead having below code in schema +```tsx +export const fetchApplicationData = async ({ + page = 1, + size = 10, + orderFields = ["name"], + orderTypes = ["asc"], + query = {}, +}: { + page?: number; + size?: number; + orderFields?: string[]; + orderTypes?: string[]; + query?: Record; +}) => { + // Call the actual API function + try { + const response = await listApplications({ + page, + size, + orderField: orderFields, + orderType: orderTypes, + query, + }); + + return { + data: response.data, + pagination: response.pagination, + }; + } catch (error) { + console.error("Error fetching application data:", error); + return { + data: [], + pagination: { + page, + size, + totalCount: 0, + totalItems: 0, + totalPages: 0, + pageCount: 0, + orderField: orderFields || [], + orderType: orderTypes || [], + query: {}, + } as PagePagination, + }; + } +}; +``` + + + +I want all these components and default return of my external api which is +interface ApiResponse { + data: any[]; + pagination: PagePagination; +} +@/components/schemas +@/components/commons/CardDisplay +@/components/commons/PaginationToolsComponent +@/components/commons/...ImportableComponents // other importable components + +```tsx +const {data, pagination, loading, error, updatePagination, refetch} = fecthDataFromApi(); +const showFields = ["uu_id", "Field1", "Field2"]; +const [mode, setMode] = useState<"list" | "create" | "update">("list"); + +// Importable components + + + +``` diff --git a/WebServices/management-frontend/src/components/componentGroups/CardDisplay/Screenshot from 2025-04-29 19-36-45.png b/WebServices/management-frontend/src/components/componentGroups/CardDisplay/Screenshot from 2025-04-29 19-36-45.png new file mode 100644 index 0000000000000000000000000000000000000000..309f151828f728dd5e0c71e9f2de3e9b7e969709 GIT binary patch literal 68479 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 z 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 GpZ^CU6=)p* literal 0 HcmV?d00001 diff --git a/WebServices/management-frontend/src/components/ui/skeleton.tsx b/WebServices/management-frontend/src/components/ui/skeleton.tsx new file mode 100644 index 0000000..32ea0ef --- /dev/null +++ b/WebServices/management-frontend/src/components/ui/skeleton.tsx @@ -0,0 +1,13 @@ +import { cn } from "@/lib/utils" + +function Skeleton({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { Skeleton } diff --git a/WebServices/management-frontend/src/components/ui/table.tsx b/WebServices/management-frontend/src/components/ui/table.tsx new file mode 100644 index 0000000..51b74dd --- /dev/null +++ b/WebServices/management-frontend/src/components/ui/table.tsx @@ -0,0 +1,116 @@ +"use client" + +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Table({ className, ...props }: React.ComponentProps<"table">) { + return ( +
+ + + ) +} + +function TableHeader({ className, ...props }: React.ComponentProps<"thead">) { + return ( + + ) +} + +function TableBody({ className, ...props }: React.ComponentProps<"tbody">) { + return ( + + ) +} + +function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) { + return ( + tr]:last:border-b-0", + className + )} + {...props} + /> + ) +} + +function TableRow({ className, ...props }: React.ComponentProps<"tr">) { + return ( + + ) +} + +function TableHead({ className, ...props }: React.ComponentProps<"th">) { + return ( +
[role=checkbox]]:translate-y-[2px]", + className + )} + {...props} + /> + ) +} + +function TableCell({ className, ...props }: React.ComponentProps<"td">) { + return ( + [role=checkbox]]:translate-y-[2px]", + className + )} + {...props} + /> + ) +} + +function TableCaption({ + className, + ...props +}: React.ComponentProps<"caption">) { + return ( +
+ ) +} + +export { + Table, + TableHeader, + TableBody, + TableFooter, + TableHead, + TableRow, + TableCell, + TableCaption, +}