diff --git a/frontend/src/config.ts b/frontend/src/config.ts
index a9783c8..2eb0fb4 100644
--- a/frontend/src/config.ts
+++ b/frontend/src/config.ts
@@ -8,8 +8,8 @@ export const localStorageStyleKey = 'style'
export const containerMaxW = 'xl:max-w-full xl:mx-auto 2xl:mx-20'
-export const appTitle = 'created by Flatlogic generator!'
+export const appTitle = 'L\'Escale Marocaine'
export const getPageTitle = (currentPageTitle: string) => `${currentPageTitle} — ${appTitle}`
-export const tinyKey = process.env.NEXT_PUBLIC_TINY_KEY || ''
+export const tinyKey = process.env.NEXT_PUBLIC_TINY_KEY || ''
\ No newline at end of file
diff --git a/frontend/src/pages/dashboard.tsx b/frontend/src/pages/dashboard.tsx
index f659d63..ec77b0a 100644
--- a/frontend/src/pages/dashboard.tsx
+++ b/frontend/src/pages/dashboard.tsx
@@ -7,7 +7,7 @@ import LayoutAuthenticated from '../layouts/Authenticated'
import SectionMain from '../components/SectionMain'
import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton'
import BaseIcon from "../components/BaseIcon";
-import { getPageTitle } from '../config'
+import { getPageTitle, appTitle } from '../config'
import Link from "next/link";
import { hasPermission } from "../helpers/userPermissions";
@@ -16,15 +16,15 @@ import { WidgetCreator } from '../components/WidgetCreator/WidgetCreator';
import { SmartWidget } from '../components/SmartWidget/SmartWidget';
import { useAppDispatch, useAppSelector } from '../stores/hooks';
+
const Dashboard = () => {
const dispatch = useAppDispatch();
const iconsColor = useAppSelector((state) => state.style.iconsColor);
const corners = useAppSelector((state) => state.style.corners);
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
- const loadingMessage = 'Loading...';
+ const loadingMessage = '...';
-
const [users, setUsers] = React.useState(loadingMessage);
const [roles, setRoles] = React.useState(loadingMessage);
const [permissions, setPermissions] = React.useState(loadingMessage);
@@ -39,29 +39,24 @@ const Dashboard = () => {
const [suppliers, setSuppliers] = React.useState(loadingMessage);
const [ingredients, setIngredients] = React.useState(loadingMessage);
-
const [widgetsRole, setWidgetsRole] = React.useState({
role: { value: '', label: '' },
});
const { currentUser } = useAppSelector((state) => state.auth);
const { isFetchingQuery } = useAppSelector((state) => state.openAi);
-
const { rolesWidgets, loading } = useAppSelector((state) => state.roles);
-
-
+
async function loadData() {
- const entities = ['users','roles','permissions','restaurants','categories','dishes','menus','orders','tables','reservations','reviews','suppliers','ingredients',];
- const fns = [setUsers,setRoles,setPermissions,setRestaurants,setCategories,setDishes,setMenus,setOrders,setTables,setReservations,setReviews,setSuppliers,setIngredients,];
+ const entities = ['users','roles','permissions','restaurants','categories','dishes','menus','orders','tables','reservations','reviews','suppliers','ingredients'];
+ const fns = [setUsers,setRoles,setPermissions,setRestaurants,setCategories,setDishes,setMenus,setOrders,setTables,setReservations,setReviews,setSuppliers,setIngredients];
const requests = entities.map((entity, index) => {
-
if(hasPermission(currentUser, `READ_${entity.toUpperCase()}`)) {
return axios.get(`/${entity.toLowerCase()}/count`);
} else {
fns[index](null);
return Promise.resolve({data: {count: null}});
}
-
});
Promise.allSettled(requests).then((results) => {
@@ -74,10 +69,11 @@ const Dashboard = () => {
});
});
}
-
- async function getWidgets(roleId) {
+
+ async function getWidgets(roleId: string) {
await dispatch(fetchWidgets(roleId));
}
+
React.useEffect(() => {
if (!currentUser) return;
loadData().then();
@@ -88,439 +84,138 @@ const Dashboard = () => {
if (!currentUser || !widgetsRole?.role?.value) return;
getWidgets(widgetsRole?.role?.value || '').then();
}, [widgetsRole?.role?.value]);
-
- return (
- <>
-
-
- {getPageTitle('Overview')}
-
-
-
-
- {''}
-
-
- {hasPermission(currentUser, 'CREATE_ROLES') && }
- {!!rolesWidgets.length &&
- hasPermission(currentUser, 'CREATE_ROLES') && (
-
- {`${widgetsRole?.role?.label || 'Users'}'s widgets`}
-
- )}
-
- {(isFetchingQuery || loading) && (
-
-
{' '}
- Loading widgets...
+ return (
+ <>
+
+
{getPageTitle('Dashboard')}
+
+
+
+ {''}
+
+
+
+
+ Welcome back, {currentUser?.firstName || 'Manager'}!
+
+
+ Here is what's happening at L'Escale Marocaine today.
+
- )}
- { rolesWidgets &&
- rolesWidgets.map((widget) => (
-
- ))}
-
+ )}
- {!!rolesWidgets.length &&
}
-
-
-
-
- {hasPermission(currentUser, 'READ_USERS') &&
-
-
-
-
- Users
-
-
- {users}
-
-
-
+
+ {(isFetchingQuery || loading) && (
+
+ Loading metrics...
-
+ )}
+
+ {rolesWidgets && rolesWidgets.map((widget) => (
+
+ ))}
- }
-
- {hasPermission(currentUser, 'READ_ROLES') &&
-
-
-
-
- Roles
+
+
+ {hasPermission(currentUser, 'READ_RESERVATIONS') && (
+
+
+
+
+
Reservations
+
{reservations}
+
+
+
-
- {roles}
+
+ )}
+
+ {hasPermission(currentUser, 'READ_ORDERS') && (
+
+
+
+
+
Active Orders
+
{orders}
+
+
+
-
-
-
-
-
+
+ )}
+
+ {hasPermission(currentUser, 'READ_DISHES') && (
+
+
+
+
+
Menu Items
+
{dishes}
+
+
+
+
+
+ )}
- }
-
- {hasPermission(currentUser, 'READ_PERMISSIONS') &&
-
-
-
-
- Permissions
-
-
- {permissions}
-
-
-
-
-
-
+
+
+ {/* Secondary Metrics */}
+ {[
+ { label: 'Restaurants', val: restaurants, path: '/restaurants/restaurants-list', icon: icon.mdiStorefront, color: 'text-blue-500', perm: 'READ_RESTAURANTS' },
+ { label: 'Categories', val: categories, path: '/categories/categories-list', icon: icon.mdiShape, color: 'text-purple-500', perm: 'READ_CATEGORIES' },
+ { label: 'Tables', val: tables, path: '/tables/tables-list', icon: icon.mdiTableLarge, color: 'text-yellow-600', perm: 'READ_TABLES' },
+ { label: 'Reviews', val: reviews, path: '/reviews/reviews-list', icon: icon.mdiStar, color: 'text-red-400', perm: 'READ_REVIEWS' },
+ ].map((item, idx) => (
+ hasPermission(currentUser, item.perm) && (
+
+
+
+
+
+
{item.label}
+
{item.val}
+
+
+
+
+ )
+ ))}
- }
-
- {hasPermission(currentUser, 'READ_RESTAURANTS') &&
-
-
-
-
- Restaurants
-
-
- {restaurants}
-
-
-
-
-
-
-
- }
-
- {hasPermission(currentUser, 'READ_CATEGORIES') &&
-
-
-
-
- Categories
-
-
- {categories}
-
-
-
-
-
-
-
- }
-
- {hasPermission(currentUser, 'READ_DISHES') &&
-
-
-
-
- Dishes
-
-
- {dishes}
-
-
-
-
-
-
-
- }
-
- {hasPermission(currentUser, 'READ_MENUS') &&
-
-
-
-
- Menus
-
-
- {menus}
-
-
-
-
-
-
-
- }
-
- {hasPermission(currentUser, 'READ_ORDERS') &&
-
-
-
-
- Orders
-
-
- {orders}
-
-
-
-
-
-
-
- }
-
- {hasPermission(currentUser, 'READ_TABLES') &&
-
-
-
-
- Tables
-
-
- {tables}
-
-
-
-
-
-
-
- }
-
- {hasPermission(currentUser, 'READ_RESERVATIONS') &&
-
-
-
-
- Reservations
-
-
- {reservations}
-
-
-
-
-
-
-
- }
-
- {hasPermission(currentUser, 'READ_REVIEWS') &&
-
-
-
-
- Reviews
-
-
- {reviews}
-
-
-
-
-
-
-
- }
-
- {hasPermission(currentUser, 'READ_SUPPLIERS') &&
-
-
-
-
- Suppliers
-
-
- {suppliers}
-
-
-
-
-
-
-
- }
-
- {hasPermission(currentUser, 'READ_INGREDIENTS') &&
-
-
-
-
- Ingredients
-
-
- {ingredients}
-
-
-
-
-
-
-
- }
-
-
-
-
- >
- )
+
+ >
+ )
}
Dashboard.getLayout = function getLayout(page: ReactElement) {
- return
{page}
+ return
{page}
}
-export default Dashboard
+export default Dashboard
\ No newline at end of file
diff --git a/frontend/src/pages/index.tsx b/frontend/src/pages/index.tsx
index 275458d..087e293 100644
--- a/frontend/src/pages/index.tsx
+++ b/frontend/src/pages/index.tsx
@@ -1,166 +1,132 @@
-
import React, { useEffect, useState } from 'react';
import type { ReactElement } from 'react';
import Head from 'next/head';
import Link from 'next/link';
import BaseButton from '../components/BaseButton';
-import CardBox from '../components/CardBox';
import SectionFullScreen from '../components/SectionFullScreen';
import LayoutGuest from '../layouts/Guest';
-import BaseDivider from '../components/BaseDivider';
-import BaseButtons from '../components/BaseButtons';
-import { getPageTitle } from '../config';
-import { useAppSelector } from '../stores/hooks';
-import CardBoxComponentTitle from "../components/CardBoxComponentTitle";
-import { getPexelsImage, getPexelsVideo } from '../helpers/pexels';
+import { getPageTitle, appTitle } from '../config';
+import { getPexelsImage } from '../helpers/pexels';
+import { mdiFood, mdiSilverwareVariant, mdiTimelineClockOutline } from '@mdi/js';
+import BaseIcon from '../components/BaseIcon';
+export default function LandingPage() {
+ const [heroImage, setHeroImage] = useState(null)
-export default function Starter() {
- const [illustrationImage, setIllustrationImage] = useState({
- src: undefined,
- photographer: undefined,
- photographer_url: undefined,
- })
- const [illustrationVideo, setIllustrationVideo] = useState({video_files: []})
- const [contentType, setContentType] = useState('image');
- const [contentPosition, setContentPosition] = useState('left');
- const textColor = useAppSelector((state) => state.style.linkColor);
-
- const title = 'AI App Draft'
-
- // Fetch Pexels image/video
useEffect(() => {
async function fetchData() {
- const image = await getPexelsImage();
- const video = await getPexelsVideo();
- setIllustrationImage(image);
- setIllustrationVideo(video);
+ // We search for Moroccan food specifically to match the theme
+ const image = await getPexelsImage('Moroccan Food');
+ setHeroImage(image);
}
fetchData();
}, []);
- const imageBlock = (image) => (
-
-
-
- Photo by {image?.photographer} on Pexels
-
+ const features = [
+ {
+ title: 'Authentic Flavors',
+ description: 'Experience the rich heritage of Moroccan spices and traditional cooking techniques.',
+ icon: mdiFood,
+ },
+ {
+ title: 'Elegant Dining',
+ description: 'A refined atmosphere inspired by the beautiful Riads of Marrakech.',
+ icon: mdiSilverwareVariant,
+ },
+ {
+ title: 'Easy Reservations',
+ description: 'Book your table in seconds and manage your dining experience online.',
+ icon: mdiTimelineClockOutline,
+ }
+ ]
+
+ return (
+
+
+
{getPageTitle('Authentic Moroccan Cuisine')}
+
+
+ {/* Hero Section */}
+
+
+ {/* Background Overlay */}
+
+
+ {/* Content */}
+
+
+ {appTitle}
+
+
+ A journey through the vibrant colors and exquisite tastes of Morocco.
+
+
+
+
+ Admin Portal
+
+
+
+
+
+
+ {/* Features / Story */}
+
+
+
+
Tradition in Every Bite
+
+
+
+
+ {features.map((feature, index) => (
+
+
+
+
+
{feature.title}
+
+ {feature.description}
+
+
+ ))}
+
+
+
+ {/* Footer */}
+
);
-
- const videoBlock = (video) => {
- if (video?.video_files?.length > 0) {
- return (
-
-
-
-
)
- }
- };
-
- return (
-
-
-
{getPageTitle('Starter Page')}
-
-
-
-
- {contentType === 'image' && contentPosition !== 'background'
- ? imageBlock(illustrationImage)
- : null}
- {contentType === 'video' && contentPosition !== 'background'
- ? videoBlock(illustrationVideo)
- : null}
-
-
-
-
-
© 2026 {title}. All rights reserved
-
- Privacy Policy
-
-
-
-
- );
}
-Starter.getLayout = function getLayout(page: ReactElement) {
- return
{page};
-};
-
+LandingPage.getLayout = function getLayout(page: ReactElement) {
+ return
{page};
+};
\ No newline at end of file