diff --git a/WebServices/client-frontend/src/apicalls/basics.ts b/WebServices/client-frontend/src/apicalls/basics.ts
index 17eea35..46f4d58 100644
--- a/WebServices/client-frontend/src/apicalls/basics.ts
+++ b/WebServices/client-frontend/src/apicalls/basics.ts
@@ -6,9 +6,9 @@ const formatServiceUrl = (url: string) => {
export const baseUrlAuth = formatServiceUrl(
process.env.NEXT_PUBLIC_AUTH_SERVICE_URL || "auth_service:8001"
);
-// export const baseUrlValidation = formatServiceUrl(
-// process.env.NEXT_PUBLIC_VALIDATION_SERVICE_URL || "validationservice:8888"
-// );
+export const baseUrlPeople = formatServiceUrl(
+ process.env.NEXT_PUBLIC_VALIDATION_SERVICE_URL || "identity_service:8002"
+);
// export const baseUrlEvent = formatServiceUrl(
// process.env.NEXT_PUBLIC_EVENT_SERVICE_URL || "eventservice:8888"
// );
diff --git a/WebServices/client-frontend/src/apicalls/login/login.tsx b/WebServices/client-frontend/src/apicalls/login/login.tsx
index edd0364..9e7e3b6 100644
--- a/WebServices/client-frontend/src/apicalls/login/login.tsx
+++ b/WebServices/client-frontend/src/apicalls/login/login.tsx
@@ -5,8 +5,6 @@ import { fetchData, fetchDataWithToken } from "../api-fetcher";
import { baseUrlAuth, cookieObject, tokenSecret } from "../basics";
import { cookies } from "next/headers";
-// import { setAvailableEvents } from "../events/available";
-
const loginEndpoint = `${baseUrlAuth}/authentication/login`;
const loginSelectEndpoint = `${baseUrlAuth}/authentication/select`;
diff --git a/WebServices/client-frontend/src/apicalls/people/people.tsx b/WebServices/client-frontend/src/apicalls/people/people.tsx
new file mode 100644
index 0000000..2648ce2
--- /dev/null
+++ b/WebServices/client-frontend/src/apicalls/people/people.tsx
@@ -0,0 +1,31 @@
+"use server";
+import { fetchData, fetchDataWithToken } from "../api-fetcher";
+import { baseUrlPeople, cookieObject, tokenSecret } from "../basics";
+import { PageListOptions, PaginateOnly } from "../schemas/list";
+
+const peopleListEndpoint = `${baseUrlPeople}/people/list`;
+const peopleCreateEndpoint = `${baseUrlPeople}/people/create`;
+const peopleUpdateEndpoint = `${baseUrlPeople}/people/update`;
+
+async function peopleList(payload: PageListOptions) {
+ try {
+ const response = await fetchDataWithToken(
+ peopleListEndpoint,
+ {
+ page: payload.page,
+ size: payload.size,
+ order_field: payload.orderField,
+ order_type: payload.orderType,
+ query: payload.query,
+ },
+ "POST",
+ false
+ );
+ return response?.status === 200 ? response.data : null;
+ } catch (error) {
+ console.error("Error fetching people list:", error);
+ return null;
+ }
+}
+
+export { peopleList };
diff --git a/WebServices/client-frontend/src/apicalls/schemas/list.tsx b/WebServices/client-frontend/src/apicalls/schemas/list.tsx
new file mode 100644
index 0000000..659fb37
--- /dev/null
+++ b/WebServices/client-frontend/src/apicalls/schemas/list.tsx
@@ -0,0 +1,14 @@
+export interface PaginateOnly {
+ page?: number;
+ size?: number;
+ orderField?: string[];
+ orderType?: string[];
+}
+
+export interface PageListOptions {
+ page?: number;
+ size?: number;
+ orderField?: string[];
+ orderType?: string[];
+ query?: any;
+}
diff --git a/WebServices/client-frontend/src/app/(DashboardLayout)/template/page.tsx b/WebServices/client-frontend/src/app/(DashboardLayout)/template/page.tsx
new file mode 100644
index 0000000..c6f0e95
--- /dev/null
+++ b/WebServices/client-frontend/src/app/(DashboardLayout)/template/page.tsx
@@ -0,0 +1,60 @@
+"use server";
+import React from "react";
+import Template from "@/components/Pages/template/app";
+import ClientMenu from "@/components/menuCleint/menu";
+import { LanguageKey } from "@/components/Pages/template/language";
+
+import { retrievePageList } from "@/apicalls/cookies/token";
+
+interface TemplatePageProps {
+ params: { lang?: string };
+ searchParams: { [key: string]: string | string[] | undefined };
+}
+
+async function TemplatePage({ params, searchParams }: TemplatePageProps) {
+ // Get language from query params or default to 'en'
+ const pParams = await params;
+ const siteUrlsList = (await retrievePageList()) || [];
+ const searchParamsInstance = await searchParams;
+ const activePage = "/template";
+ const lang = (searchParamsInstance?.lang as LanguageKey) || "en";
+
+ return (
+ <>
+ <>
+
+ {/* Sidebar */}
+
+
+ {/* Main Content Area */}
+
+ {/* Sticky Header */}
+
+
+
+
+
+
+ >
+ >
+ );
+}
+
+export default TemplatePage;
diff --git a/WebServices/client-frontend/src/components/NavigatePages/app000003.tsx b/WebServices/client-frontend/src/components/NavigatePages/app000003.tsx
index fd86945..dbc8a09 100644
--- a/WebServices/client-frontend/src/components/NavigatePages/app000003.tsx
+++ b/WebServices/client-frontend/src/components/NavigatePages/app000003.tsx
@@ -1,45 +1,100 @@
"use client";
import React, { useEffect } from "react";
-import buildingsMockData from "./mock-data";
-import { BuildingFormData } from "../Pages/build/buildschema1";
-import BuildPageForm1 from "../Pages/build/buildform1";
-import BuildPage1 from "../Pages/build/buildpage1";
-import BuildInfo1 from "../Pages/build/buildinfo1";
+import {
+ PeopleFormData,
+ PeopleSchema,
+} from "../Pages/people/superusers/peopleschema1";
+
+import PeoplePageForm1 from "../Pages/people/superusers/peopleform1";
+import PeoplePage1 from "../Pages/people/superusers/peoplepage1";
+import PeopleInfo1 from "../Pages/people/superusers/peopleinfo1";
+import { peopleList } from "@/apicalls/people/people";
+
+interface Pagination {
+ page: number;
+ size: number;
+ totalCount: number;
+ allCount: number;
+ totalPages: number;
+ orderField: string[];
+ orderType: string[];
+ pageCount: number;
+}
+
+const defaultPagination: Pagination = {
+ page: 1,
+ size: 1,
+ totalCount: 0,
+ allCount: 0,
+ totalPages: 0,
+ orderField: ["uu_id"],
+ orderType: ["asc"],
+ pageCount: 0,
+};
function app000003() {
const [modifyEnable, setModifyEnable] = React.useState(false);
const [isCreate, setIsCreate] = React.useState(false);
const [selectedId, setSelectedId] = React.useState(null);
- const [tableData, setTableData] = React.useState([]);
+ const [tableData, setTableData] = React.useState([]);
+ const [pagination, setPagination] =
+ React.useState(defaultPagination);
const fecthData = async ({
// Add any parameters if needed
page = 1,
pageSize = 10,
- orderBy = "asc",
- orderType = "name",
+ orderBy = ["asc"],
+ orderType = ["uu_id"],
query = {},
}) => {
// Simulate an API call
- const response = await new Promise((resolve) =>
- setTimeout(() => resolve(buildingsMockData), 1000)
- );
- setTableData(response as BuildingFormData[]);
+ const result = await peopleList({
+ page,
+ size: pageSize,
+ orderField: orderType,
+ orderType: orderBy,
+ query: query,
+ });
+ setTableData(result?.data || []);
+ setPagination(result?.pagination || {});
};
- // Fetch data when the component mounts
- useEffect(() => {
- fecthData({
- page: 1,
- pageSize: 10,
- orderBy: "asc",
- orderType: "uu_id",
- query: {},
+ const fetchDataRef = React.useCallback(({
+ page = 1,
+ pageSize = 10,
+ orderBy = ["asc"],
+ orderType = ["uu_id"],
+ query = {},
+ }) => {
+ peopleList({
+ page,
+ size: pageSize,
+ orderField: orderType,
+ orderType: orderBy,
+ query: query,
+ }).then(result => {
+ setTableData(result?.data || []);
+ setPagination(result?.pagination || {});
});
}, []);
- const onSubmit = (data: BuildingFormData) => {
+ useEffect(() => {
+ const timer = setTimeout(() => {
+ fetchDataRef({
+ page: pagination.page,
+ pageSize: pagination.size,
+ orderBy: pagination.orderField,
+ orderType: pagination.orderType,
+ query: {},
+ });
+ }, 300); // 300ms debounce
+
+ return () => clearTimeout(timer);
+ }, [pagination.page, pagination.size, fetchDataRef]);
+
+ const onSubmit = (data: PeopleFormData) => {
console.log("Form data:", data);
// Submit to API or do other operations
};
@@ -57,21 +112,22 @@ function app000003() {
return (
<>
-
setIsCreate(true)}
/>
{!isCreate ? (
{!selectedId ? (
-
) : (
- item.uu_id === selectedId) || {}}
onSubmit={onSubmit}
modifyEnable={modifyEnable}
@@ -81,7 +137,7 @@ function app000003() {
) : (
<>
- void;
+ onView: (uu_id: string) => void;
+}
+
+// Card component
+const Card: React.FC = ({ data, onUpdate, onView }) => (
+
+
+
+
+
{data.person_tag}
+
+ Building Number: {data.firstname} {data.surname}
+
+
+ UUID: {data.uu_id}
+
+ Built: {new Date(data.created_at).toDateString()}
+
+
+
+
+
+
+);
+
+export default Card;
diff --git a/WebServices/client-frontend/src/components/Pages/people/superusers/peopleform1.tsx b/WebServices/client-frontend/src/components/Pages/people/superusers/peopleform1.tsx
new file mode 100644
index 0000000..ce3e560
--- /dev/null
+++ b/WebServices/client-frontend/src/components/Pages/people/superusers/peopleform1.tsx
@@ -0,0 +1,431 @@
+import React from "react";
+import { zodResolver } from "@hookform/resolvers/zod";
+import { useForm } from "react-hook-form";
+import {
+ Form,
+ FormControl,
+ FormDescription,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from "@/components/ui/form";
+import { Input } from "@/components/ui/input";
+import { ArrowLeft } from "lucide-react";
+import { DatePicker } from "@/components/ui/datepicker";
+import { Checkbox } from "@/components/ui/checkbox";
+import { PeopleFormData, PeopleSchema } from "./peopleschema1";
+
+interface FormProps {
+ data: any;
+ modifyEnable: boolean | null;
+ setSelectedId: () => void;
+ onSubmit: (data: any) => void;
+}
+
+const PeoplePageForm1: React.FC = ({
+ data,
+ modifyEnable,
+ setSelectedId,
+ onSubmit,
+}) => {
+ const form = useForm({
+ resolver: zodResolver(PeopleSchema),
+ defaultValues: {
+ ...data,
+ },
+ });
+
+ return (
+ <>
+ setSelectedId()} className="flex items-center">
+
Back
+
+
+ >
+ );
+};
+
+export default PeoplePageForm1;
diff --git a/WebServices/client-frontend/src/components/Pages/people/superusers/peopleinfo1.tsx b/WebServices/client-frontend/src/components/Pages/people/superusers/peopleinfo1.tsx
new file mode 100644
index 0000000..05519c7
--- /dev/null
+++ b/WebServices/client-frontend/src/components/Pages/people/superusers/peopleinfo1.tsx
@@ -0,0 +1,74 @@
+import React from "react";
+import { ChevronFirst, ChevronLast, Plus } from "lucide-react";
+
+interface InfoData {
+ pagination: any;
+ selectedId: string | null;
+ setPagination: () => void;
+ setIsCreate: () => void;
+}
+
+
+
+const PeopleInfo1: React.FC = ({
+ pagination,
+ selectedId,
+ setPagination,
+ setIsCreate,
+}) => {
+ console.log("PeopleInfo1", pagination, selectedId);
+ return (
+
+
+
+
Individual Dashboard
+
+ Selected ID: {selectedId}
+
+
+
+
+
+ Active Page: {pagination.page}
+
+
+ Size: {pagination.size}
+
+
+ Total Pages: {pagination.totalPages}
+
+
+ Order By: {JSON.stringify(pagination.orderField)}
+
+
+ Order Type: {JSON.stringify(pagination.orderType)}
+
+
+ All Count: {pagination.allCount}
+
+
+ Total Count: {pagination.totalCount}
+
+
+ Page: 1
+
+
+
+
+
+ );
+};
+
+export default PeopleInfo1;
diff --git a/WebServices/client-frontend/src/components/Pages/people/superusers/peoplepage1.tsx b/WebServices/client-frontend/src/components/Pages/people/superusers/peoplepage1.tsx
new file mode 100644
index 0000000..106f0a2
--- /dev/null
+++ b/WebServices/client-frontend/src/components/Pages/people/superusers/peoplepage1.tsx
@@ -0,0 +1,37 @@
+"use client";
+import React from "react";
+import Card from "./card1";
+import { PeopleFormData } from "./peopleschema1";
+
+interface PageData {
+ data: PeopleFormData[];
+ handleUpdateModify: (uu_id: string) => void;
+ handleView: (uu_id: string) => void;
+}
+
+const PeoplePage1: React.FC = ({
+ data,
+ handleUpdateModify,
+ handleView,
+}) => {
+ return (
+ <>
+
+
+ {data.map((item) => (
+
+
+
+ ))}
+
+
+ >
+ );
+};
+
+export default PeoplePage1;
diff --git a/WebServices/client-frontend/src/components/Pages/people/superusers/peopleschema1.tsx b/WebServices/client-frontend/src/components/Pages/people/superusers/peopleschema1.tsx
new file mode 100644
index 0000000..55b9631
--- /dev/null
+++ b/WebServices/client-frontend/src/components/Pages/people/superusers/peopleschema1.tsx
@@ -0,0 +1,24 @@
+import { z } from "zod";
+
+export const PeopleSchema = z.object({
+ uu_id: z.string(),
+ created_at: z.string(),
+ updated_at: z.string(),
+ person_tag: z.string(),
+ expiry_starts: z.string(),
+ expiry_ends: z.string(),
+ firstname: z.string(),
+ middle_name: z.string(),
+ surname: z.string(),
+ birth_date: z.string(),
+ birth_place: z.string(),
+ sex_code: z.string(),
+ country_code: z.string(),
+ tax_no: z.string(),
+ active: z.boolean(),
+ deleted: z.boolean(),
+ is_confirmed: z.boolean(),
+ is_notification_send: z.boolean(),
+});
+
+export type PeopleFormData = z.infer;
diff --git a/WebServices/client-frontend/src/components/Pages/template/ActionButtonsComponent.tsx b/WebServices/client-frontend/src/components/Pages/template/ActionButtonsComponent.tsx
new file mode 100644
index 0000000..cd2f7e2
--- /dev/null
+++ b/WebServices/client-frontend/src/components/Pages/template/ActionButtonsComponent.tsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import { getTranslation, LanguageKey } from './language';
+
+interface ActionButtonsComponentProps {
+ onCreateClick: () => void;
+ lang?: LanguageKey;
+}
+
+export function ActionButtonsComponent({
+ onCreateClick,
+ lang = 'en'
+}: ActionButtonsComponentProps) {
+ const t = getTranslation(lang);
+
+ return (
+
+
+ {/* Additional action buttons can be added here in the future */}
+
+ );
+}
diff --git a/WebServices/client-frontend/src/components/Pages/template/DataDisplayComponent.tsx b/WebServices/client-frontend/src/components/Pages/template/DataDisplayComponent.tsx
new file mode 100644
index 0000000..098d052
--- /dev/null
+++ b/WebServices/client-frontend/src/components/Pages/template/DataDisplayComponent.tsx
@@ -0,0 +1,60 @@
+import React from 'react';
+import { DataType } from './schema';
+import { getTranslation, LanguageKey } from './language';
+import { DataCard } from './ListInfoComponent';
+
+interface DataDisplayComponentProps {
+ data: DataType[];
+ loading: boolean;
+ error: Error | null;
+ onViewClick: (item: DataType) => void;
+ onUpdateClick: (item: DataType) => void;
+ lang?: LanguageKey;
+}
+
+export function DataDisplayComponent({
+ data,
+ loading,
+ error,
+ onViewClick,
+ onUpdateClick,
+ lang = 'en'
+}: DataDisplayComponentProps) {
+ const t = getTranslation(lang);
+
+ if (error) {
+ return (
+
+ {t.error} {error.message}
+
+ );
+ }
+
+ if (loading) {
+ return (
+
+ );
+ }
+
+ return (
+
+ {data.map(item => (
+
+ ))}
+
+ {data.length === 0 && (
+
+ {t.noItemsFound}
+
+ )}
+
+ );
+}
diff --git a/WebServices/client-frontend/src/components/Pages/template/FormComponent.tsx b/WebServices/client-frontend/src/components/Pages/template/FormComponent.tsx
new file mode 100644
index 0000000..aad7e09
--- /dev/null
+++ b/WebServices/client-frontend/src/components/Pages/template/FormComponent.tsx
@@ -0,0 +1,127 @@
+import React, { useState } from 'react';
+import { z } from 'zod';
+import { DataType, DataSchema } from './schema';
+import { getTranslation, LanguageKey } from './language';
+
+interface FormComponentProps {
+ initialData?: Partial;
+ onSubmit: (data: DataType) => void;
+ onCancel: () => void;
+ readOnly?: boolean;
+ lang?: LanguageKey;
+}
+
+export function FormComponent({
+ initialData,
+ onSubmit,
+ onCancel,
+ readOnly = false,
+ lang = 'en'
+}: FormComponentProps) {
+ const t = getTranslation(lang);
+ const [formData, setFormData] = useState>(initialData || {
+ title: '',
+ description: '',
+ status: 'active',
+ });
+ const [errors, setErrors] = useState>({});
+
+ const handleChange = (e: React.ChangeEvent) => {
+ const { name, value } = e.target;
+ setFormData(prev => ({
+ ...prev,
+ [name]: value,
+ }));
+ };
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault();
+
+ try {
+ // Validate with Zod
+ const validData = DataSchema.parse(formData);
+ onSubmit(validData);
+ setErrors({});
+ } catch (err) {
+ if (err instanceof z.ZodError) {
+ const fieldErrors: Record = {};
+ err.errors.forEach(error => {
+ const field = error.path[0];
+ fieldErrors[field as string] = error.message;
+ });
+ setErrors(fieldErrors);
+ }
+ }
+ };
+
+ return (
+
+
+ {readOnly ? t.view : initialData?.id ? t.update : t.createNew}
+
+
+
+
+ );
+}
diff --git a/WebServices/client-frontend/src/components/Pages/template/ListInfoComponent.tsx b/WebServices/client-frontend/src/components/Pages/template/ListInfoComponent.tsx
new file mode 100644
index 0000000..6d1fdae
--- /dev/null
+++ b/WebServices/client-frontend/src/components/Pages/template/ListInfoComponent.tsx
@@ -0,0 +1,136 @@
+import React from 'react';
+import { DataType, Pagination } from './schema';
+import { getTranslation, LanguageKey } from './language';
+import { ActionButtonsComponent } from './ActionButtonsComponent';
+import { SortingComponent } from './SortingComponent';
+import { PaginationToolsComponent } from './PaginationToolsComponent';
+
+
+
+interface DataCardProps {
+ item: DataType;
+ onView: (item: DataType) => void;
+ onUpdate: (item: DataType) => void;
+ lang?: LanguageKey;
+}
+
+export function DataCard({
+ item,
+ onView,
+ onUpdate,
+ lang = 'en'
+}: DataCardProps) {
+ const t = getTranslation(lang);
+
+ return (
+
+
+
+
{item.title}
+
{item.description}
+
+
+ {item.status}
+
+
+ {t.formLabels.createdAt}: {new Date(item.createdAt).toLocaleDateString()}
+
+
+
+
+
+
+
+
+
+ );
+}
+
+interface ListInfoComponentProps {
+ data: DataType[];
+ pagination: Pagination;
+ loading: boolean;
+ error: Error | null;
+ updatePagination: (updates: Partial) => void;
+ onCreateClick: () => void;
+ onViewClick: (item: DataType) => void;
+ onUpdateClick: (item: DataType) => void;
+ lang?: LanguageKey;
+}
+
+export function ListInfoComponent({
+ data,
+ pagination,
+ loading,
+ error,
+ updatePagination,
+ onCreateClick,
+ onViewClick,
+ onUpdateClick,
+ lang = 'en'
+}: ListInfoComponentProps) {
+ const t = getTranslation(lang);
+
+ if (error) {
+ return (
+
+ {t.error} {error.message}
+
+ );
+ }
+
+ return (
+ <>
+
+
+
+
+
+
+ {loading ? (
+
+ ) : (
+
+ {data.map(item => (
+
+ ))}
+
+ {data.length === 0 && (
+
+ {t.noItemsFound}
+
+ )}
+
+ )}
+ >
+ );
+}
diff --git a/WebServices/client-frontend/src/components/Pages/template/PaginationToolsComponent.tsx b/WebServices/client-frontend/src/components/Pages/template/PaginationToolsComponent.tsx
new file mode 100644
index 0000000..f5bac14
--- /dev/null
+++ b/WebServices/client-frontend/src/components/Pages/template/PaginationToolsComponent.tsx
@@ -0,0 +1,77 @@
+import React from 'react';
+import { Pagination } from './schema';
+import { getTranslation, LanguageKey } from './language';
+
+interface PaginationToolsComponentProps {
+ pagination: Pagination;
+ updatePagination: (updates: Partial) => void;
+ lang?: LanguageKey;
+}
+
+export function PaginationToolsComponent({
+ pagination,
+ updatePagination,
+ lang = 'en'
+}: PaginationToolsComponentProps) {
+ const t = getTranslation(lang);
+
+ const handlePageChange = (newPage: number) => {
+ if (newPage >= 1 && newPage <= pagination.totalPages) {
+ updatePagination({ page: newPage });
+ }
+ };
+
+ const handleSizeChange = (e: React.ChangeEvent) => {
+ updatePagination({ size: Number(e.target.value), page: 1 });
+ };
+
+ return (
+
+
+ {/* Navigation buttons */}
+
+
+
+
+ {t.page} {pagination.page} {t.of} {pagination.totalPages}
+
+
+
+
+
+ {/* Items per page selector */}
+
+
+
+
+
+ {/* Pagination stats */}
+
+
{t.showing} {pagination.pageCount} {t.of} {pagination.totalCount} {t.items}
+
{t.total}: {pagination.allCount} {t.items}
+
+
+
+ );
+}
diff --git a/WebServices/client-frontend/src/components/Pages/template/SearchComponent.tsx b/WebServices/client-frontend/src/components/Pages/template/SearchComponent.tsx
new file mode 100644
index 0000000..9006df4
--- /dev/null
+++ b/WebServices/client-frontend/src/components/Pages/template/SearchComponent.tsx
@@ -0,0 +1,133 @@
+import React, { useState, useEffect } from 'react';
+import { DataSchema } from './schema';
+import { getTranslation, LanguageKey } from './language';
+
+interface SearchComponentProps {
+ onSearch: (query: Record) => void;
+ lang?: LanguageKey;
+}
+
+export function SearchComponent({ onSearch, lang = 'en' }: SearchComponentProps) {
+ const t = getTranslation(lang);
+ const [searchValue, setSearchValue] = useState('');
+ const [activeFields, setActiveFields] = useState([]);
+ const [searchQuery, setSearchQuery] = useState>({});
+
+ // Update search query when fields or search value changes
+ useEffect(() => {
+ // Only update if we have active fields and a search value
+ // or if we have no active fields (to clear the search)
+ if ((activeFields.length > 0 && searchValue) || activeFields.length === 0) {
+ const newQuery: Record = {};
+
+ // Only add fields if we have a search value
+ if (searchValue) {
+ activeFields.forEach(field => {
+ newQuery[field] = searchValue;
+ });
+ }
+
+ // Update local state
+ setSearchQuery(newQuery);
+
+ // Don't call onSearch here - it creates an infinite loop
+ // We'll call it in a separate effect
+ }
+ }, [activeFields, searchValue]);
+
+ // This effect handles calling the onSearch callback
+ // It runs when searchQuery changes, not when onSearch changes
+ useEffect(() => {
+ onSearch(searchQuery);
+ }, [searchQuery]);
+
+ const handleSearchChange = (e: React.ChangeEvent) => {
+ const value = e.target.value;
+ setSearchValue(value);
+
+ if (!value) {
+ setSearchQuery({});
+ onSearch({});
+ return;
+ }
+
+ if (activeFields.length === 0) {
+ // If no fields are selected, don't search
+ return;
+ }
+
+ const newQuery: Record = {};
+ activeFields.forEach(field => {
+ newQuery[field] = value;
+ });
+
+ setSearchQuery(newQuery);
+ onSearch(newQuery);
+ };
+
+ const toggleField = (field: string) => {
+ setActiveFields(prev => {
+ if (prev.includes(field)) {
+ return prev.filter(f => f !== field);
+ } else {
+ return [...prev, field];
+ }
+ });
+ };
+
+ return (
+
+
+
+
+
+
+
+
{t.searchFields || 'Search in fields'}:
+
+ {Object.keys(DataSchema.shape).map(field => (
+
+ ))}
+
+
+
+ {Object.keys(searchQuery).length > 0 && (
+
+
{t.activeSearch || 'Active search'}:
+
+ {Object.entries(searchQuery).map(([field, value]) => (
+
+ {field}: {value}
+
+
+ ))}
+
+
+ )}
+
+ );
+}
diff --git a/WebServices/client-frontend/src/components/Pages/template/SortingComponent.tsx b/WebServices/client-frontend/src/components/Pages/template/SortingComponent.tsx
new file mode 100644
index 0000000..c1170ae
--- /dev/null
+++ b/WebServices/client-frontend/src/components/Pages/template/SortingComponent.tsx
@@ -0,0 +1,76 @@
+import React from 'react';
+import { Pagination, DataSchema } from './schema';
+import { getTranslation, LanguageKey } from './language';
+
+interface SortingComponentProps {
+ pagination: Pagination;
+ updatePagination: (updates: Partial) => void;
+ lang?: LanguageKey;
+}
+
+export function SortingComponent({
+ pagination,
+ updatePagination,
+ lang = 'en'
+}: SortingComponentProps) {
+ const t = getTranslation(lang);
+
+ const handleSortChange = (field: string) => {
+ // Find if the field is already in the orderFields array
+ const fieldIndex = pagination.orderFields.indexOf(field);
+
+ // Create copies of the arrays to modify
+ const newOrderFields = [...pagination.orderFields];
+ const newOrderTypes = [...pagination.orderTypes];
+
+ if (fieldIndex === -1) {
+ // Field is not being sorted yet - add it with 'asc' direction
+ newOrderFields.push(field);
+ newOrderTypes.push('asc');
+ } else if (pagination.orderTypes[fieldIndex] === 'asc') {
+ // Field is being sorted ascending - change to descending
+ newOrderTypes[fieldIndex] = 'desc';
+ } else {
+ // Field is being sorted descending - remove it from sorting
+ newOrderFields.splice(fieldIndex, 1);
+ newOrderTypes.splice(fieldIndex, 1);
+ }
+
+ updatePagination({
+ orderFields: newOrderFields,
+ orderTypes: newOrderTypes,
+ page: 1,
+ });
+ };
+
+ return (
+
+
+
+
+ {Object.keys(DataSchema.shape).map(field => {
+ // Find if this field is in the orderFields array
+ const fieldIndex = pagination.orderFields.indexOf(field);
+ const isActive = fieldIndex !== -1;
+ const direction = isActive ? pagination.orderTypes[fieldIndex] : null;
+
+ return (
+
+ );
+ })}
+
+
+
+ );
+}
diff --git a/WebServices/client-frontend/src/components/Pages/template/app.tsx b/WebServices/client-frontend/src/components/Pages/template/app.tsx
new file mode 100644
index 0000000..43577f5
--- /dev/null
+++ b/WebServices/client-frontend/src/components/Pages/template/app.tsx
@@ -0,0 +1,125 @@
+"use client";
+import React, { useState } from "react";
+import { DataType } from "./schema";
+import { usePaginatedData } from "./hooks";
+import { FormComponent } from "./FormComponent";
+import { SearchComponent } from "./SearchComponent";
+import { getTranslation, LanguageKey } from "./language";
+import { ActionButtonsComponent } from "./ActionButtonsComponent";
+import { SortingComponent } from "./SortingComponent";
+import { PaginationToolsComponent } from "./PaginationToolsComponent";
+import { DataDisplayComponent } from "./DataDisplayComponent";
+
+interface TemplateProps {
+ lang?: LanguageKey;
+}
+
+// Main template component
+function TemplateApp({ lang = "en" }: TemplateProps) {
+ const t = getTranslation(lang);
+ const { data, pagination, loading, error, updatePagination, refetch } =
+ usePaginatedData();
+
+ const [mode, setMode] = useState<"list" | "create" | "view" | "update">(
+ "list"
+ );
+ const [selectedItem, setSelectedItem] = useState(null);
+
+ const handleCreateClick = () => {
+ setSelectedItem(null);
+ setMode("create");
+ };
+
+ const handleViewClick = (item: DataType) => {
+ setSelectedItem(item);
+ setMode("view");
+ };
+
+ const handleUpdateClick = (item: DataType) => {
+ setSelectedItem(item);
+ setMode("update");
+ };
+
+ const handleFormSubmit = async (data: DataType) => {
+ console.log("Submitting form data:", data);
+ // Here you would call your API to save the data
+ // await saveData(data);
+
+ // After saving, refresh the list and go back to list view
+ setMode("list");
+ setSelectedItem(null);
+ refetch();
+ };
+
+ const handleFormCancel = () => {
+ setMode("list");
+ setSelectedItem(null);
+ };
+
+ return (
+
+
{t.title}
+
+ {/* Search Component */}
+ {mode === "list" && (
+
) => {
+ // Update pagination with both page reset and new query
+ updatePagination({
+ page: 1,
+ query: query,
+ });
+ }}
+ lang={lang}
+ />
+ )}
+
+ {/* Action Buttons Component */}
+ {mode === "list" && (
+
+ )}
+
+ {/* Sorting Component */}
+ {mode === "list" && (
+
+ )}
+
+ {/* Pagination Tools Component */}
+ {mode === "list" && (
+
+ )}
+
+ {/* Data Display - Only shown in list mode */}
+ {mode === "list" && (
+
+ )}
+
+ {(mode === "create" || mode === "update" || mode === "view") && (
+
+ )}
+
+ );
+}
+
+export default TemplateApp;
diff --git a/WebServices/client-frontend/src/components/Pages/template/hooks.ts b/WebServices/client-frontend/src/components/Pages/template/hooks.ts
new file mode 100644
index 0000000..b891a0e
--- /dev/null
+++ b/WebServices/client-frontend/src/components/Pages/template/hooks.ts
@@ -0,0 +1,124 @@
+import { useState, useEffect, useCallback } from 'react';
+import { DataType, Pagination, fetchData, DataSchema } from './schema';
+
+// Define request parameters interface
+interface RequestParams {
+ page: number;
+ size: number;
+ orderFields: string[];
+ orderTypes: string[];
+ query: Record;
+}
+
+// Define response metadata interface
+interface ResponseMetadata {
+ totalCount: number;
+ allCount: number;
+ totalPages: number;
+ pageCount: number;
+}
+
+// Custom hook for pagination and data fetching
+export function usePaginatedData() {
+ const [data, setData] = useState([]);
+
+ // Request parameters - these are controlled by the user
+ const [requestParams, setRequestParams] = useState({
+ page: 1,
+ size: 10,
+ orderFields: ['createdAt'],
+ orderTypes: ['desc'],
+ query: {},
+ });
+
+ // Response metadata - these come from the API
+ const [responseMetadata, setResponseMetadata] = useState({
+ totalCount: 0,
+ allCount: 0,
+ totalPages: 0,
+ pageCount: 0,
+ });
+
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
+
+ const fetchDataFromApi = useCallback(async () => {
+ setLoading(true);
+ try {
+ const result = await fetchData({
+ page: requestParams.page,
+ size: requestParams.size,
+ orderFields: requestParams.orderFields,
+ orderTypes: requestParams.orderTypes,
+ query: requestParams.query,
+ });
+
+ // Validate data with Zod
+ const validatedData = result.data.map(item => {
+ try {
+ return DataSchema.parse(item);
+ } catch (err) {
+ console.error('Validation error for item:', item, err);
+ return null;
+ }
+ }).filter(Boolean) as DataType[];
+
+ setData(validatedData);
+
+ // Update response metadata from API response
+ setResponseMetadata({
+ totalCount: result.pagination.totalCount,
+ allCount: result.pagination.allCount,
+ totalPages: result.pagination.totalPages,
+ pageCount: result.pagination.pageCount,
+ });
+
+ setError(null);
+ } catch (err) {
+ setError(err instanceof Error ? err : new Error('Unknown error'));
+ } finally {
+ setLoading(false);
+ }
+ }, [requestParams.page, requestParams.size, requestParams.orderFields, requestParams.orderTypes, requestParams.query]);
+
+ useEffect(() => {
+ const timer = setTimeout(() => {
+ fetchDataFromApi();
+ }, 300); // Debounce
+
+ return () => clearTimeout(timer);
+ }, [fetchDataFromApi]);
+
+ const updatePagination = (updates: Partial) => {
+ setRequestParams(prev => ({
+ ...prev,
+ ...updates,
+ }));
+ };
+
+ // Create a combined refetch object that includes the setQuery function
+ const setQuery = (query: Record) => {
+ setRequestParams(prev => ({
+ ...prev,
+ query,
+ }));
+ };
+
+ const refetch = Object.assign(fetchDataFromApi, { setQuery });
+
+ // Combine request params and response metadata for backward compatibility
+ const pagination: Pagination = {
+ ...requestParams,
+ ...responseMetadata,
+ };
+
+ return {
+ data,
+ pagination,
+ loading,
+ error,
+ updatePagination,
+ setQuery,
+ refetch,
+ };
+}
diff --git a/WebServices/client-frontend/src/components/Pages/template/language.ts b/WebServices/client-frontend/src/components/Pages/template/language.ts
new file mode 100644
index 0000000..352d4f4
--- /dev/null
+++ b/WebServices/client-frontend/src/components/Pages/template/language.ts
@@ -0,0 +1,56 @@
+// Language dictionary for the template component
+const language = {
+ en: {
+ title: 'Data Management',
+ create: 'Create New',
+ view: 'View Item',
+ update: 'Update Item',
+ createNew: 'Create New Item',
+ back: 'Back',
+ cancel: 'Cancel',
+ submit: 'Submit',
+ noItemsFound: 'No items found',
+ previous: 'Previous',
+ next: 'Next',
+ page: 'Page',
+ of: 'of',
+ itemsPerPage: 'Items per page:',
+ sortBy: 'Sort by:',
+ loading: 'Loading...',
+ error: 'Error loading data:',
+ showing: 'Showing',
+ items: 'items',
+ total: 'Total',
+ // Search related translations
+ search: 'Search',
+ searchPlaceholder: 'Enter search term...',
+ searchFields: 'Search in fields',
+ activeSearch: 'Active search',
+ clearSearch: 'Clear',
+ formLabels: {
+ title: 'Title',
+ description: 'Description',
+ status: 'Status',
+ createdAt: 'Created'
+ },
+ status: {
+ active: 'Active',
+ inactive: 'Inactive'
+ },
+ buttons: {
+ view: 'View',
+ update: 'Update',
+ create: 'Create',
+ save: 'Save'
+ }
+ },
+ // Add more languages as needed
+};
+
+export type LanguageKey = keyof typeof language;
+
+export const getTranslation = (lang: LanguageKey = 'en') => {
+ return language[lang] || language.en;
+};
+
+export default language;
diff --git a/WebServices/client-frontend/src/components/Pages/template/schema.ts b/WebServices/client-frontend/src/components/Pages/template/schema.ts
new file mode 100644
index 0000000..188cd0c
--- /dev/null
+++ b/WebServices/client-frontend/src/components/Pages/template/schema.ts
@@ -0,0 +1,98 @@
+import { z } from "zod";
+
+// Define the data schema using Zod
+export const DataSchema = z.object({
+ id: z.string(),
+ title: z.string(),
+ description: z.string().optional(),
+ status: z.string(),
+ createdAt: z.string().or(z.date()),
+ // Add more fields as needed
+});
+
+export type DataType = z.infer;
+
+// Define pagination interface
+export interface Pagination {
+ page: number;
+ size: number;
+ totalCount: number;
+ allCount: number;
+ totalPages: number;
+ orderFields: string[];
+ orderTypes: string[];
+ pageCount: number;
+ query: Record;
+}
+
+// Mock API function (replace with your actual API call)
+export const fetchData = async ({
+ page = 1,
+ size = 10,
+ orderFields = ["createdAt"],
+ orderTypes = ["desc"],
+ query = {},
+}: {
+ page?: number;
+ size?: number;
+ orderFields?: string[];
+ orderTypes?: string[];
+ query?: Record;
+}) => {
+ // Replace with your actual API call
+ console.log("Fetching data with:", {
+ page,
+ size,
+ orderFields,
+ orderTypes,
+ query,
+ });
+
+ // Simulated API response
+ return new Promise<{ data: DataType[]; pagination: Pagination }>(
+ (resolve) => {
+ setTimeout(() => {
+ // Generate mock data
+ const mockData: DataType[] = Array.from({ length: 100 }, (_, i) => ({
+ id: `id-${i + 1}`,
+ title: `Title ${i + 1}`,
+ description: `Description for item ${i + 1}`,
+ status: i % 3 === 0 ? "active" : "inactive",
+ createdAt: new Date(
+ Date.now() - Math.floor(Math.random() * 10000000000)
+ ).toISOString(),
+ }));
+
+ // Filter by query if provided
+ const filteredData = Object.keys(query).length
+ ? mockData.filter((item) => {
+ return Object.entries(query).every(([key, value]) => {
+ return String(item[key as keyof DataType])
+ .toLowerCase()
+ .includes(String(value).toLowerCase());
+ });
+ })
+ : mockData;
+
+ // Apply pagination
+ const startIndex = (page - 1) * size;
+ const paginatedData = filteredData.slice(startIndex, startIndex + size);
+
+ resolve({
+ data: paginatedData,
+ pagination: {
+ page,
+ size,
+ totalCount: filteredData.length,
+ allCount: mockData.length,
+ totalPages: Math.ceil(filteredData.length / size),
+ orderFields,
+ orderTypes,
+ pageCount: paginatedData.length,
+ query, // Include the query in the pagination object
+ },
+ });
+ }, 500);
+ }
+ );
+};
diff --git a/WebServices/client-frontend/src/components/dash/card.tsx b/WebServices/client-frontend/src/components/dash/card.tsx
new file mode 100644
index 0000000..417de26
--- /dev/null
+++ b/WebServices/client-frontend/src/components/dash/card.tsx
@@ -0,0 +1,56 @@
+import React from "react";
+import { Pencil, ScanSearch } from "lucide-react";
+
+interface CardProps {
+ data: [string, string, string, string];
+ langDictionary: [string, string, string, string];
+ onUpdate: (uu_id: string) => void;
+ onView: (uu_id: string) => void;
+}
+
+const CardComponent: React.FC = ({
+ data,
+ langDictionary,
+ onUpdate,
+ onView,
+}) => {
+ return (
+ <>
+
+
+
+
+ {langDictionary[1]}:{data[1]}
+
+
+ {langDictionary[2]}: {data[2]}
+
+
+
+ {langDictionary[0]} {data[0]}
+
+
+ {langDictionary[3]}: {new Date(data[3]).toDateString()}
+
+
+
+
+
+
+ >
+ );
+};
+
+export default CardComponent;
diff --git a/WebServices/client-frontend/src/components/menuCleint/handler.tsx b/WebServices/client-frontend/src/components/menuCleint/handler.tsx
new file mode 100644
index 0000000..d39db23
--- /dev/null
+++ b/WebServices/client-frontend/src/components/menuCleint/handler.tsx
@@ -0,0 +1,109 @@
+"use client";
+
+import Menu from "./store";
+
+// Define TypeScript interfaces for menu structure
+export interface LanguageTranslation {
+ tr: string;
+ en: string;
+}
+
+export interface MenuThirdLevel {
+ name: string;
+ lg: LanguageTranslation;
+ siteUrl: string;
+}
+
+export interface MenuSecondLevel {
+ name: string;
+ lg: LanguageTranslation;
+ subList: MenuThirdLevel[];
+}
+
+export interface MenuFirstLevel {
+ name: string;
+ lg: LanguageTranslation;
+ subList: MenuSecondLevel[];
+}
+
+// Define interfaces for the filtered menu structure
+export interface FilteredMenuThirdLevel {
+ name: string;
+ lg: LanguageTranslation;
+ siteUrl: string;
+}
+
+export interface FilteredMenuSecondLevel {
+ name: string;
+ lg: LanguageTranslation;
+ subList: FilteredMenuThirdLevel[];
+}
+
+export interface FilteredMenuFirstLevel {
+ name: string;
+ lg: LanguageTranslation;
+ subList: FilteredMenuSecondLevel[];
+}
+
+/**
+ * Filters the menu structure based on intersections with provided URLs
+ * @param {string[]} siteUrls - Array of site URLs to check for intersection
+ * @returns {Array} - Filtered menu structure with only matching items
+ */
+export function transformMenu(siteUrls: string[]) {
+ // Process the menu structure
+ const filteredMenu: FilteredMenuFirstLevel[] = Menu.reduce(
+ (acc: FilteredMenuFirstLevel[], firstLevel: MenuFirstLevel) => {
+ // Create a new first level item with empty subList
+ const newFirstLevel: FilteredMenuFirstLevel = {
+ name: firstLevel.name,
+ lg: { ...firstLevel.lg },
+ subList: [],
+ };
+
+ // Process second level items
+ firstLevel.subList.forEach((secondLevel: MenuSecondLevel) => {
+ // Create a new second level item with empty subList
+ const newSecondLevel: FilteredMenuSecondLevel = {
+ name: secondLevel.name,
+ lg: { ...secondLevel.lg },
+ subList: [],
+ };
+
+ // Process third level items
+ secondLevel.subList.forEach((thirdLevel: MenuThirdLevel) => {
+ // Check if the third level's siteUrl matches exactly
+ if (
+ thirdLevel.siteUrl &&
+ siteUrls.some((url) => url === thirdLevel.siteUrl)
+ ) {
+ // Create a modified third level item
+ const newThirdLevel: FilteredMenuThirdLevel = {
+ name: thirdLevel.name,
+ lg: { ...thirdLevel.lg },
+ siteUrl: thirdLevel.siteUrl,
+ };
+
+ // Add the modified third level to the second level's subList
+ newSecondLevel.subList.push(newThirdLevel);
+ }
+ });
+
+ // Only add the second level to the first level if it has any matching third level items
+ if (newSecondLevel.subList.length > 0) {
+ newFirstLevel.subList.push(newSecondLevel);
+ }
+ });
+
+ // Only add the first level to the result if it has any matching second level items
+ if (newFirstLevel.subList.length > 0) {
+ acc.push(newFirstLevel);
+ }
+
+ return acc;
+ },
+ []
+ );
+
+ return filteredMenu;
+}
\ No newline at end of file
diff --git a/WebServices/client-frontend/src/components/menuCleint/menu.tsx b/WebServices/client-frontend/src/components/menuCleint/menu.tsx
new file mode 100644
index 0000000..d567a8a
--- /dev/null
+++ b/WebServices/client-frontend/src/components/menuCleint/menu.tsx
@@ -0,0 +1,116 @@
+"use client";
+
+import React, { useState } from "react";
+import Link from "next/link";
+import { Home, ChevronDown, ChevronRight } from "lucide-react";
+import { transformMenu } from "./handler";
+import type { LanguageTranslation } from "./handler";
+
+interface ClientMenuProps {
+ siteUrls: string[];
+ lang: keyof LanguageTranslation;
+}
+
+const ClientMenu: React.FC = ({ siteUrls, lang }) => {
+ const transformedMenu = transformMenu(siteUrls) || [];
+
+ // State to track which menu items are expanded
+ const [firstLayerIndex, setFirstLayerIndex] = useState(-1);
+ const [secondLayerIndex, setSecondLayerIndex] = useState(-1);
+
+ // Handle first level menu click
+ const handleFirstLevelClick = (index: number) => {
+ setFirstLayerIndex(index === firstLayerIndex ? -1 : index);
+ setSecondLayerIndex(-1); // Reset second layer selection when first layer changes
+ };
+
+ // Handle second level menu click
+ const handleSecondLevelClick = (index: number) => {
+ setSecondLayerIndex(index === secondLayerIndex ? -1 : index);
+ };
+
+ // No need for a navigation handler since we'll use Link components
+
+ return (
+
+
+
+ Dashboard
+
+
+
+
+
+ );
+};
+
+export default ClientMenu;
diff --git a/WebServices/client-frontend/src/components/menuCleint/store.tsx b/WebServices/client-frontend/src/components/menuCleint/store.tsx
new file mode 100644
index 0000000..b8e137a
--- /dev/null
+++ b/WebServices/client-frontend/src/components/menuCleint/store.tsx
@@ -0,0 +1,203 @@
+const Individual = {
+ name: "Individual",
+ lg: {
+ tr: "Birey",
+ en: "Individual",
+ },
+ siteUrl: "/individual",
+};
+
+const User = {
+ name: "User",
+ lg: {
+ tr: "Kullanıcı",
+ en: "User",
+ },
+ siteUrl: "/user",
+};
+
+const Build = {
+ name: "Build",
+ lg: {
+ tr: "Apartman",
+ en: "Build",
+ },
+ siteUrl: "/build",
+};
+
+const Dashboard = {
+ name: "Dashboard",
+ lg: {
+ tr: "Pano",
+ en: "Dashboard",
+ },
+ siteUrl: "/dashboard",
+};
+
+const BuildParts = {
+ name: "BuildParts",
+ lg: {
+ tr: "Daireler",
+ en: "Build Parts",
+ },
+ siteUrl: "/build/parts",
+};
+
+const BuildArea = {
+ name: "BuildArea",
+ lg: {
+ tr: "Daire Alanları",
+ en: "Build Area",
+ },
+ siteUrl: "/build/area",
+};
+
+const ManagementAccounting = {
+ name: "ManagementAccounting",
+ lg: {
+ tr: "Yönetim Cari Hareketler",
+ en: "ManagementAccounting",
+ },
+ siteUrl: "/management/accounting",
+};
+
+const ManagementBudget = {
+ name: "ManagementBudget",
+ lg: {
+ tr: "Yönetim Bütçe İşlemleri",
+ en: "Management Budget",
+ },
+ siteUrl: "/management/budget",
+};
+
+const BuildPartsAccounting = {
+ name: "BuildPartsAccounting",
+ lg: {
+ tr: "Daire Cari Hareketler",
+ en: "Build Parts Accounting",
+ },
+ siteUrl: "/build/parts/accounting",
+};
+
+const AnnualMeeting = {
+ name: "AnnualMeeting",
+ lg: {
+ tr: "Yıllık Olağan Toplantı Tanımlama ve Davet",
+ en: "Annual Meetings and Invitations",
+ },
+ siteUrl: "/annual/meeting",
+};
+
+const AnnualMeetingClose = {
+ name: "AnnualMeetingClose",
+ lg: {
+ tr: "Yıllık Olağan Toplantı kapatma ve Cari Yaratma",
+ en: "Annual Meeting Close and Accountings",
+ },
+ siteUrl: "/annual/meeting/close",
+};
+
+const EmergencyMeeting = {
+ name: "EmergencyMeeting",
+ lg: {
+ tr: "Acil Toplantı Tanımlama ve Davet",
+ en: "Emergency Meeting and Invitations",
+ },
+ siteUrl: "/emergency/meeting",
+};
+
+const EmergencyMeetingClose = {
+ name: "EmergencyMeetingClose",
+ lg: {
+ tr: "Acil Olağan Toplantı kapatma ve Cari Yaratma",
+ en: "Emergency Meeting Close and Accountings",
+ },
+ siteUrl: "/emergency/meeting/close",
+};
+
+const MeetingParticipations = {
+ name: "MeetingParticipations",
+ lg: {
+ tr: "Toplantı Katılım İşlemleri",
+ en: "Meeting Participations",
+ },
+ siteUrl: "/meeting/participation",
+};
+
+const Menu = [
+ {
+ name: "Dashboard",
+ lg: {
+ tr: "Pano",
+ en: "Dashboard",
+ },
+ subList: [
+ {
+ name: "Dashboard",
+ lg: {
+ tr: "Pano",
+ en: "Dashboard",
+ },
+ subList: [Dashboard],
+ },
+ ],
+ },
+ {
+ name: "Definitions",
+ lg: {
+ tr: "Tanımlar",
+ en: "Definitions",
+ },
+ subList: [
+ {
+ name: "People",
+ lg: {
+ tr: "Kişiler",
+ en: "People",
+ },
+ subList: [Individual, User],
+ },
+ {
+ name: "Building",
+ lg: {
+ tr: "Binalar",
+ en: "Building",
+ },
+ subList: [Build, BuildParts, BuildArea],
+ },
+ ],
+ },
+ {
+ name: "Building Management",
+ lg: {
+ tr: "Bina Yönetimi",
+ en: "Building Management",
+ },
+ subList: [
+ {
+ name: "Management Accounting",
+ lg: {
+ tr: "Cari işlemler",
+ en: "Management Accounting",
+ },
+ subList: [ManagementAccounting, ManagementBudget, BuildPartsAccounting],
+ },
+ {
+ name: "Meetings",
+ lg: {
+ tr: "Toplantılar",
+ en: "Meetings",
+ },
+ subList: [
+ AnnualMeeting,
+ AnnualMeetingClose,
+ EmergencyMeeting,
+ EmergencyMeetingClose,
+ MeetingParticipations,
+ ],
+ },
+ ],
+ },
+];
+
+export default Menu;
diff --git a/docker-compose.yml b/docker-compose.yml
index 388b209..45d020c 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -51,22 +51,82 @@ services:
- REDIS_DB=0
ports:
- "11222:6379"
+ mem_limit: 512M
+ cpus: 0.5
-# client_frontend:
-# container_name: client_frontend
-# build:
-# context: .
-# dockerfile: WebServices/client-frontend/Dockerfile
-# networks:
-# - wag-services
-# ports:
-# - "3000:3000"
-# # volumes:
-# # - client-frontend:/WebServices/client-frontend
-# environment:
-# - NODE_ENV=development
-# mem_limit: 4096M
-# cpus: 2.0
+ client_frontend:
+ container_name: client_frontend
+ build:
+ context: .
+ dockerfile: WebServices/client-frontend/Dockerfile
+ networks:
+ - wag-services
+ ports:
+ - "3000:3000"
+ # volumes:
+ # - client-frontend:/WebServices/client-frontend
+ environment:
+ - NODE_ENV=development
+ mem_limit: 4096M
+ cpus: 1.5
+
+ identity_service:
+ container_name: identity_service
+ build:
+ context: .
+ dockerfile: ApiServices/IdentityService/Dockerfile
+ networks:
+ - wag-services
+ env_file:
+ - api_env.env
+ environment:
+ - API_PATH=app:app
+ - API_HOST=0.0.0.0
+ - API_PORT=8002
+ - API_LOG_LEVEL=info
+ - API_RELOAD=1
+ - API_APP_NAME=evyos-identity-api-gateway
+ - API_TITLE=WAG API Identity Api Gateway
+ - API_FORGOT_LINK=https://identity_service/forgot-password
+ - API_DESCRIPTION=This api is serves as web identity api gateway only to evyos web services.
+ - API_APP_URL=https://identity_service
+ ports:
+ - "8002:8002"
+ depends_on:
+ - postgres-service
+ - mongo_service
+ - redis_service
+ mem_limit: 512M
+ cpus: 0.5
+
+ auth_service:
+ container_name: auth_service
+ build:
+ context: .
+ dockerfile: ApiServices/AuthService/Dockerfile
+ networks:
+ - wag-services
+ env_file:
+ - api_env.env
+ environment:
+ - API_PATH=app:app
+ - API_HOST=0.0.0.0
+ - API_PORT=8001
+ - API_LOG_LEVEL=info
+ - API_RELOAD=1
+ - API_APP_NAME=evyos-auth-api-gateway
+ - API_TITLE=WAG API Auth Api Gateway
+ - API_FORGOT_LINK=https://auth_service/forgot-password
+ - API_DESCRIPTION=This api is serves as web auth api gateway only to evyos web services.
+ - API_APP_URL=https://auth_service
+ ports:
+ - "8001:8001"
+ depends_on:
+ - postgres-service
+ - mongo_service
+ - redis_service
+ mem_limit: 512M
+ cpus: 0.5
# management_frontend:
# container_name: management_frontend
@@ -137,74 +197,6 @@ services:
# - mongo_service
# - redis_service
-# dealer_service:
-# container_name: dealer_service
-# build:
-# context: .
-# dockerfile: ApiServices/DealerService/Dockerfile
-# networks:
-# - wag-services
-# env_file:
-# - api_env.env
-# depends_on:
-# - postgres-service
-# - mongo_service
-# - redis_service
-
- identity_service:
- container_name: identity_service
- build:
- context: .
- dockerfile: ApiServices/IdentityService/Dockerfile
- networks:
- - wag-services
- env_file:
- - api_env.env
- environment:
- - API_PATH=app:app
- - API_HOST=0.0.0.0
- - API_PORT=8002
- - API_LOG_LEVEL=info
- - API_RELOAD=1
- - API_APP_NAME=evyos-identity-api-gateway
- - API_TITLE=WAG API Identity Api Gateway
- - API_FORGOT_LINK=https://identity_service/forgot-password
- - API_DESCRIPTION=This api is serves as web identity api gateway only to evyos web services.
- - API_APP_URL=https://identity_service
- ports:
- - "8002:8002"
- depends_on:
- - postgres-service
- - mongo_service
- - redis_service
-
- auth_service:
- container_name: auth_service
- build:
- context: .
- dockerfile: ApiServices/AuthService/Dockerfile
- networks:
- - wag-services
- env_file:
- - api_env.env
- environment:
- - API_PATH=app:app
- - API_HOST=0.0.0.0
- - API_PORT=8001
- - API_LOG_LEVEL=info
- - API_RELOAD=1
- - API_APP_NAME=evyos-auth-api-gateway
- - API_TITLE=WAG API Auth Api Gateway
- - API_FORGOT_LINK=https://auth_service/forgot-password
- - API_DESCRIPTION=This api is serves as web auth api gateway only to evyos web services.
- - API_APP_URL=https://auth_service
- ports:
- - "8001:8001"
- depends_on:
- - postgres-service
- - mongo_service
- - redis_service
-
# test_server:
# container_name: test_server
# build: