web service tenant first try

This commit is contained in:
Berkay 2025-05-07 11:41:08 +03:00
parent aee9d59750
commit 4d7a6e6ec0
25 changed files with 161 additions and 80 deletions

View File

@ -0,0 +1,27 @@
"use server";
import React from "react";
import DashboardLayout from "@/components/layouts/DashboardLayout";
import { useDashboardPage } from "@/components/common/hooks/useDashboardPage";
export default async function Dashboard({
searchParams,
}: {
searchParams: Promise<{ [key: string]: string | undefined }>;
}) {
const {
activePage,
searchParamsInstance,
lang,
PageComponent,
siteUrlsList,
} = await useDashboardPage({
pageUrl: "/management/budget/actions",
searchParams
});
return (
<DashboardLayout lang={lang} activePage={activePage} siteUrls={siteUrlsList} >
<PageComponent lang={lang} queryParams={searchParamsInstance} />
</DashboardLayout>
);
}

View File

@ -15,7 +15,7 @@ export default async function Dashboard({
PageComponent, PageComponent,
siteUrlsList, siteUrlsList,
} = await useDashboardPage({ } = await useDashboardPage({
pageUrl: "/management/budget", pageUrl: "/management/budget/status",
searchParams searchParams
}); });

View File

@ -61,6 +61,24 @@ const ManagementAccounting = {
siteUrl: "/management/accounting", siteUrl: "/management/accounting",
}; };
const BuildingBudgetActions = {
name: "BuildingBudgetActions",
lg: {
tr: "Son Bakiye",
en: "Last Balance",
},
siteUrl: "/management/budget/actions",
};
const BuildingBudgetStatus = {
name: "BuildingBudgetStatus",
lg: {
tr: "Bakiye Durumu",
en: "Balance Status",
},
siteUrl: "/management/budget/status",
};
const ManagementBudget = { const ManagementBudget = {
name: "ManagementBudget", name: "ManagementBudget",
lg: { lg: {
@ -207,7 +225,7 @@ const Menu = [
tr: "Cari işlemler", tr: "Cari işlemler",
en: "Management Accounting", en: "Management Accounting",
}, },
subList: [ManagementAccounting, ManagementBudget, BuildPartsAccounting], subList: [ManagementAccounting, ManagementBudget, BuildPartsAccounting, BuildingBudgetActions, BuildingBudgetStatus],
}, },
{ {
name: "Meetings", name: "Meetings",
@ -215,13 +233,7 @@ const Menu = [
tr: "Toplantılar", tr: "Toplantılar",
en: "Meetings", en: "Meetings",
}, },
subList: [ subList: [AnnualMeeting, AnnualMeetingClose, EmergencyMeeting, EmergencyMeetingClose, MeetingParticipations],
AnnualMeeting,
AnnualMeetingClose,
EmergencyMeeting,
EmergencyMeetingClose,
MeetingParticipations,
],
}, },
], ],
}, },

View File

