updated app reachable codes
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
"use server";
|
||||
import React from "react";
|
||||
import { Home, User, Settings, Mail, Calendar } from "lucide-react";
|
||||
import { transformMenu, LanguageTranslation } from "@/components/menu/runner";
|
||||
import Link from "next/link";
|
||||
|
||||
async function LeftMenu({
|
||||
searchParams,
|
||||
pageUuidList,
|
||||
lang,
|
||||
}: {
|
||||
pageUuidList: string[];
|
||||
lang: keyof LanguageTranslation;
|
||||
searchParams: { [key: string]: string | string[] | undefined };
|
||||
}) {
|
||||
const transformedMenu = transformMenu(pageUuidList);
|
||||
|
||||
// Get the menuContext from searchParams without setting a default value
|
||||
const menuContext = searchParams?.menu;
|
||||
|
||||
// Only parse the indices if menuContext exists
|
||||
let firstLayerIndex = -1;
|
||||
let secondLayerIndex = -1;
|
||||
|
||||
if (menuContext) {
|
||||
const indices = menuContext.toString().split("*").map(Number);
|
||||
firstLayerIndex = indices[0] || 0;
|
||||
secondLayerIndex = indices[1] || 0;
|
||||
}
|
||||
|
||||
const pageSelected = searchParams?.page;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<nav className="flex flex-col space-y-2">
|
||||
<div className="text-xl font-bold mb-6 text-center">Dashboard</div>
|
||||
{transformedMenu.map((item, firstIndex) => (
|
||||
<div key={item.name} className="mb-4">
|
||||
<Link
|
||||
href={`/dashboard?${
|
||||
pageSelected ? `page=${pageSelected}` : ""
|
||||
}&menu=${firstIndex}*0`}
|
||||
className={`text-xl font-semibold pl-5 my-2 py-2 block ${
|
||||
firstIndex === firstLayerIndex
|
||||
? "text-emerald-600"
|
||||
: "text-emerald-400"
|
||||
} hover:text-emerald-600`}
|
||||
>
|
||||
{item.lg[lang]}
|
||||
</Link>
|
||||
|
||||
{/* Only render the second layer if menuContext exists and this first layer item is selected */}
|
||||
{menuContext && firstIndex === firstLayerIndex && (
|
||||
<ul className="space-y-2">
|
||||
{item.subList.map((subItem, secondIndex) => (
|
||||
<div key={subItem.name}>
|
||||
<Link
|
||||
href={`/dashboard?${
|
||||
pageSelected ? `page=${pageSelected}` : ""
|
||||
}&menu=${firstIndex}*${secondIndex}`}
|
||||
className={`ml-5 my-4 pl-4 text-xl font-semibold block ${
|
||||
secondIndex === secondLayerIndex
|
||||
? "text-emerald-700"
|
||||
: "text-emerald-500"
|
||||
} hover:text-emerald-700`}
|
||||
>
|
||||
{subItem.lg[lang]}
|
||||
</Link>
|
||||
{/* Only render the third layer if this second layer item is selected */}
|
||||
{firstIndex === firstLayerIndex &&
|
||||
secondIndex === secondLayerIndex && (
|
||||
<div className="ml-5">
|
||||
{subItem.subList.map((subSubItem) => (
|
||||
<Link
|
||||
key={subSubItem.appUUID}
|
||||
href={`/dashboard?page=${subSubItem.appUUID}&menu=${firstIndex}*${secondIndex}`}
|
||||
className={`flex flex-row text-xl py-4 my-4 w-full space-x-2 p-2 rounded ${
|
||||
pageSelected === subSubItem.appUUID
|
||||
? " bg-gray-100 cursor-not-allowed"
|
||||
: "hover:bg-gray-200"
|
||||
}`}
|
||||
>
|
||||
<span className="text-gray-400">
|
||||
<Home />
|
||||
</span>
|
||||
<span className="ml-5 text-gray-700">
|
||||
{subSubItem.lg[lang]}
|
||||
</span>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default LeftMenu;
|
||||
@@ -0,0 +1,32 @@
|
||||
import React from "react";
|
||||
import retrievePage from "@/components/NavigatePages";
|
||||
|
||||
function MainPage({
|
||||
pageSelected,
|
||||
lang,
|
||||
}: {
|
||||
pageSelected: string | undefined;
|
||||
lang: string;
|
||||
}) {
|
||||
const ComponentPage = retrievePage({
|
||||
pageId: pageSelected ?? "",
|
||||
});
|
||||
|
||||
if (!ComponentPage) {
|
||||
return (
|
||||
<div className="flex flex-col w-full">
|
||||
<h2 className="text-2xl font-semibold p-4">No Page Selected</h2>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{/* Main Content */}
|
||||
<main className="flex-grow p-6 bg-gray-50 overflow-y-auto">
|
||||
<ComponentPage lang={lang} />
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default MainPage;
|
||||
@@ -2,13 +2,56 @@ import React from "react";
|
||||
import { checkAccessTokenIsValid } from "@/apicalls/cookies/token";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
async function DashboardPage() {
|
||||
const token_is_valid = await checkAccessTokenIsValid();
|
||||
import LeftMenu from "./leftMenu";
|
||||
import MainPage from "./main";
|
||||
|
||||
export default async function DashboardLayout({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: { [key: string]: string | undefined };
|
||||
}) {
|
||||
const token_is_valid = await checkAccessTokenIsValid();
|
||||
if (!token_is_valid) {
|
||||
redirect("/auth/login");
|
||||
}
|
||||
return <div>You have arrived to Dashboard Page</div>;
|
||||
}
|
||||
const pageUuidList = [
|
||||
"6015129b-f665-479c-a440-04fb82ea6114",
|
||||
"14a98ae7-c64e-403d-9b53-32e7ea867ab4",
|
||||
"e368137d-d548-4ed4-90da-337bcc5d1559",
|
||||
"d3d97973-41c6-4bad-881b-6bf77d837fa5",
|
||||
]; // Mock data of pageUUID list []
|
||||
const lang = "tr"; // Assuming you have a way to determine the current language
|
||||
const queryParams = await searchParams;
|
||||
const pageSelected = queryParams?.page || undefined;
|
||||
|
||||
export default DashboardPage;
|
||||
return (
|
||||
<div className="flex h-screen overflow-hidden">
|
||||
{/* Sidebar */}
|
||||
<aside className="w-1/4 border-r p-4 overflow-y-auto">
|
||||
<LeftMenu
|
||||
pageUuidList={pageUuidList}
|
||||
lang={lang}
|
||||
searchParams={queryParams}
|
||||
/>
|
||||
</aside>
|
||||
|
||||
{/* Main Content Area */}
|
||||
|
||||
<div className="flex flex-col w-3/4">
|
||||
{/* Sticky Header */}
|
||||
<header className="sticky top-0 bg-white shadow-md z-10 p-4 flex justify-between items-center">
|
||||
<h1 className="text-2xl font-semibold">Dashboard</h1>
|
||||
<div className="flex items-center space-x-4">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search..."
|
||||
className="border px-3 py-2 rounded-lg"
|
||||
/>
|
||||
<div className="w-10 h-10 bg-gray-300 rounded-full"></div>
|
||||
</div>
|
||||
</header>
|
||||
<MainPage pageSelected={pageSelected} lang={lang} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { PageProps } from "./interFaces";
|
||||
import Page0001 from "./page0001";
|
||||
|
||||
const PageIndexs = {
|
||||
"6015129b-f665-479c-a440-04fb82ea6114": Page0001,
|
||||
};
|
||||
|
||||
function UnAuthorizedPage({ lang }: PageProps) {
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col h-screen">
|
||||
<header className="bg-gray-800 text-white p-4 text-center">
|
||||
<h1 className="text-2xl font-bold">Unauthorized Access</h1>
|
||||
</header>
|
||||
<main className="flex-grow p-4 bg-gray-100">
|
||||
<p className="text-gray-700">
|
||||
You do not have permission to access this page.
|
||||
</p>
|
||||
<p className="text-gray-700">Please contact the administrator.</p>
|
||||
</main>
|
||||
<footer className="bg-gray-800 text-white p-4 text-center">
|
||||
<p>© 2023 My Application</p>
|
||||
</footer>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function retrievePage({
|
||||
pageId,
|
||||
}: {
|
||||
pageId: string;
|
||||
}): React.ComponentType<PageProps> {
|
||||
const PageComponent = PageIndexs[pageId as keyof typeof PageIndexs];
|
||||
if (!PageComponent) {
|
||||
return UnAuthorizedPage;
|
||||
}
|
||||
return PageComponent;
|
||||
}
|
||||
|
||||
export default retrievePage;
|
||||
@@ -0,0 +1,3 @@
|
||||
export interface PageProps {
|
||||
lang: string;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import React from "react";
|
||||
import { PageProps } from "./interFaces";
|
||||
|
||||
const pageContext = {
|
||||
tr: {
|
||||
pageTitle: "Sayfa 0001",
|
||||
pageDescription: "Bu, Sayfa 0001'in içeriğidir.",
|
||||
},
|
||||
en: {
|
||||
pageTitle: "Page 0001",
|
||||
pageDescription: "This is the content of Page 0001.",
|
||||
},
|
||||
};
|
||||
|
||||
function Page0001({ lang }: PageProps) {
|
||||
const { pageTitle, pageDescription } =
|
||||
pageContext[lang as keyof typeof pageContext];
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col h-screen">
|
||||
<header className="bg-gray-800 text-white p-4 text-center">
|
||||
<h1 className="text-2xl font-bold">{pageTitle}</h1>
|
||||
</header>
|
||||
<main className="flex-grow p-4 bg-gray-100">
|
||||
<p className="text-gray-700">{pageDescription}</p>
|
||||
</main>
|
||||
<footer className="bg-gray-800 text-white p-4 text-center">
|
||||
<p>© 2023 My Application</p>
|
||||
</footer>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page0001;
|
||||
125
WebServices/client-frontend/src/components/menu/runner.tsx
Normal file
125
WebServices/client-frontend/src/components/menu/runner.tsx
Normal file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Filters the menu structure based on intersections with provided UUIDs
|
||||
* @param {string[]} uuids - Array of UUIDs to check for intersection
|
||||
* @param {Array} menu - The original menu structure
|
||||
* @returns {Array} - Filtered menu structure with only matching items
|
||||
*/
|
||||
import Menu from "@/menu/store"; // Assuming you have a menu structure imported
|
||||
|
||||
// Define TypeScript interfaces for menu structure
|
||||
interface LanguageTranslation {
|
||||
tr: string;
|
||||
en: string;
|
||||
}
|
||||
|
||||
interface MenuThirdLevel {
|
||||
name: string;
|
||||
lg: LanguageTranslation;
|
||||
appList: string[];
|
||||
}
|
||||
|
||||
interface MenuSecondLevel {
|
||||
name: string;
|
||||
lg: LanguageTranslation;
|
||||
subList: MenuThirdLevel[];
|
||||
}
|
||||
|
||||
interface MenuFirstLevel {
|
||||
name: string;
|
||||
lg: LanguageTranslation;
|
||||
subList: MenuSecondLevel[];
|
||||
}
|
||||
|
||||
// Define interfaces for the filtered menu structure
|
||||
interface FilteredMenuThirdLevel {
|
||||
name: string;
|
||||
lg: LanguageTranslation;
|
||||
appUUID: string;
|
||||
}
|
||||
|
||||
interface FilteredMenuSecondLevel {
|
||||
name: string;
|
||||
lg: LanguageTranslation;
|
||||
subList: FilteredMenuThirdLevel[];
|
||||
}
|
||||
|
||||
interface FilteredMenuFirstLevel {
|
||||
name: string;
|
||||
lg: LanguageTranslation;
|
||||
subList: FilteredMenuSecondLevel[];
|
||||
}
|
||||
|
||||
export type { LanguageTranslation };
|
||||
|
||||
function transformMenu(uuids: string[]) {
|
||||
// Helper function to check if arrays have at least one common element
|
||||
const hasIntersection = (array1: string[], array2: string[]): boolean => {
|
||||
return array1.some((item) => array2.includes(item));
|
||||
};
|
||||
|
||||
// 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 appList has an intersection with our UUIDs
|
||||
if (
|
||||
thirdLevel.appList &&
|
||||
hasIntersection(thirdLevel.appList, uuids)
|
||||
) {
|
||||
// Find the first matching UUID
|
||||
const matchedUUID = thirdLevel.appList.find((uuid) =>
|
||||
uuids.includes(uuid)
|
||||
);
|
||||
|
||||
// Only proceed if we found a matching UUID (should always be true due to hasIntersection)
|
||||
if (matchedUUID) {
|
||||
// Create a modified third level item with the matched UUID
|
||||
const newThirdLevel: FilteredMenuThirdLevel = {
|
||||
name: thirdLevel.name,
|
||||
lg: { ...thirdLevel.lg },
|
||||
appUUID: matchedUUID,
|
||||
};
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
export { transformMenu };
|
||||
180
WebServices/client-frontend/src/components/menu/store.tsx
Normal file
180
WebServices/client-frontend/src/components/menu/store.tsx
Normal file
@@ -0,0 +1,180 @@
|
||||
const Individual = {
|
||||
name: "Individual",
|
||||
lg: {
|
||||
tr: "Birey",
|
||||
en: "Individual",
|
||||
},
|
||||
appList: [
|
||||
"0362071d-90d9-48db-8fa0-3528aaf450bd",
|
||||
"6015129b-f665-479c-a440-04fb82ea6114",
|
||||
],
|
||||
};
|
||||
|
||||
const User = {
|
||||
name: "User",
|
||||
lg: {
|
||||
tr: "Kullanıcı",
|
||||
en: "User",
|
||||
},
|
||||
appList: ["14a98ae7-c64e-403d-9b53-32e7ea867ab4"],
|
||||
};
|
||||
|
||||
const Build = {
|
||||
name: "Build",
|
||||
lg: {
|
||||
tr: "Apartman",
|
||||
en: "Build",
|
||||
},
|
||||
appList: ["e368137d-d548-4ed4-90da-337bcc5d1559"],
|
||||
};
|
||||
|
||||
const BuildParts = {
|
||||
name: "BuildParts",
|
||||
lg: {
|
||||
tr: "Daire",
|
||||
en: "BuildParts",
|
||||
},
|
||||
appList: [],
|
||||
};
|
||||
|
||||
const BuildArea = {
|
||||
name: "BuildArea",
|
||||
lg: {
|
||||
tr: "Daire",
|
||||
en: "BuildArea",
|
||||
},
|
||||
appList: [],
|
||||
};
|
||||
|
||||
const ManagementAccounting = {
|
||||
name: "ManagementAccounting",
|
||||
lg: {
|
||||
tr: "Yönetim Cari Hareketler",
|
||||
en: "ManagementAccounting",
|
||||
},
|
||||
appList: [],
|
||||
};
|
||||
|
||||
const ManagementBudget = {
|
||||
name: "ManagementBudget",
|
||||
lg: {
|
||||
tr: "Yönetim Bütçe İşlemleri",
|
||||
en: "Management Budget",
|
||||
},
|
||||
appList: [],
|
||||
};
|
||||
|
||||
const BuildPartsAccounting = {
|
||||
name: "BuildPartsAccounting",
|
||||
lg: {
|
||||
tr: "Daire Cari Hareketler",
|
||||
en: "Build Parts Accounting",
|
||||
},
|
||||
appList: [],
|
||||
};
|
||||
|
||||
const AnnualMeeting = {
|
||||
name: "AnnualMeeting",
|
||||
lg: {
|
||||
tr: "Yıllık Olağan Toplantı Tanımlama ve Davet",
|
||||
en: "Annual Meetings and Invitations",
|
||||
},
|
||||
appList: ["d3d97973-41c6-4bad-881b-6bf77d837fa5"],
|
||||
};
|
||||
|
||||
const AnnualMeetingClose = {
|
||||
name: "AnnualMeetingClose",
|
||||
lg: {
|
||||
tr: "Yıllık Olağan Toplantı kapatma ve Cari Yaratma",
|
||||
en: "Annual Meeting Close and Accountings",
|
||||
},
|
||||
appList: [],
|
||||
};
|
||||
|
||||
const EmergencyMeeting = {
|
||||
name: "EmergencyMeeting",
|
||||
lg: {
|
||||
tr: "Acil Toplantı Tanımlama ve Davet",
|
||||
en: "Emergency Meeting and Invitations",
|
||||
},
|
||||
appList: [],
|
||||
};
|
||||
|
||||
const EmergencyMeetingClose = {
|
||||
name: "EmergencyMeetingClose",
|
||||
lg: {
|
||||
tr: "Acil Olağan Toplantı kapatma ve Cari Yaratma",
|
||||
en: "Emergency Meeting Close and Accountings",
|
||||
},
|
||||
appList: [],
|
||||
};
|
||||
|
||||
const MeetingParticipations = {
|
||||
name: "MeetingParticipations",
|
||||
lg: {
|
||||
tr: "Toplantı Katılım İşlemleri",
|
||||
en: "Meeting Participations",
|
||||
},
|
||||
appList: ["SomeUUID"],
|
||||
};
|
||||
|
||||
const Menu = [
|
||||
{
|
||||
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;
|
||||
Reference in New Issue
Block a user