updated service binders updated

This commit is contained in:
2025-05-03 23:35:03 +03:00
parent ac8c3fe1c3
commit 01f3e82a54
82 changed files with 735 additions and 3371 deletions

View File

@@ -1,5 +1,5 @@
"use server";
import { retrieveAccessToken } from "@/apicalls/cookies/token";
import { retrieveAccessToken } from "@/apicalls/cookies/endpoints";
import {
DEFAULT_RESPONSE,
defaultHeaders,

View File

@@ -25,7 +25,7 @@ async function listApplications(payload: PaginationParams): Promise<PaginatedApi
"POST",
false
);
// Format the response to match the expected PaginatedApiResponse format
if (response?.status === 200 || response?.status === 202) {
const responseData = response.data as any;

View File

@@ -2,7 +2,6 @@
import { fetchDataWithToken } from "../api-fetcher";
import { baseUrlAuth, tokenSecret } from "../basics";
import { cookies } from "next/headers";
import NextCrypto from "next-crypto";
const checkToken = `${baseUrlAuth}/authentication/token/check`;
@@ -17,14 +16,14 @@ async function checkAccessTokenIsValid() {
}
async function retrievePageList() {
const response = await fetchDataWithToken(siteUrls, {}, "GET", false);
const response: any = await fetchDataWithToken(siteUrls, {}, "GET", false);
return response?.status === 200 || response?.status === 202
? response.data?.sites
: null;
}
async function retrievePagebyUrl(pageUrl: string) {
const response = await fetchDataWithToken(
const response: any = await fetchDataWithToken(
pageValid,
{
page_url: pageUrl,
@@ -88,15 +87,10 @@ async function retrieveUserSelection() {
} else if (decrpytUserSelection?.user_type === "occupant") {
const buildingsList = accessObjects?.selectionList;
// Iterate through all buildings
if (buildingsList) {
// Loop through each building
for (const buildKey in buildingsList) {
const building = buildingsList[buildKey];
// Check if the building has occupants
if (building.occupants && building.occupants.length > 0) {
// Find the occupant with the matching build_living_space_uu_id
const occupant = building.occupants.find(
(occ: any) => occ.build_living_space_uu_id === userSelection
);
@@ -121,21 +115,6 @@ async function retrieveUserSelection() {
};
}
// const avatarInfo = await retrieveAvatarInfo();
// lang: avatarInfo?.data?.lang
// ? String(avatarInfo?.data?.lang).toLowerCase()
// : undefined,
// avatar: avatarInfo?.data?.avatar,
// fullName: avatarInfo?.data?.full_name,
// async function retrieveAvatarInfo() {
// const response = await fetchDataWithToken(
// `${baseUrlAuth}/authentication/avatar`,
// {},
// "POST"
// );
// return response;
// }
export {
checkAccessTokenIsValid,
retrieveAccessToken,
@@ -144,5 +123,4 @@ export {
retrieveUserSelection,
retrievePagebyUrl,
retrievePageList,
// retrieveavailablePages,
};

View File

@@ -53,7 +53,7 @@ async function loginViaAccessKeys(payload: LoginViaAccessKeys) {
);
console.log("response", response);
if (response.status === 200 || response.status === 202) {
const loginRespone = response?.data;
const loginRespone: any = response?.data;
const accessToken = await nextCrypto.encrypt(loginRespone.access_token);
const accessObject = await nextCrypto.encrypt(
JSON.stringify({

View File

@@ -0,0 +1,84 @@
"use server";
import { fetchDataWithToken } from "../api-fetcher";
import { baseUrlApplication } from "../basics";
import { PaginationParams } from "../schemas/list";
import type { PaginatedApiResponse } from "@/app/api/utils/types";
const servicesListEndpoint = `${baseUrlApplication}/service/list`;
async function listServices(payload: PaginationParams): Promise<PaginatedApiResponse<any>> {
try {
const response = await fetchDataWithToken(
servicesListEndpoint,
{
page: payload.page,
size: payload.size,
order_field: payload.orderField,
order_type: payload.orderType,
query: payload.query,
},
"POST",
false
);
if (response?.status === 200 || response?.status === 202) {
const responseData = response.data as PaginatedApiResponse<any>;
return {
data: responseData.data || [],
pagination: {
page: responseData.pagination?.page || 1,
size: responseData.pagination?.size || 10,
totalCount: responseData.pagination?.totalCount || 0,
totalItems: responseData.pagination?.totalItems || 0,
totalPages: responseData.pagination?.totalPages || 0,
pageCount: responseData.pagination?.pageCount || 0,
orderField: responseData.pagination?.orderField || ['name'],
orderType: responseData.pagination?.orderType || ['asc'],
query: responseData.pagination?.query || {},
next: responseData.pagination?.next || false,
back: responseData.pagination?.back || false
}
};
}
return {
data: [],
pagination: {
page: 1,
size: 10,
totalCount: 0,
totalItems: 0,
totalPages: 0,
pageCount: 0,
orderField: ['name'],
orderType: ['asc'],
query: {},
next: false,
back: false
}
};
} catch (error) {
console.error("Error fetching application list:", error);
// Return a default empty response instead of null to match the expected return type
return {
data: [],
pagination: {
page: 1,
size: 10,
totalCount: 0,
totalItems: 0,
totalPages: 0,
pageCount: 0,
orderField: ['name'],
orderType: ['asc'],
query: {},
next: false,
back: false
}
};
}
}
export {
listServices,
};

View File

@@ -3,7 +3,7 @@ import React from "react";
import {
checkAccessTokenIsValid,
retrieveUserType,
} from "@/apicalls/cookies/token";
} from "@/apicalls/cookies/endpoints";
import { redirect } from "next/navigation";
import LoginEmployee from "@/components/auth/LoginEmployee";
import LoginOccupant from "@/components/auth/LoginOccupant";

View File

@@ -1,5 +1,5 @@
import type { Metadata } from "next";
import { checkAccessTokenIsValid } from "@/apicalls/cookies/token";
import { checkAccessTokenIsValid } from "@/apicalls/cookies/endpoints";
import { redirect } from "next/navigation";
export const metadata: Metadata = {

View File

@@ -0,0 +1,4 @@
import { listApplications } from "@/apicalls/application/endpoints";
import { createListHandler } from "@/app/api/utils";
export const POST = createListHandler(listApplications);

View File

@@ -1,4 +1,4 @@
import { createCreateHandler } from "@/app/api/utils";
import { createApplication } from "@/apicalls/application/application";
import { createApplication } from "@/apicalls/application/endpoints";
export const POST = createCreateHandler(createApplication);

View File

@@ -1,4 +1,4 @@
import { listApplications } from "@/apicalls/application/application";
import { listApplications } from "@/apicalls/application/endpoints";
import { createListHandler } from "@/app/api/utils";
export const POST = createListHandler(listApplications);

View File

@@ -1,4 +1,4 @@
import { createUpdateHandler } from "../../utils";
import { updateApplication } from "@/apicalls/application/application";
import { updateApplication } from "@/apicalls/application/endpoints";
export const POST = createUpdateHandler(updateApplication);

View File

@@ -0,0 +1,4 @@
import { listApplications } from "@/apicalls/application/endpoints";
import { createListHandler } from "@/app/api/utils";
export const POST = createListHandler(listApplications);

View File

@@ -0,0 +1,4 @@
import { listServices } from "@/apicalls/services/endpoints";
import { createListHandler } from "@/app/api/utils";
export const POST = createListHandler(listServices);

View File

@@ -1,6 +1,6 @@
"use client";
import React from "react";
import { loginSelectEmployee } from "@/apicalls/login/login";
import { loginSelectEmployee } from "@/apicalls/login/endpoints";
import { useRouter } from "next/navigation";
import { Company } from "./types";

View File

@@ -1,6 +1,6 @@
"use client";
import React from "react";
import { loginSelectOccupant } from "@/apicalls/login/login";
import { loginSelectOccupant } from "@/apicalls/login/endpoints";
import { useRouter } from "next/navigation";
import { BuildingMap } from "./types";
@@ -33,10 +33,10 @@ function LoginOccupant({
}: LoginOccupantProps) {
const t = languageDictionary[lang] || languageDictionary.en;
const router = useRouter();
const handleSelect = (uu_id: string) => {
console.log("Selected occupant uu_id:", uu_id);
loginSelectOccupant({
build_living_space_uu_id: uu_id,
})

View File

@@ -3,7 +3,7 @@ import { useState, useTransition } from "react";
import { useRouter } from "next/navigation";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { loginViaAccessKeys } from "@/apicalls/login/login";
import { loginViaAccessKeys } from "@/apicalls/login/endpoints";
import { z } from "zod";
const loginSchema = z.object({
@@ -53,8 +53,8 @@ function Login() {
}
return dataResponse;
})
.catch(() => {});
} catch (error) {}
.catch(() => { });
} catch (error) { }
});
} catch (error) {
console.error("Login error:", error);

View File

@@ -3,7 +3,7 @@ import React from "react";
import {
loginSelectEmployee,
loginSelectOccupant,
} from "@/apicalls/login/login";
} from "@/apicalls/login/endpoints";
import { useRouter } from "next/navigation";
import LoginEmployee from "./LoginEmployee";
import LoginOccupant from "./LoginOccupant";
@@ -66,21 +66,21 @@ function SelectList({
return (
<>
{isEmployee && Array.isArray(selectionList) && (
<LoginEmployee
selectionList={selectionList as Company[]}
lang={lang as "en" | "tr"}
onSelect={setSelectionHandler}
<LoginEmployee
selectionList={selectionList as Company[]}
lang={lang as "en" | "tr"}
onSelect={setSelectionHandler}
/>
)}
{isOccupant && !Array.isArray(selectionList) && (
<LoginOccupant
selectionList={selectionList as BuildingMap}
lang={lang as "en" | "tr"}
onSelect={setSelectionHandler}
<LoginOccupant
selectionList={selectionList as BuildingMap}
lang={lang as "en" | "tr"}
onSelect={setSelectionHandler}
/>
)}
</>
</>
);
}

View File

@@ -4,6 +4,7 @@ import { CardItem } from "./CardItem";
import { CardSkeleton } from "./CardSkeleton";
import { getFieldValue, getGridClasses } from "./utils";
import { CardDisplayProps } from "./schema";
import { GridSize } from "../HeaderSelections/GridSelectionComponent";
export function CardDisplay<T>({
showFields,
@@ -12,7 +13,7 @@ export function CardDisplay<T>({
translations,
error,
loading,
titleField = "name",
titleField,
onCardClick,
renderCustomField,
gridCols = 4,
@@ -30,7 +31,7 @@ export function CardDisplay<T>({
}
return (
<div className={getGridClasses(gridCols)}>
<div className={getGridClasses(gridCols as GridSize)}>
{loading ? (
// Loading skeletons
Array.from({ length: 10 }).map((_, index) => (
@@ -44,7 +45,7 @@ export function CardDisplay<T>({
))
) : data.length === 0 ? (
<div className="col-span-full text-center py-6">
{(translations[lang] || {}).noData || "No data found"}
{translations[lang].noData || "No data found"}
</div>
) : (
data.map((item: T, index: number) => (
@@ -56,10 +57,10 @@ export function CardDisplay<T>({
titleField={titleField}
lang={lang}
translations={translations}
onCardClick={onCardClick}
renderCustomField={renderCustomField}
showViewIcon={showViewIcon}
showUpdateIcon={showUpdateIcon}
onCardClick={onCardClick}
renderCustomField={renderCustomField}
onViewClick={onViewClick}
onUpdateClick={onUpdateClick}
getFieldValue={getFieldValue}

View File

@@ -24,16 +24,16 @@ export function CardItem<T>({
onUpdateClick,
getFieldValue,
}: CardItemProps<T>) {
return (
<div key={index} className="w-full p-1">
<Card
className={`h-full ${onCardClick ? 'cursor-pointer hover:shadow-md transition-shadow' : ''}`}
onClick={onCardClick ? () => onCardClick(item) : undefined}
>
<CardHeader className="p-3 pb-0 flex justify-between items-start">
<h3 className="text-lg font-semibold">
{getFieldValue(item, titleField)}
</h3>
<h3 className="text-lg font-semibold">{getFieldValue(item, titleField)}</h3>
<CardActions
item={item}
showViewIcon={showViewIcon}

View File

@@ -1,117 +1,57 @@
/**
* CardDisplay component interfaces
*/
import { GridSize } from "../HeaderSelections/GridSelectionComponent";
/**
* Main props for the CardDisplay component
*/
export interface CardDisplayProps<T> {
/** Fields to display in each card */
showFields: string[];
/** Array of data items to display */
data: T[];
/** Current language code */
lang: string;
/** Translations object for field labels and messages */
translations: Record<string, any>;
/** Error object if data fetching failed */
error: Error | null;
/** Loading state indicator */
loading: boolean;
/** Field to use as the card title (default: "name") */
titleField?: string;
/** Handler for when a card is clicked */
onCardClick?: (item: T) => void;
/** Custom renderer for specific fields */
renderCustomField?: (item: T, field: string) => React.ReactNode;
/** Number of columns in the grid (1-6) */
gridCols?: 1 | 2 | 3 | 4 | 5 | 6;
/** Whether to show the view icon */
showViewIcon?: boolean;
/** Whether to show the update/edit icon */
showUpdateIcon?: boolean;
/** Handler for when the view icon is clicked */
onViewClick?: (item: T) => void;
/** Handler for when the update/edit icon is clicked */
onUpdateClick?: (item: T) => void;
}
/**
* Props for the CardItem component
*/
export interface CardItemProps<T> {
/** Data item to display */
item: T;
/** Index of the item in the data array */
index: number;
/** Fields to display in the card */
showFields: string[];
/** Field to use as the card title */
titleField: string;
/** Current language code */
lang: string;
/** Translations object for field labels */
translations: Record<string, any>;
/** Handler for when the card is clicked */
onCardClick?: (item: T) => void;
/** Custom renderer for specific fields */
renderCustomField?: (item: T, field: string) => React.ReactNode;
/** Whether to show the view icon */
showViewIcon: boolean;
/** Whether to show the update/edit icon */
showUpdateIcon: boolean;
/** Handler for when the view icon is clicked */
gridCols?: number | GridSize;
showViewIcon?: boolean;
showUpdateIcon?: boolean;
onViewClick?: (item: T) => void;
/** Handler for when the update/edit icon is clicked */
onUpdateClick?: (item: T) => void;
/** Function to get field values from the item */
getFieldValue: (item: any, field: string) => any;
}
/**
* Props for the CardActions component
*/
export interface CardActionsProps<T> {
/** Data item the actions apply to */
item: T;
/** Whether to show the view icon */
showViewIcon: boolean;
/** Whether to show the update/edit icon */
showUpdateIcon: boolean;
/** Handler for when the view icon is clicked */
onViewClick?: (item: T) => void;
/** Handler for when the update/edit icon is clicked */
onUpdateClick?: (item: T) => void;
}
/**
* Props for the CardField component
*/
export interface CardFieldProps<T> {
/** Data item the field belongs to */
export interface CardItemProps<T> {
item: T;
/** Field name to display */
field: string;
/** Current language code */
lang: string;
/** Translations object for field labels */
translations: Record<string, any>;
/** Custom renderer for specific fields */
renderCustomField?: (item: T, field: string) => React.ReactNode;
/** Function to get field values from the item */
getFieldValue: (item: any, field: string) => any;
}
/**
* Props for the CardSkeleton component
*/
export interface CardSkeletonProps {
/** Index of the skeleton in the loading array */
index: number;
/** Fields to create skeleton placeholders for */
showFields: string[];
/** Whether to show a skeleton for the view icon */
titleField: string;
lang: string;
translations: Record<string, any>;
onCardClick?: (item: T) => void;
renderCustomField?: (item: T, field: string) => React.ReactNode;
showViewIcon: boolean;
showUpdateIcon: boolean;
onViewClick?: (item: T) => void;
onUpdateClick?: (item: T) => void;
getFieldValue: (item: any, field: string) => any;
}
export interface CardActionsProps<T> {
item: T;
showViewIcon: boolean;
showUpdateIcon: boolean;
onViewClick?: (item: T) => void;
onUpdateClick?: (item: T) => void;
}
export interface CardFieldProps<T> {
item: T;
field: string;
lang: string;
translations: Record<string, any>;
renderCustomField?: (item: T, field: string) => React.ReactNode;
getFieldValue: (item: any, field: string) => any;
}
export interface CardSkeletonProps {
index: number;
showFields: string[];
showViewIcon: boolean;
/** Whether to show a skeleton for the update/edit icon */
showUpdateIcon: boolean;
}

View File

@@ -1,10 +1,5 @@
/**
* Safely gets a field value from an item, supporting nested fields with dot notation
*/
export function getFieldValue(item: any, field: string): any {
if (!item) return "";
// Handle nested fields with dot notation (e.g., "user.name")
if (field.includes(".")) {
const parts = field.split(".");
let value = item;
@@ -14,33 +9,31 @@ export function getFieldValue(item: any, field: string): any {
}
return value;
}
return item[field];
}
/**
* Gets a field label from translations or formats the field name
*/
export function getFieldLabel(field: string, translations: Record<string, any>, lang: string): string {
export function getFieldLabel(
field: string,
translations: Record<string, any>,
lang: string
): string {
const t = translations[lang] || {};
return t[field] || field.charAt(0).toUpperCase() + field.slice(1).replace(/_/g, " ");
return (
t[field] ||
field.charAt(0).toUpperCase() + field.slice(1).replace(/_/g, " ")
);
}
/**
* Generates responsive grid classes based on the gridCols prop
*/
export function getGridClasses(gridCols: 1 | 2 | 3 | 4 | 5 | 6): string {
const baseClass = "grid grid-cols-1 gap-4";
// Map gridCols to responsive classes
const colClasses: Record<number, string> = {
1: "",
2: "sm:grid-cols-2",
3: "sm:grid-cols-2 md:grid-cols-3",
4: "sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4",
5: "sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5",
6: "sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6"
6: "sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6",
};
return `${baseClass} ${colClasses[gridCols]}`;
}

View File

@@ -19,6 +19,7 @@ export function FormDisplay<T>({
}: FormDisplayProps<T>) {
const [enhancedFormProps, setEnhancedFormProps] = useState(formProps);
useEffect(() => {
const updateFormProps = async () => {
try {
@@ -91,12 +92,10 @@ export function FormDisplay<T>({
/>
);
case "update":
// Create a stable key for the component to ensure proper re-rendering
const updateKey = `update-${lang}-${(initialData as any)?.uu_id || 'new'}`;
return initialData ? (
<UpdateComponent<T>
key={updateKey} // Add key with lang and item ID to force re-render
key={updateKey}
initialData={initialData}
refetch={refetch}
setMode={setMode}
@@ -111,7 +110,7 @@ export function FormDisplay<T>({
case "view":
return initialData ? (
<ViewComponent<T>
key={`view-${lang}`} // Add key with lang to force re-render on language change
key={`view-${lang}`}
initialData={initialData}
refetch={refetch}
setMode={setMode}
@@ -119,7 +118,7 @@ export function FormDisplay<T>({
onCancel={onCancel}
lang={lang}
translations={translations}
formProps={enhancedFormProps} // Changed from formProps to enhancedFormProps for consistency
formProps={enhancedFormProps}
/>
) : null;
default:

View File

@@ -8,12 +8,7 @@ import { z } from "zod";
// Utility function to format field label
const formatFieldLabel = (fieldName: string) =>
fieldName
.replace(/([A-Z])/g, ' $1')
.replace(/_/g, ' ')
.replace(/^./, (str) => str.toUpperCase())
.replace(/\b\w/g, (c) => c.toUpperCase());
const formatFieldLabel = (fieldName: string) => fieldName.replace(/_/g, ' ').replace(/^./, (str) => str.toUpperCase()).replace(/\b\w/g, (c) => c.toUpperCase());
// Component for rendering a single field
const ViewField: React.FC<{
@@ -55,9 +50,7 @@ const ViewField: React.FC<{
<div className={`rounded-md border ${hasError ? 'border-red-500' : 'border-input'} bg-background px-3 py-2 text-sm min-h-[2.5rem] flex items-center`}>
{formatFieldValue()}
</div>
{hasError && (
<p className="text-sm text-red-500">{hasError}</p>
)}
{hasError && <p className="text-sm text-red-500">{hasError}</p>}
</div>
);
};
@@ -71,9 +64,7 @@ const ViewFieldGroup: React.FC<{
translations: any;
validationErrors: Record<string, string>;
}> = ({ groupName, fields, initialData, lang, translations, validationErrors }) => {
const getGroupTitle = (name: string) => {
return translations[name] || formatFieldLabel(name);
};
const getGroupTitle = (name: string) => { return translations[name] || formatFieldLabel(name); };
return (
<Card className="shadow-sm">
@@ -86,7 +77,6 @@ const ViewFieldGroup: React.FC<{
const fieldName = field.name || "";
const value = initialData ? (initialData as any)[fieldName] : undefined;
const hasError = validationErrors[fieldName];
return (
<ViewField
key={fieldName}
@@ -105,7 +95,6 @@ const ViewFieldGroup: React.FC<{
);
};
// Main ViewComponent
export function ViewComponent<T>({
initialData,
setMode,
@@ -117,26 +106,19 @@ export function ViewComponent<T>({
}: ViewComponentProps<T>) {
const t = translations[lang as keyof typeof translations] || {};
// Get field definitions and validation schema from formProps if available
const fieldDefinitions = formProps.fieldDefinitions || {};
const validationSchema = formProps.validationSchema as z.ZodObject<any> | undefined;
// Group fields by their group property
const [groupedFields, setGroupedFields] = useState<Record<string, FieldDefinition[]>>({});
// State to track validation errors if any
const [validationErrors, setValidationErrors] = useState<Record<string, string>>({});
// Process field definitions to group them
useEffect(() => {
if (Object.keys(fieldDefinitions).length > 0) {
const groups: Record<string, FieldDefinition[]> = {};
// Group fields by their group property
Object.entries(fieldDefinitions).forEach(([fieldName, definition]) => {
const def = definition as FieldDefinition;
if (!groups[def.group]) {
groups[def.group] = [];
}
if (!groups[def.group]) { groups[def.group] = []; }
groups[def.group].push({ ...def, name: fieldName });
});
@@ -144,31 +126,24 @@ export function ViewComponent<T>({
}
}, [fieldDefinitions]);
// For view mode, we don't need strict validation
// Just log validation issues but don't show errors to the user
useEffect(() => {
if (validationSchema && initialData) {
try {
// Try to parse the data through the Zod schema
validationSchema.parse(initialData);
// Clear any previous validation errors if successful
setValidationErrors({});
} catch (error) {
if (error instanceof z.ZodError) {
// Just log the errors but don't set them in the state
// This prevents showing validation errors in view mode
console.warn('View data validation issues (not shown to user):', error.errors);
// Clear any previous validation errors
setValidationErrors({});
}
}
}
}, [initialData, validationSchema]);
const handleEdit = () => {
setMode("update");
};
const handleEdit = () => { setMode("update") };
console.log("Grouped Fields", groupedFields);
console.log("Validation Errors", validationErrors);
return (
<Card className="w-full mb-6">
@@ -177,73 +152,66 @@ export function ViewComponent<T>({
<CardDescription>{t.viewDescription || "View item details"}</CardDescription>
</CardHeader>
<CardContent>
<div className="flex justify-end space-x-2 pt-4 my-4">
<Button variant="outline" onClick={onCancel}>
{t.back || "Back"}
</Button>
<Button onClick={handleEdit}>
{t.edit || "Edit"}
</Button>
</div>
<div className="space-y-6">
{/* If we have grouped fields from schema, use them */}
{Object.keys(groupedFields).length > 0 ? (
// Render fields grouped by their group property
Object.entries(groupedFields).map(([groupName, fields]) => (
<ViewFieldGroup
key={groupName}
groupName={groupName}
fields={fields}
initialData={initialData}
lang={lang}
translations={t}
validationErrors={validationErrors}
/>
))
) : (
// Fallback to the default view if no field definitions are available
initialData && (
<div className="space-y-4">
{validationSchema ? (
// If we have a validation schema, use its shape to determine fields
Object.entries(validationSchema.shape || {}).map(([fieldName, _]) => {
const value = (initialData as any)[fieldName];
// Skip undefined or null values
if (value === undefined || value === null) return null;
{
Object.keys(groupedFields).length > 0 ? (
Object.entries(groupedFields).map(([groupName, fields]) => (
<ViewFieldGroup
key={groupName}
groupName={groupName}
fields={fields}
initialData={initialData}
lang={lang}
translations={t}
validationErrors={validationErrors}
/>
))
) : (
initialData && (
<div className="space-y-4">
{validationSchema ? (
Object.entries(validationSchema.shape || {}).map(([fieldName, _]) => {
const value = (initialData as any)[fieldName];
if (value === undefined || value === null) return null;
return (
<ViewField
key={fieldName}
fieldName={fieldName}
value={value}
label={formatFieldLabel(fieldName)}
lang={lang}
translations={t}
/>
);
})
) : (
Object.entries(initialData as Record<string, any>).map(([fieldName, value]) => {
if (value === undefined || value === null) return null;
return (
<ViewField
key={fieldName}
fieldName={fieldName}
value={value}
label={formatFieldLabel(fieldName)}
lang={lang}
translations={t}
/>
);
})
)}
</div>
)
)}
return (
<ViewField
key={fieldName}
fieldName={fieldName}
value={value}
label={formatFieldLabel(fieldName)}
lang={lang}
translations={t}
/>
);
})
) : (
// If no schema, just iterate over the data keys
Object.entries(initialData as Record<string, any>).map(([fieldName, value]) => {
// Skip undefined or null values
if (value === undefined || value === null) return null;
return (
<ViewField
key={fieldName}
fieldName={fieldName}
value={value}
label={formatFieldLabel(fieldName)}
lang={lang}
translations={t}
/>
);
})
)}
</div>
)
)}
<div className="flex justify-end space-x-2 pt-4">
<Button variant="outline" onClick={onCancel}>
{t.back || "Back"}
</Button>
<Button onClick={handleEdit}>
{t.edit || "Edit"}
</Button>
</div>
</div>
</CardContent>
</Card>

View File

@@ -11,12 +11,10 @@ export function useApiData<T>(
endpoint: string,
initialParams: Partial<RequestParams> = {}
) {
// Define the fetch function that will be passed to useDataFetching
const fetchFromApi = async (
params: RequestParams
): Promise<ApiResponse<T>> => {
try {
// Prepare the request body with pagination parameters
const requestBody = {
page: params.page,
size: params.size,
@@ -25,10 +23,7 @@ export function useApiData<T>(
query: params.query,
};
// Construct the list endpoint URL
const listEndpoint = `${endpoint}/list`;
// Make the API request using POST
const response = await fetch(listEndpoint, {
method: "POST",
headers: {

View File

@@ -10,7 +10,7 @@ import {
X,
} from "lucide-react";
import { searchPlaceholder, menuLanguage } from "@/app/commons/pageDefaults";
import { logoutActiveSession } from "@/apicalls/login/login";
import { logoutActiveSession } from "@/apicalls/login/endpoints";
import { useRouter } from "next/navigation";
import { LanguageSelectionComponent } from "../common/HeaderSelections/LanguageSelectionComponent";

View File

@@ -1,8 +1,8 @@
"use client";
import React, { useState, useEffect } from "react";
import { Briefcase } from "lucide-react";
import { retrieveAccessObjects } from "@/apicalls/cookies/token";
import { loginSelectEmployee } from "@/apicalls/login/login";
import { retrieveAccessObjects } from "@/apicalls/cookies/endpoints";
import { loginSelectEmployee } from "@/apicalls/login/endpoints";
import { EmployeeProfileLanguage } from "./language";
import { EmployeeProfileSectionProps, CompanyInfo } from "./type";

View File

@@ -1,8 +1,8 @@
"use client";
import React, { useState, useEffect } from "react";
import { Building, Home, ChevronDown } from "lucide-react";
import { retrieveAccessObjects } from "@/apicalls/cookies/token";
import { loginSelectOccupant } from "@/apicalls/login/login";
import { retrieveAccessObjects } from "@/apicalls/cookies/endpoints";
import { loginSelectOccupant } from "@/apicalls/login/endpoints";
import { OccupantProfileLanguage } from "./language";
import { OccupantSelectionList, BuildingInfo, OccupantInfo, OccupantDetails, OccupantProfileSectionProps } from "./type";

View File

@@ -1,6 +1,6 @@
"use client";
import React, { useEffect, useState, Suspense, JSX } from "react";
import { retrieveUserSelection } from "@/apicalls/cookies/token";
import { retrieveUserSelection } from "@/apicalls/cookies/endpoints";
import { ClientMenuProps, UserSelection } from "@/validations/menu/menu";
import { dashboardLanguage } from "./language";
import EmployeeProfileSection from "./EmployeeProfileSection";

View File

@@ -3,14 +3,13 @@ import {
TranslationSet,
} from "@/validations/translations/translation";
import {
ApplicationBaseTranslationEn,
ApplicationBaseTranslationTr,
} from "./schemaList/schema";
ServiceBaseTranslationEn,
ServiceBaseTranslationTr,
} from "./schemaList/services";
// Define translations as a flat object structure to match the common components expectations
export const translations = {
en: {
...ApplicationBaseTranslationEn,
...ServiceBaseTranslationEn,
// Page title
mainTitle: "Services",
@@ -75,7 +74,7 @@ export const translations = {
},
tr: {
// Page title
...ApplicationBaseTranslationTr,
...ServiceBaseTranslationTr,
mainTitle: "Servisler",
// Common actions

View File

@@ -6,9 +6,9 @@ import { Card, CardContent } from '@/components/ui/card';
import { TextQueryModifier } from '@/components/common/QueryModifiers/TextQueryModifier';
import { PaginationToolsComponent } from '@/components/common/PaginationModifiers/PaginationToolsComponent';
import { CardDisplay } from '@/components/common/CardDisplay/CardDisplay';
import { ListComponentProps } from './type';
import { ListComponentApplicationProps, ListComponentServiceProps } from './type';
const ListComponent: React.FC<ListComponentProps> = ({
const ListComponentServices: React.FC<ListComponentServiceProps> = ({
lang,
loading,
error,
@@ -16,12 +16,13 @@ const ListComponent: React.FC<ListComponentProps> = ({
pagination,
showFields,
gridCols,
titleField,
handleQueryChange,
updatePagination,
handleCardClick,
handleViewClick,
}) => {
const fieldKey = "service_name";
return (
<>
{/* Search Filters */}
@@ -37,8 +38,82 @@ const ListComponent: React.FC<ListComponentProps> = ({
</div>
{/* Search input */}
<TextQueryModifier
fieldKey="name"
value={pagination.query["name__ilike"] ? pagination.query["name__ilike"].replace(/%/g, "") : ""}
fieldKey={fieldKey}
value={pagination.query[`${fieldKey}__ilike`] ? pagination.query[`${fieldKey}__ilike`].replace(/%/g, "") : ""}
label={translations[lang].search}
onQueryChange={handleQueryChange}
translations={translations}
lang={lang}
/>
</div>
</div>
</CardContent>
</Card>
{/* Pagination Tools Component */}
<Card className="my-4">
<CardContent className="pt-6">
<PaginationToolsComponent
pagination={pagination}
updatePagination={updatePagination}
loading={loading}
lang={lang}
translations={translations}
/>
</CardContent>
</Card>
{/* Card Display Component */}
<div className="mt-6">
<CardDisplay
showFields={showFields}
data={data}
lang={lang}
translations={translations}
error={error}
loading={loading}
titleField={titleField}
onCardClick={handleCardClick}
gridCols={gridCols}
showViewIcon={true}
onViewClick={handleViewClick}
/>
</div>
</>
);
};
const ListComponentEvents: React.FC<ListComponentApplicationProps> = ({
lang,
loading,
error,
data,
pagination,
showFields,
gridCols,
handleQueryChange,
updatePagination,
handleCardClick,
handleViewClick,
}) => {
const fieldKey = "description";
return (
<>
{/* Search Filters */}
<Card>
<CardContent className="pt-6">
<div className="flex flex-col md:flex-row">
{/* Filters on the right */}
<div className={`w-full flex flex-col space-y-4`}>
<div className="font-medium text-sm mb-2 flex justify-between items-center">
<div className="flex items-center">
<Filter className="mr-2 h-4 w-4" />{translations[lang].filterSelection}
</div>
</div>
{/* Search input */}
<TextQueryModifier
fieldKey={fieldKey}
value={pagination.query[`${fieldKey}__ilike`] ? pagination.query[`${fieldKey}__ilike`].replace(/%/g, "") : ""}
label={translations[lang].search}
onQueryChange={handleQueryChange}
translations={translations}
@@ -75,7 +150,6 @@ const ListComponent: React.FC<ListComponentProps> = ({
onCardClick={handleCardClick}
gridCols={gridCols}
showViewIcon={true}
showUpdateIcon={true}
onViewClick={handleViewClick}
/>
</div>
@@ -83,4 +157,7 @@ const ListComponent: React.FC<ListComponentProps> = ({
);
};
export default ListComponent;
export {
ListComponentEvents,
ListComponentServices,
};

View File

@@ -2,8 +2,10 @@
import React, { useState, useEffect } from "react";
import { z } from "zod";
import * as schemaServices from "./schemaList/services";
import * as schema from "./schemaList/schema";
import ListComponent from "./listComponent";
import { ListComponentEvents, ListComponentServices } from "./listComponent";
import { translations } from "./language";
import { PageProps } from "@/validations/translations/translation";
@@ -24,7 +26,7 @@ const AppendersServicePage: React.FC<PageProps> = ({ lang }: { lang: Language })
error: errorServices,
updatePagination: updatePaginationServices,
refetch: refetchServices
} = useApiData<schema.ApplicationData>('/api/services');
} = useApiData<schemaServices.ServiceData>('/api/services');
const {
data: dataEvents,
pagination: paginationEvents,
@@ -43,34 +45,36 @@ const AppendersServicePage: React.FC<PageProps> = ({ lang }: { lang: Language })
} = useApiData<schema.ApplicationData>('/api/appenders');
const [mode, setMode] = useState<FormModeView | FormMode>("list");
const [selectedItemServices, setSelectedItemServices] = useState<schema.ApplicationData | null>(null);
const [selectedItemEvents, setSelectedItemEvents] = useState<schema.ApplicationData | null>(null);
const [selectedItemAppenders, setSelectedItemAppenders] = useState<schema.ApplicationData | null>(null);
const [gridCols, setGridCols] = useState<GridSize>(3);
const [fieldDefinitionsServices, setFieldDefinitionsServices] = useState<schema.FieldDefinitionsType | null>(null);
const [validationSchemaServices, setValidationSchemaServices] = useState<z.ZodSchema | null>(null);
const [selectedItemServices, setSelectedItemServices] = useState<schemaServices.ServiceData | null>(null);
const [selectedItemEvents, setSelectedItemEvents] = useState<schema.ApplicationData | null>(null);
const [selectedItemAppenders, setSelectedItemAppenders] = useState<schema.ApplicationData | null>(null);
const [fieldDefinitionsServices, setFieldDefinitionsServices] = useState<schemaServices.FieldDefinitionsType | null>(null);
const [fieldDefinitionsEvents, setFieldDefinitionsEvents] = useState<schema.FieldDefinitionsType | null>(null);
const [validationSchemaEvents, setValidationSchemaEvents] = useState<z.ZodSchema | null>(null);
const [fieldDefinitionsAppenders, setFieldDefinitionsAppenders] = useState<schema.FieldDefinitionsType | null>(null);
const [validationSchemaServices, setValidationSchemaServices] = useState<z.ZodSchema | null>(null);
const [validationSchemaEvents, setValidationSchemaEvents] = useState<z.ZodSchema | null>(null);
const [validationSchemaAppenders, setValidationSchemaAppenders] = useState<z.ZodSchema | null>(null);
const showFieldsServices = ["service_name", "service_code", "related_responsibility"];
const showFieldsEvents = ["description", "marketing_layer", "cost"];
useEffect(() => {
setFieldDefinitionsServices(schema.viewFieldDefinitions); setValidationSchemaServices(schema.UpdateApplicationSchema);
setFieldDefinitionsEvents(schema.viewFieldDefinitions); setValidationSchemaEvents(schema.UpdateApplicationSchema);
setFieldDefinitionsAppenders(schema.viewFieldDefinitions); setValidationSchemaAppenders(schema.UpdateApplicationSchema);
setFieldDefinitionsServices(schemaServices.viewFieldDefinitions); setValidationSchemaServices(schemaServices.ViewServiceSchema);
setFieldDefinitionsEvents(schema.viewFieldDefinitions); setValidationSchemaEvents(schema.ViewApplicationSchema);
setFieldDefinitionsAppenders(schema.viewFieldDefinitions); setValidationSchemaAppenders(schema.ViewApplicationSchema);
}, [lang]);
const handleQueryChange = (key: string, value: string | null) => {
const newQuery = { ...paginationServices.query };
if (value === null) { delete newQuery[key]; } else if (value.trim() === "") { delete newQuery[key]; } else { newQuery[key] = value; }
updatePaginationServices({ page: 1, query: newQuery });
if (value === null) { delete newQuery[key] } else if (value.trim() === "") { delete newQuery[key] } else { newQuery[key] = value }
updatePaginationServices({ page: 1, query: newQuery })
};
const handleServicesCardClick = (item: schema.ApplicationData) => { console.log("Services Card clicked:", item) };
const handleServicesViewClick = (item: schema.ApplicationData) => { setSelectedItemServices(item); setMode("view"); };
const handleServicesCardClick = (item: schemaServices.ServiceData) => { setSelectedItemServices(item); setMode("list"); };
const handleServicesViewClick = (item: schemaServices.ServiceData) => { setSelectedItemServices(item); setMode("view"); };
const handleEventsCardClick = (item: schema.ApplicationData) => { console.log("Events Card clicked:", item) };
const handleEventsViewClick = (item: schema.ApplicationData) => { setSelectedItemEvents(item); setMode("view"); };
@@ -85,7 +89,7 @@ const AppendersServicePage: React.FC<PageProps> = ({ lang }: { lang: Language })
setSelectedItemAppenders(null);
};
const seriveListProps = {
const serviceListProps = {
lang,
loading: loadingServices,
error: errorServices,
@@ -93,6 +97,7 @@ const AppendersServicePage: React.FC<PageProps> = ({ lang }: { lang: Language })
pagination: paginationServices,
showFields: showFieldsServices,
gridCols: gridCols,
titleField: "service_name",
handleQueryChange: handleQueryChange,
updatePagination: updatePaginationServices,
handleCardClick: handleServicesCardClick,
@@ -106,7 +111,8 @@ const AppendersServicePage: React.FC<PageProps> = ({ lang }: { lang: Language })
data: dataEvents,
pagination: paginationEvents,
showFields: showFieldsEvents,
gridCols: gridCols,
gridCols: 1,
titleField: "description",
handleQueryChange: handleQueryChange,
updatePagination: updatePaginationEvents,
handleCardClick: handleEventsCardClick,
@@ -120,7 +126,8 @@ const AppendersServicePage: React.FC<PageProps> = ({ lang }: { lang: Language })
data: dataAppenders,
pagination: paginationAppenders,
showFields: showFieldsEvents,
gridCols: gridCols,
gridCols: 1,
titleField: "description",
handleQueryChange: handleQueryChange,
updatePagination: updatePaginationAppenders,
handleCardClick: handleAppendersCardClick,
@@ -184,26 +191,25 @@ const AppendersServicePage: React.FC<PageProps> = ({ lang }: { lang: Language })
<h1 className="text-2xl font-bold">{translations[lang].mainTitle}</h1>
<div className="flex space-x-4"><GridSelectionComponent gridCols={gridCols} setGridCols={setGridCols} /></div>
</div>
{mode === "list" ? (
<div className="flex flex-col space-y-4">
{!selectedItemServices ? <div className="w-full h-1/2"><ListComponent {...seriveListProps} /></div> :
{!selectedItemServices ? <div className="w-full h-1/2"><ListComponentServices {...serviceListProps} /></div> :
<div className="w-full h-1/2">
<Button onClick={cancelAllSelections}>{translations[lang].cancel}</Button>
<Card className="my-5">
<CardHeader>{translations[lang].serviceSelectedTitle}</CardHeader>
<CardContent>{selectedItemServices?.name}{" "}{translations[lang].serviceSelectedContent}</CardContent>
<CardContent>{selectedItemServices?.service_name}{" "}{translations[lang].serviceSelectedContent}</CardContent>
</Card>
<div className="flex flex-row space-x-4">
<div className="flex-1"><ListComponent {...eventsListProps} /></div>
<div className="flex-1"><ListComponent {...appendersListProps} /></div>
<div className="flex-1"><ListComponentEvents {...eventsListProps} /></div>
<div className="flex-1"><ListComponentEvents {...appendersListProps} /></div>
</div>
</div>
}
</div>
) : (
<div className="flex flex-col space-y-4">
{selectedItemServices && <FormDisplay<schema.ApplicationData> {...serviceFormProps} />}
{selectedItemServices && <FormDisplay<schemaServices.ServiceData> {...serviceFormProps} />}
{selectedItemEvents && <FormDisplay<schema.ApplicationData> {...eventsFormProps} />}
{selectedItemAppenders && <FormDisplay<schema.ApplicationData> {...appendersFormProps} />}
</div>

View File

@@ -137,9 +137,7 @@ export type CreateApplicationFormData = z.infer<typeof CreateApplicationSchema>;
export type UpdateApplicationFormData = z.infer<typeof UpdateApplicationSchema>;
export type ViewApplicationFormData = z.infer<typeof ViewApplicationSchema>;
// Base field definitions grouped by section
const baseFieldDefinitions = {
// Identification fields
identificationInfo: {
title: "Identification Information",
order: 1,
@@ -173,8 +171,6 @@ const baseFieldDefinitions = {
},
},
},
// Application details
applicationDetails: {
title: "Application Details",
order: 2,
@@ -219,8 +215,6 @@ const baseFieldDefinitions = {
},
},
},
// Status fields
statusInfo: {
title: "Status Information",
order: 3,
@@ -247,8 +241,6 @@ const baseFieldDefinitions = {
},
},
},
// System fields
systemInfo: {
title: "System Information",
order: 4,
@@ -275,10 +267,8 @@ const baseFieldDefinitions = {
},
};
// Create a flat version of the field definitions for compatibility
const flatFieldDefinitions = flattenFieldDefinitions(baseFieldDefinitions);
// Create mode-specific field definitions using the flattened structure
export const createFieldDefinitions = {
name: {
...flatFieldDefinitions.name,
@@ -324,7 +314,6 @@ export const createFieldDefinitions = {
},
};
// Update mode-specific field definitions
export const updateFieldDefinitions = {
uu_id: {
...flatFieldDefinitions.uu_id,
@@ -376,7 +365,6 @@ export const updateFieldDefinitions = {
},
};
// View mode-specific field definitions
export const viewFieldDefinitions = {
uu_id: {
...flatFieldDefinitions.uu_id,
@@ -446,7 +434,6 @@ export const viewFieldDefinitions = {
},
};
// Combined field definitions for all modes
export const fieldDefinitions = {
...baseFieldDefinitions,
getDefinitionsByMode: (mode: "create" | "update" | "view") => {

View File

@@ -0,0 +1,298 @@
import { z } from "zod";
import { flattenFieldDefinitions } from "@/eventRouters/schemas/zodSchemas";
export interface ServiceData {
uu_id: string;
module_uu_id: string;
service_name: string;
service_description?: string;
service_code: string;
related_responsibility?: string;
is_confirmed: boolean;
active: boolean;
deleted?: boolean;
created_at?: string;
updated_at?: string;
}
const errorMessages = {
en: {
moduleUuIdRequired: "Module UUID is required",
serviceNameRequired: "Service name is required",
serviceCodeRequired: "Service code is required",
},
tr: {
moduleUuIdRequired: "Modül UUID'si gereklidir",
serviceNameRequired: "Servis adı gereklidir",
serviceCodeRequired: "Servis kodu gereklidir",
},
};
const getServiceBaseSchema = (lang: "en" | "tr" = "en") =>
z.object({
uu_id: z.string().optional(),
module_uu_id: z.string().min(1, errorMessages[lang].moduleUuIdRequired),
service_name: z.string().min(1, errorMessages[lang].serviceNameRequired),
service_description: z.string().optional(),
service_code: z.string().min(1, errorMessages[lang].serviceCodeRequired),
related_responsibility: z.string().optional(),
is_confirmed: z.boolean().default(false),
active: z.boolean().default(true),
deleted: z.boolean().default(false),
created_at: z.string().optional(),
updated_at: z.string().optional(),
});
const ServiceBaseSchema = getServiceBaseSchema("en");
export const ServiceBaseTranslationTr = {
uu_id: "UUID",
module_uu_id: "Modül UUID'si",
service_name: "Servis Adı",
service_description: "Servis Açıklaması",
service_code: "Servis Kodu",
related_responsibility: "İlgili Sorumluluk",
is_confirmed: "Onaylandı",
active: "Active",
deleted: "Deleted",
created_at: "Created At",
updated_at: "Updated At",
};
export const ServiceBaseTranslationEn = {
uu_id: "UUID",
module_uu_id: "Module UUID",
service_name: "Service Name",
service_description: "Service Description",
service_code: "Service Code",
related_responsibility: "Related Responsibility",
is_confirmed: "Confirmed",
active: "Active",
deleted: "Deleted",
created_at: "Created At",
updated_at: "Updated At",
};
const ViewServiceSchema = ServiceBaseSchema;
const ServiceSchema = ServiceBaseSchema;
export {
ServiceBaseSchema,
ServiceSchema,
ViewServiceSchema,
getServiceBaseSchema,
};
export type ServiceFormData = z.infer<typeof ServiceSchema>;
export type ViewServiceFormData = z.infer<typeof ViewServiceSchema>;
const baseFieldDefinitions = {
identificationInfo: {
title: "Service Information",
order: 1,
fields: {
uu_id: {
type: "text",
label: {
tr: ServiceBaseTranslationTr.uu_id,
en: ServiceBaseTranslationEn.uu_id,
},
readOnly: true,
required: false,
},
module_uu_id: {
type: "text",
label: {
tr: ServiceBaseTranslationTr.module_uu_id,
en: ServiceBaseTranslationEn.module_uu_id,
},
readOnly: false,
required: true,
},
service_name: {
type: "text",
label: {
tr: ServiceBaseTranslationTr.service_name,
en: ServiceBaseTranslationEn.service_name,
},
readOnly: false,
required: true,
},
service_description: {
type: "text",
label: {
tr: ServiceBaseTranslationTr.service_description,
en: ServiceBaseTranslationEn.service_description,
},
readOnly: false,
required: true,
},
service_code: {
type: "text",
label: {
tr: ServiceBaseTranslationTr.service_code,
en: ServiceBaseTranslationEn.service_code,
},
readOnly: false,
required: true,
},
related_responsibility: {
type: "text",
label: {
tr: ServiceBaseTranslationTr.related_responsibility,
en: ServiceBaseTranslationEn.related_responsibility,
},
readOnly: false,
required: false,
},
},
},
statusInfo: {
title: "Status Information",
order: 3,
fields: {
active: {
type: "checkbox",
label: {
tr: ServiceBaseTranslationTr.active,
en: ServiceBaseTranslationEn.active,
},
readOnly: false,
required: false,
defaultValue: true,
},
deleted: {
type: "checkbox",
label: {
tr: ServiceBaseTranslationTr.deleted,
en: ServiceBaseTranslationEn.deleted,
},
readOnly: true,
required: false,
defaultValue: false,
},
is_confirmed: {
type: "checkbox",
label: {
tr: ServiceBaseTranslationTr.is_confirmed,
en: ServiceBaseTranslationEn.is_confirmed,
},
readOnly: false,
required: true,
},
},
},
systemInfo: {
title: "System Information",
order: 4,
fields: {
created_at: {
type: "date",
label: {
tr: ServiceBaseTranslationTr.created_at,
en: ServiceBaseTranslationEn.created_at,
},
readOnly: true,
required: false,
},
updated_at: {
type: "date",
label: {
tr: ServiceBaseTranslationTr.updated_at,
en: ServiceBaseTranslationEn.updated_at,
},
readOnly: true,
required: false,
},
},
},
};
const flatFieldDefinitions = flattenFieldDefinitions(baseFieldDefinitions);
export const viewFieldDefinitions = {
uu_id: {
...flatFieldDefinitions.uu_id,
readOnly: true,
required: false,
defaultValue: 0,
},
module_uu_id: {
...flatFieldDefinitions.module_uu_id,
readOnly: true,
required: false,
defaultValue: "",
},
service_name: {
...flatFieldDefinitions.service_name,
readOnly: true,
required: false,
defaultValue: "",
},
service_description: {
...flatFieldDefinitions.service_description,
readOnly: true,
required: false,
defaultValue: "",
},
service_code: {
...flatFieldDefinitions.service_code,
readOnly: true,
required: false,
defaultValue: "",
},
related_responsibility: {
...flatFieldDefinitions.related_responsibility,
readOnly: true,
required: false,
defaultValue: "",
},
active: {
...flatFieldDefinitions.active,
readOnly: true,
required: false,
defaultValue: true,
},
is_confirmed: {
...flatFieldDefinitions.is_confirmed,
readOnly: true,
required: false,
defaultValue: true,
},
deleted: {
...flatFieldDefinitions.deleted,
readOnly: true,
required: false,
defaultValue: false,
},
created_at: {
...flatFieldDefinitions.created_at,
readOnly: true,
required: false,
defaultValue: "",
},
updated_at: {
...flatFieldDefinitions.updated_at,
readOnly: true,
required: false,
defaultValue: "",
},
};
export const fieldDefinitions = {
...baseFieldDefinitions,
getDefinitionsByMode: (mode: "view") => {
switch (mode) {
case "view":
return viewFieldDefinitions;
default:
return baseFieldDefinitions;
}
},
};
export const fieldsByMode = {
view: Object.keys(viewFieldDefinitions),
};
export type FieldDefinitionsType = typeof viewFieldDefinitions;

View File

@@ -1,17 +1,34 @@
import { Language } from "@/components/common/schemas";
import { GridSize } from "@/components/common/HeaderSelections/GridSelectionComponent";
import * as schema from "./schemaList/schema";
import * as schemaServices from "./schemaList/services";
export interface ListComponentProps {
export interface ListComponentApplicationProps {
lang: Language;
loading: boolean;
error: any;
data: schema.ApplicationData[];
pagination: any;
showFields: string[];
gridCols: GridSize;
gridCols: GridSize | number;
titleField: string;
handleQueryChange: (key: string, value: string | null) => void;
updatePagination: (pagination: any) => void;
handleCardClick: (item: schema.ApplicationData) => void;
handleViewClick: (item: schema.ApplicationData) => void;
}
export interface ListComponentServiceProps {
lang: Language;
loading: boolean;
error: any;
data: schemaServices.ServiceData[];
pagination: any;
showFields: string[];
gridCols: GridSize | number;
titleField: string;
handleQueryChange: (key: string, value: string | null) => void;
updatePagination: (pagination: any) => void;
handleCardClick: (item: schemaServices.ServiceData) => void;
handleViewClick: (item: schemaServices.ServiceData) => void;
}

View File

@@ -15,7 +15,6 @@ export interface ApplicationData {
updated_at?: string;
}
// Validation error messages by language
const errorMessages = {
en: {
nameRequired: "Name is required",
@@ -31,7 +30,6 @@ const errorMessages = {
},
};
// Function to get schema with language-specific validation messages
const getApplicationBaseSchema = (lang: "en" | "tr" = "en") =>
z.object({
// Identification fields
@@ -58,7 +56,6 @@ const getApplicationBaseSchema = (lang: "en" | "tr" = "en") =>
updated_at: z.string().optional(),
});
// For backward compatibility
const ApplicationBaseSchema = getApplicationBaseSchema("en");
export const ApplicationBaseTranslationTr = {
@@ -89,7 +86,6 @@ export const ApplicationBaseTranslationEn = {
updated_at: "Updated At",
};
// Create schema for creating new applications with language support
const getCreateApplicationSchema = (lang: "en" | "tr" = "en") =>
getApplicationBaseSchema(lang).omit({
uu_id: true,
@@ -98,7 +94,6 @@ const getCreateApplicationSchema = (lang: "en" | "tr" = "en") =>
deleted: true,
});
// Update schema for updating existing applications with language support
const getUpdateApplicationSchema = (lang: "en" | "tr" = "en") =>
getApplicationBaseSchema(lang)
.omit({
@@ -110,17 +105,11 @@ const getUpdateApplicationSchema = (lang: "en" | "tr" = "en") =>
uu_id: true,
});
// For backward compatibility
const CreateApplicationSchema = getCreateApplicationSchema("en");
const UpdateApplicationSchema = getUpdateApplicationSchema("en");
// Schema for viewing an application (all fields)
const ViewApplicationSchema = ApplicationBaseSchema;
// Default schema (used for validation)
const ApplicationSchema = ApplicationBaseSchema;
// Export all schemas and schema generators
export {
ApplicationBaseSchema,
ApplicationSchema,
@@ -137,7 +126,6 @@ export type CreateApplicationFormData = z.infer<typeof CreateApplicationSchema>;
export type UpdateApplicationFormData = z.infer<typeof UpdateApplicationSchema>;
export type ViewApplicationFormData = z.infer<typeof ViewApplicationSchema>;
// Base field definitions grouped by section
const baseFieldDefinitions = {
// Identification fields
identificationInfo: {
@@ -274,11 +262,8 @@ const baseFieldDefinitions = {
},
},
};
// Create a flat version of the field definitions for compatibility
const flatFieldDefinitions = flattenFieldDefinitions(baseFieldDefinitions);
// Create mode-specific field definitions using the flattened structure
export const createFieldDefinitions = {
name: {
...flatFieldDefinitions.name,
@@ -323,8 +308,6 @@ export const createFieldDefinitions = {
defaultValue: true,
},
};
// Update mode-specific field definitions
export const updateFieldDefinitions = {
uu_id: {
...flatFieldDefinitions.uu_id,
@@ -375,8 +358,6 @@ export const updateFieldDefinitions = {
defaultValue: true,
},
};
// View mode-specific field definitions
export const viewFieldDefinitions = {
uu_id: {
...flatFieldDefinitions.uu_id,
@@ -445,8 +426,6 @@ export const viewFieldDefinitions = {
defaultValue: "",
},
};
// Combined field definitions for all modes
export const fieldDefinitions = {
...baseFieldDefinitions,
getDefinitionsByMode: (mode: "create" | "update" | "view") => {
@@ -462,8 +441,6 @@ export const fieldDefinitions = {
}
},
};
// Fields to show based on mode - dynamically generated from field definitions
export const fieldsByMode = {
create: Object.keys(createFieldDefinitions),
update: Object.keys(updateFieldDefinitions),

View File

@@ -1,4 +1,3 @@
// Define field definition type
interface FieldDefinition {
type: string;
group: string;
@@ -9,7 +8,6 @@ interface FieldDefinition {
defaultValue?: any;
}
// Helper function to flatten grouped field definitions into a flat structure
const flattenFieldDefinitions = (
groupedDefs: any
): Record<string, FieldDefinition> => {
@@ -27,7 +25,6 @@ const flattenFieldDefinitions = (
);
}
);
return result;
};