@ -29,19 +29,34 @@ const NavigationMenu: React.FC<NavigationMenuProps> = ({ transformedMenu, lang,
// Handle first level menu click // Handle first level menu click
const handleFirstLevelClick = (index: number) => { const handleFirstLevelClick = (index: number) => {
// Only allow collapsing if we're not on an active page or if it's dashboard // If this is the active menu path and not dashboard, don't allow collapsing it
if (activePage === "/dashboard" || !activeMenuPath) { if (activeMenuPath && activeMenuPath.first === index && activePage !== "/dashboard") {
setFirstLayerIndex(index === firstLayerIndex ? -1 : index); // Don't collapse the active menu item
setSecondLayerIndex(-1); // Reset second layer selection when first layer changes return;
}
// Otherwise allow expanding/collapsing any menu item
setFirstLayerIndex(index === firstLayerIndex ? -1 : index);
// If we're clicking on a different first level, reset second level
if (index !== firstLayerIndex) {
setSecondLayerIndex(-1);
} }
}; };
// Handle second level menu click // Handle second level menu click
const handleSecondLevelClick = (index: number) => { const handleSecondLevelClick = (index: number) => {
// Only allow collapsing if we're not on an active page or if it's dashboard // If this is the active menu path and not dashboard, don't allow collapsing it
if (activePage === "/dashboard" || !activeMenuPath) { if (activeMenuPath &&
setSecondLayerIndex(index === secondLayerIndex ? -1 : index); activeMenuPath.first === firstLayerIndex &&
activeMenuPath.second === index &&
activePage !== "/dashboard") {
// Don't collapse the active menu item
return;
} }
// Otherwise allow expanding/collapsing any menu item
setSecondLayerIndex(index === secondLayerIndex ? -1 : index);
}; };
return ( return (

View File

@ -1,8 +0,0 @@
import { PageComponent } from "@/components/validations/translations/translation";
import { peopleApplications } from "./people";
import { dashboardApplications } from "./dashboard";
export const PageNavigator: Record<string, Record<string, PageComponent>> = {
"/individual": peopleApplications,
"/dashboard": dashboardApplications,
};

View File

@ -0,0 +1,6 @@
import { PageComponent } from "@/components/validations/translations/translation";
import TenantActionsSuperUserApp from "./superusers/app";
export const tenantBudgetActionsApplications: Record<string, PageComponent> = {
app000023: TenantActionsSuperUserApp,
};

View File

@ -0,0 +1,9 @@
import React from "react";
const TenantActionsSuperUserApp = () => {
return (
<><h1>Tenant Budget Actions</h1></>
);
};
export default TenantActionsSuperUserApp;

View File

@ -0,0 +1,6 @@
import { PageComponent } from "@/components/validations/translations/translation";
import TenantBudgetStatusSuperUserApp from "./superusers/app";
export const tenantBudgetStatusApplications: Record<string, PageComponent> = {
app000024: TenantBudgetStatusSuperUserApp,
};

View File

@ -0,0 +1,9 @@
import React from "react";
const TenantBudgetStatusSuperUserApp = () => {
return (
<><h1>Tenant Budget Status</h1></>
);
};
export default TenantBudgetStatusSuperUserApp;

View File

@ -1,10 +1,12 @@
import { PageComponent } from "@/components/validations/translations/translation"; import { PageComponent } from "@/components/validations/translations/translation";
import { peopleApplications } from "./Pages/people"; import { peopleApplications } from "@/eventRouters/Pages/people";
import { dashboardApplications } from "./Pages/dashboard"; import { dashboardApplications } from "@/eventRouters/Pages/dashboard";
import { tenantBudgetActionsApplications } from "@/eventRouters/Pages/tenantActions";
import { tenantBudgetStatusApplications } from "@/eventRouters/Pages/tenantBudgetStatus";
export const menuPages: Record<string, Record<string, PageComponent>> = { export const menuPages: Record<string, Record<string, PageComponent>> = {
"/individual": peopleApplications, "/individual": peopleApplications,
"/dashboard": dashboardApplications, "/dashboard": dashboardApplications,
"/management/budget/actions": tenantBudgetActionsApplications,
"/management/budget/status": tenantBudgetStatusApplications,
}; };
export default menuPages;

View File

@ -1,6 +1,6 @@
import { PageProps } from "../validations/translations/translation"; import { PageProps } from "../validations/translations/translation";
import { UnAuthorizedPage } from "./unauthorizedpage"; import { UnAuthorizedPage } from "./unauthorizedpage";
import menuPages from "./index"; import { menuPages } from "@/eventRouters/index";
export function retrievePageByUrl(siteUrl: string, url: string): React.FC<PageProps> { export function retrievePageByUrl(siteUrl: string, url: string): React.FC<PageProps> {
console.log("siteUrl", siteUrl, "url", url); console.log("siteUrl", siteUrl, "url", url);

View File

@ -1,27 +1,23 @@
"use client"; "use client";
import { useState, useEffect } from "react";
import LoginOccupant from "./LoginOccupant"; import LoginOccupant from "./LoginOccupant";
import LoginEmployee from "./LoginEmployee"; import LoginEmployee from "./LoginEmployee";
import { useState, useEffect } from "react";
import { LanguageSelectionComponent } from "@/components/common/HeaderSelections/LanguageSelectionComponent";
import { Company, SelectListProps, BuildingMap } from "./types"; import { Company, SelectListProps, BuildingMap } from "./types";
import { selectEmployeeTranslation, selectOccupantTranslation } from "./language"; import { selectEmployeeTranslation, selectOccupantTranslation } from "./language";
import { LanguageSelectionComponent } from "@/components/common/HeaderSelections/LanguageSelectionComponent";
const Select: React.FC<SelectListProps> = ({ selectionList, isEmployee, isOccupant, language }) => { const Select: React.FC<SelectListProps> = ({ selectionList, isEmployee, isOccupant, language }) => {
const isEmployeeTrue = isEmployee && Array.isArray(selectionList) const isEmployeeTrue = isEmployee && Array.isArray(selectionList)
const isOccupantTrue = isOccupant && !Array.isArray(selectionList) const isOccupantTrue = isOccupant && !Array.isArray(selectionList)
const initTranslation = isEmployee ? selectEmployeeTranslation[language as "en" | "tr"] : selectOccupantTranslation[language as "en" | "tr"] const initTranslation = isEmployee ? selectEmployeeTranslation[language as "en" | "tr"] : selectOccupantTranslation[language as "en" | "tr"]
console.log("initTranslation", initTranslation);
const [lang, setLang] = useState(language); const [lang, setLang] = useState(language);
const [translation, setTranslation] = useState(initTranslation); const [translation, setTranslation] = useState(initTranslation);
const [listEmployeeSelection, setListEmployeeSelection] = useState<Company[]>(selectionList as Company[]); const [listEmployeeSelection, setListEmployeeSelection] = useState<Company[]>(selectionList as Company[]);
const [listOccupantSelection, setListOccupantSelection] = useState<BuildingMap>(selectionList as BuildingMap); const [listOccupantSelection, setListOccupantSelection] = useState<BuildingMap>(selectionList as BuildingMap);
console.log("translation", translation);
useEffect(() => { useEffect(() => {
if (isEmployee) { setListEmployeeSelection(selectionList as Company[]) } if (isEmployee) { setListEmployeeSelection(selectionList as Company[]) }
else if (isOccupant) { setListOccupantSelection(selectionList as BuildingMap) } else if (isOccupant) { setListOccupantSelection(selectionList as BuildingMap) }
@ -43,7 +39,6 @@ const Select: React.FC<SelectListProps> = ({ selectionList, isEmployee, isOccupa
<div className="flex h-full min-h-[inherit] flex-col items-center justify-center gap-4"> <div className="flex h-full min-h-[inherit] flex-col items-center justify-center gap-4">
<div className="w-full max-w-md rounded-lg bg-white p-8 shadow-md"> <div className="w-full max-w-md rounded-lg bg-white p-8 shadow-md">
<h2 className="mb-6 text-center text-2xl font-bold text-gray-900">{translation?.select}</h2>
{isEmployeeTrue && <LoginEmployee translation={translation} selectionList={listEmployeeSelection} />} {isEmployeeTrue && <LoginEmployee translation={translation} selectionList={listEmployeeSelection} />}
{isOccupantTrue && <LoginOccupant translation={translation} selectionList={listOccupantSelection} />} {isOccupantTrue && <LoginOccupant translation={translation} selectionList={listOccupantSelection} />}
</div> </div>

View File

@ -194,6 +194,7 @@ async function removeApplicationFromService(payload: RemoveApplicationFromServic
} }
async function createApplication(payload: any) { async function createApplication(payload: any) {
console.log("Creating application with payload:", payload);
try { try {
const response = await fetchDataWithToken( const response = await fetchDataWithToken(
applicationCreateEndpoint, applicationCreateEndpoint,

View File

@ -63,12 +63,13 @@ export async function handleCreateOperation(
} }
if (createFunction) { if (createFunction) {
console.log("Body:", body);
const result = await createFunction(body); const result = await createFunction(body);
return createResponse(result); return createResponse(result);
} }
return createResponse({ return createResponse({
id: Math.floor(Math.random() * 1000), uuid: Math.floor(Math.random() * 1000),
...body, ...body,
}); });
} }
@ -136,9 +137,15 @@ export function createCreateHandler(
requiredFields: string[] = [] requiredFields: string[] = []
) { ) {
console.log("Required fields:", requiredFields); console.log("Required fields:", requiredFields);
return withErrorHandling((body: any) => // This handler only takes the body parameter, not the request
handleCreateOperation(body, createFunction, requiredFields) return withErrorHandling((body: any) => {
); // Ensure we're only passing the actual body data to the create function
if (body && typeof body === 'object' && body.body) {
console.log("Extracting body from request body");
return handleCreateOperation(body.body, createFunction, requiredFields);
}
return handleCreateOperation(body, createFunction, requiredFields);
});
} }
/** /**

View File

@ -1,6 +1,6 @@
import { NextRequest } from "next/server"; import { NextRequest } from "next/server";
import { errorResponse } from "./responseHandlers"; import { errorResponse } from "./responseHandlers";
import { ValidationResult, ApiHandler } from "./types"; import { ValidationResult, ApiHandler, ApiHandlerBodyOnly, ApiHandlerWithRequest } from "./types";
/** /**
* Safely parse JSON request body with error handling * Safely parse JSON request body with error handling
@ -30,7 +30,15 @@ export function withErrorHandling(
return errorResponse("Invalid request body", 400); return errorResponse("Invalid request body", 400);
} }
return await handler(request, body); // Check handler parameter count to determine if it needs request object
// If handler has only 1 parameter, it's likely a create operation that only needs body
if (handler.length === 1) {
// Cast to the appropriate handler type
return await (handler as ApiHandlerBodyOnly)(body);
} else {
// Otherwise pass both request and body (for list, update, delete operations)
return await (handler as ApiHandlerWithRequest)(request, body);
}
} catch (error: any) { } catch (error: any) {
return errorResponse( return errorResponse(
error.message || "Internal Server Error", error.message || "Internal Server Error",

View File

@ -90,9 +90,11 @@ export const collectPaginationFromApiResponse = (
}; };
/** /**
* API handler function type * API handler function types
*/ */
export type ApiHandler = (request: NextRequest, body: any) => Promise<Response>; export type ApiHandlerWithRequest = (request: NextRequest, body: any) => Promise<Response>;
export type ApiHandlerBodyOnly = (body: any) => Promise<Response>;
export type ApiHandler = ApiHandlerWithRequest | ApiHandlerBodyOnly;
/** /**
* List function type * List function type

View File

@ -103,7 +103,7 @@ export function CreateComponent<T>({
const onSubmit: SubmitHandler<Record<string, any>> = async (data) => { const onSubmit: SubmitHandler<Record<string, any>> = async (data) => {
try { try {
if (apiUrl) { if (apiUrl) {
const createUrl = `${apiUrl}/create`; const createUrl = `${apiUrl}`;
const response = await fetch(createUrl, { const response = await fetch(createUrl, {
method: 'POST', method: 'POST',
headers: { headers: {
@ -252,7 +252,7 @@ export function CreateComponent<T>({
return null; return null;
} }
}; };
return ( return (
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
<div className="grid grid-cols-2 gap-4 pt-6 my-4"> <div className="grid grid-cols-2 gap-4 pt-6 my-4">

View File

@ -15,11 +15,10 @@ export function FormDisplay<T>({
lang, lang,
translations, translations,
formProps = {}, formProps = {},
apiUrl, apiUrls,
}: FormDisplayProps<T>) { }: FormDisplayProps<T>) {
const [enhancedFormProps, setEnhancedFormProps] = useState(formProps); const [enhancedFormProps, setEnhancedFormProps] = useState(formProps);
useEffect(() => { useEffect(() => {
const updateFormProps = async () => { const updateFormProps = async () => {
try { try {
@ -88,7 +87,7 @@ export function FormDisplay<T>({
lang={lang} lang={lang}
translations={translations} translations={translations}
formProps={enhancedFormProps} formProps={enhancedFormProps}
apiUrl={apiUrl} apiUrl={apiUrls?.create}
/> />
); );
case "update": case "update":
@ -104,7 +103,7 @@ export function FormDisplay<T>({
lang={lang} lang={lang}
translations={translations} translations={translations}
formProps={enhancedFormProps} formProps={enhancedFormProps}
apiUrl={apiUrl} apiUrl={apiUrls?.update}
/> />
) : null; ) : null;
case "view": case "view":

View File

@ -180,7 +180,7 @@ export function UpdateComponent<T>({
} }
}); });
const updateUrl = `${apiUrl}/update?uuid=${uuid}`; const updateUrl = `${apiUrl}?uuid=${uuid}`;
console.log("Updating application with payload:", dataToSend, 'uuId:', uuid); console.log("Updating application with payload:", dataToSend, 'uuId:', uuid);
try { try {
let response = await fetch(updateUrl, { let response = await fetch(updateUrl, {

View File

@ -47,5 +47,5 @@ export interface FormDisplayProps<T> {
lang: string; lang: string;
translations: Record<string, Record<string, string>>; translations: Record<string, Record<string, string>>;
formProps?: Record<string, any>; formProps?: Record<string, any>;
apiUrl: string; apiUrls: Record<string, string>;
} }

View File

@ -287,7 +287,7 @@ const AppendersApplicationPage: React.FC<PageProps> = ({ lang }: { lang: Languag
onCancel: cancelAllSelections, onCancel: cancelAllSelections,
lang: lang, lang: lang,
translations: translationsServices, translations: translationsServices,
apiUrl: '/api/services', apiUrls: {},
formProps: { formProps: {
fieldDefinitions: fieldDefinitionsServices, fieldDefinitions: fieldDefinitionsServices,
validationSchema: validationSchemaServices, validationSchema: validationSchemaServices,
@ -304,7 +304,7 @@ const AppendersApplicationPage: React.FC<PageProps> = ({ lang }: { lang: Languag
onCancel: cancelAllSelections, onCancel: cancelAllSelections,
lang: lang, lang: lang,
translations: translationsApplications, translations: translationsApplications,
apiUrl: '/api/applications', apiUrls: {},
formProps: { formProps: {
fieldDefinitions: fieldDefinitionsEvents, fieldDefinitions: fieldDefinitionsEvents,
validationSchema: validationSchemaEvents, validationSchema: validationSchemaEvents,
@ -321,7 +321,7 @@ const AppendersApplicationPage: React.FC<PageProps> = ({ lang }: { lang: Languag
onCancel: cancelAllSelections, onCancel: cancelAllSelections,
lang: lang, lang: lang,
translations: translationsAppenders, translations: translationsAppenders,
apiUrl: '/api/appenders/applications', apiUrls: {},
formProps: { formProps: {
fieldDefinitions: fieldDefinitionsAppenders, fieldDefinitions: fieldDefinitionsAppenders,
validationSchema: validationSchemaAppenders, validationSchema: validationSchemaAppenders,
@ -329,7 +329,6 @@ const AppendersApplicationPage: React.FC<PageProps> = ({ lang }: { lang: Languag
} }
}; };
return ( return (
<div className="container mx-auto p-4 overflow-y-auto" > <div className="container mx-auto p-4 overflow-y-auto" >
<div className="mb-4 flex justify-between items-center"> <div className="mb-4 flex justify-between items-center">
@ -343,19 +342,11 @@ const AppendersApplicationPage: React.FC<PageProps> = ({ lang }: { lang: Languag
</Card> </Card>
{mode === "list" ? ( {mode === "list" ? (
<div className="flex flex-col space-y-4"> <div className="flex flex-col space-y-4">
{ {!selectedItemServices ? <div className="w-full h-1/2"><ListComponentServices {...serviceListProps} /></div> :
!selectedItemServices ? <div className="w-full h-1/2"><ListComponentServices {...serviceListProps} /></div> : <div className="w-full h-1/2"><div className="flex flex-row space-x-4">
<div className="w-full h-1/2"> {loadingEvents ? <Loader /> : <div className="flex-1"><ListComponentEvents {...eventsListProps} /></div>}
{loadingAppenders ? <Loader /> : <div className="flex-1"><ListComponentEvents {...appendersListProps} /></div>}
<div className="flex flex-row space-x-4"> </div></div>
{
loadingEvents ? <Loader /> : <div className="flex-1"><ListComponentEvents {...eventsListProps} /></div>
}
{
loadingAppenders ? <Loader /> : <div className="flex-1"><ListComponentEvents {...appendersListProps} /></div>
}
</div>
</div>
} }
</div> </div>
) : ( ) : (

View File

@ -283,7 +283,7 @@ const AppendersEventsPage: React.FC<PageProps> = ({ lang }: { lang: Language })
onCancel: cancelAllSelections, onCancel: cancelAllSelections,
lang: lang, lang: lang,
translations: translationsServices, translations: translationsServices,
apiUrl: '/api/services', apiUrls: {},
formProps: { formProps: {
fieldDefinitions: fieldDefinitionsServices, fieldDefinitions: fieldDefinitionsServices,
validationSchema: validationSchemaServices, validationSchema: validationSchemaServices,
@ -300,7 +300,7 @@ const AppendersEventsPage: React.FC<PageProps> = ({ lang }: { lang: Language })
onCancel: cancelAllSelections, onCancel: cancelAllSelections,
lang: lang, lang: lang,
translations: translationsEvents, translations: translationsEvents,
apiUrl: '/api/events', apiUrls: {},
formProps: { formProps: {
fieldDefinitions: fieldDefinitionsEvents, fieldDefinitions: fieldDefinitionsEvents,
validationSchema: validationSchemaEvents, validationSchema: validationSchemaEvents,
@ -317,7 +317,7 @@ const AppendersEventsPage: React.FC<PageProps> = ({ lang }: { lang: Language })
onCancel: cancelAllSelections, onCancel: cancelAllSelections,
lang: lang, lang: lang,
translations: translationsAppenders, translations: translationsAppenders,
apiUrl: '/api/appenders', apiUrls: {},
formProps: { formProps: {
fieldDefinitions: fieldDefinitionsAppenders, fieldDefinitions: fieldDefinitionsAppenders,
validationSchema: validationSchemaAppenders, validationSchema: validationSchemaAppenders,

View File

@ -118,7 +118,10 @@ const ApplicationPage: React.FC<PageProps> = ({ lang }: { lang: Language }) => {
onCancel: cancelAllSelections, onCancel: cancelAllSelections,
lang, lang,
translations, translations,
apiUrl: '/api/applications', apiUrls: {
create: '/api/applications/create',
update: '/api/applications/update',
},
formProps: { formProps: {
fieldDefinitions, fieldDefinitions,
validationSchema, validationSchema,

View File

@ -7,7 +7,7 @@ const menuPages = {
"/dashboard": DashboardPage, "/dashboard": DashboardPage,
"/application": ApplicationPage, "/application": ApplicationPage,
"/append/event": AppendersEventsPage, "/append/event": AppendersEventsPage,
"/append/service": AppendersServicePage "/append/service": AppendersServicePage,
}; };
export default menuPages; export default menuPages;

View File

@ -10,12 +10,9 @@ services:
- "3000:3000" - "3000:3000"
environment: environment:
- NODE_ENV=development - NODE_ENV=development
cpus: 1 cpus: 2
mem_limit: 2048m mem_limit: 2048m
# volumes:
# - client-frontend:/WebServices/client-frontend
management_frontend: management_frontend:
container_name: management_frontend container_name: management_frontend
build: build:
@ -117,7 +114,7 @@ services:
context: . context: .
dockerfile: ApiServices/InitialService/Dockerfile dockerfile: ApiServices/InitialService/Dockerfile
environment: environment:
- SET_ALEMBIC=1 - SET_ALEMBIC=0
networks: networks:
- wag-services - wag-services
env_file: env_file: