diff --git a/components/header.tsx b/components/header.tsx index 2dbaff8..6859f7e 100644 --- a/components/header.tsx +++ b/components/header.tsx @@ -1,124 +1,121 @@ -import Link from "next/link" -import { signIn, signOut, useSession } from "next-auth/react" -import styles from "../styles/header.module.css" +// import Link from "next/link" +// import { signIn, signOut, useSession } from "next-auth/react" +// import styles from "../styles/header.module.css" -// The approach used in this component shows how to build a sign in and sign out -// component that works on pages which support both client and server side -// rendering, and avoids any flash incorrect content on initial page load. -export default function Header() { - const { data: session, status } = useSession() - const loading = status === "loading" +// // The approach used in this component shows how to build a sign in and sign out +// // component that works on pages which support both client and server side +// // rendering, and avoids any flash incorrect content on initial page load. +// export default function Header() { +// const { data: session, status } = useSession() +// const loading = status === "loading" -//generate top header with sign in/out button and dropdown menu and user name/surname using tailwindcss +// //generate top header with sign in/out button and dropdown menu and user name/surname using tailwindcss - return ( -
- - {/* */} -
-

- {!session && ( - <> - - You are not signed in - - { - e.preventDefault() - signIn() - }} - > - Sign in - - - )} - {session?.user && ( - <> - {session.user.image && ( - - )} - - Signed in as -
- {session.user.email ?? session.user.name} -
- { - e.preventDefault() - signOut() - }} - > - Sign out - - - )} -

-
- */ } + +//
+// ) +// } diff --git a/components/layout.tsx b/components/layout.tsx index 39d91c5..25279f5 100644 --- a/components/layout.tsx +++ b/components/layout.tsx @@ -1,4 +1,4 @@ -import Header from "./header" + import Link from 'next/link' import Footer from "./footer" import Sidebar from "./sidebar" diff --git a/components/sidebar.tsx b/components/sidebar.tsx index 73ff708..52144db 100644 --- a/components/sidebar.tsx +++ b/components/sidebar.tsx @@ -16,6 +16,7 @@ import { UserRole } from "@prisma/client"; const packageVersion = require('../package.json').version; function SidebarMenuItem({ item, session, isSubmenu }) { + // const tMenu = useTranslations('menu'); // const [t, locale] = useState(useTranslations('menu')); // useEffect(() => { diff --git a/content/i18n/bg.json b/content/i18n/bg.json index 26788cf..8ec5af7 100644 --- a/content/i18n/bg.json +++ b/content/i18n/bg.json @@ -32,5 +32,13 @@ "statistics": "Статистика", "coverMeLogs": "Замествания", "translations": "Преводи" + }, + "content": { + "location": { + "warehouse": { + "description": "- снимки как да се поставят количките\n- снимка с код за катинар\nвсеки може да всима/връща\n- преди да влизаме трябва да почистим краката.\n- зареждаме/почистваме извън\n- влизане/озлизане няма код\n- влизане/излизане има код", + "title": "СНЛАД" + } + } } } \ No newline at end of file diff --git a/content/i18n/en.json b/content/i18n/en.json index 19bce02..87077a2 100644 --- a/content/i18n/en.json +++ b/content/i18n/en.json @@ -32,5 +32,13 @@ "statistics": "View Statistics", "coverMeLogs": "View CoverMe logs", "translations": "Translation" + }, + "content": { + "location": { + "warehouse": { + "description": "- снимки как да се поставят количките\n- снимка с код за катинар\nвсеки може да всима/връща\n- преди да влизаме трябва да почистим краката.\n- зареждаме/почистваме извън\n- влизане/озлизане няма код\n- влизане/излизане има код", + "title": "СНЛАД" + } + } } } \ No newline at end of file diff --git a/content/i18n/ru.json b/content/i18n/ru.json index c68913e..fb8f07b 100644 --- a/content/i18n/ru.json +++ b/content/i18n/ru.json @@ -8,10 +8,17 @@ "BG": "болгарский", "EN": "английский", "RU": "русский", - "login": "вход", - "contacts": "Контакти te" + "login": "вход" }, "menu": { "dashboard": "Начало" + }, + "content": { + "location": { + "warehouse": { + "description": "- снимки как да се поставят количките\n- снимка с код за катинар\nвсеки може да всима/връща\n- преди да влизаме трябва да почистим краката.\n- зареждаме/почистваме извън\n- влизане/озлизане няма код\n- влизане/излизане има код", + "title": "СНЛАД" + } + } } } \ No newline at end of file diff --git a/pages/cart/locations/[id].tsx b/pages/cart/locations/[id].tsx index c66f338..7101159 100644 --- a/pages/cart/locations/[id].tsx +++ b/pages/cart/locations/[id].tsx @@ -5,6 +5,8 @@ import "react-responsive-carousel/lib/styles/carousel.min.css"; // requires a lo import { GetServerSideProps } from 'next'; import { Location, UserRole } from "@prisma/client"; import axiosServer from '../../../src/axiosServer'; +import { useTranslations, createTranslator } from 'next-intl'; +// import { getTranslations } from 'next-intl/server'; const ViewLocationPage: React.FC = ({ location }) => { const [activeTab, setActiveTab] = useState('mainLocation'); @@ -12,6 +14,7 @@ const ViewLocationPage: React.FC = ({ location }) => { const [images, setImages] = useState([]); const [mainLocationImageCount, setMainLocationImageCount] = useState(0); + const t = useTranslations('content'); useEffect(() => { const mainLocationImages = [location.picture1, location.picture2, location.picture3].filter(Boolean); @@ -98,15 +101,44 @@ const ViewLocationPage: React.FC = ({ location }) => { export const getServerSideProps: GetServerSideProps = async (context) => { const axios = await axiosServer(context); + // Get the locale from context or use default + const locale = context.locale || 'en'; + const messages = (await import(`../../../content/i18n/${locale}.json`)).default; + + const t = createTranslator({ locale, messages }); + // Function to replace placeholders in HTML content + const replacePlaceholders = (content: string) => { + if (!content) return ''; + const placeholderPattern = /{([^}]+)}/g; + return content.replace(placeholderPattern, (match, key) => { + try { + const translation = t('content.' + key); + // Check if translation exists and is not empty + if (translation && translation !== 'content.' + key) { + return translation; + } + // Return formatted placeholder if translation not found + return `[${locale}:${key}]`; + } catch (error) { + // Return formatted placeholder on error + return `[${locale}:${key}]`; + } + }); + }; + + + const { data: location } = await axios.get( `${process.env.NEXT_PUBLIC_PUBLIC_URL}/api/data/locations/${context.params.id}` ); + location.content = replacePlaceholders(location.content); + if (location.backupLocationId !== null) { const { data: backupLocation } = await axios.get( process.env.NEXT_PUBLIC_PUBLIC_URL + "/api/data/locations/" + location.backupLocationId ); location.backupLocationName = backupLocation.name; - location.backupLocationContent = backupLocation ? backupLocation.content : ""; + location.backupLocationContent = backupLocation ? replacePlaceholders(backupLocation.content) : ""; location.backupLocationImages = backupLocation ? [backupLocation.picture1, backupLocation.picture2, backupLocation.picture3].filter(Boolean) : []; } diff --git a/pages/cart/reports/coverMe.tsx b/pages/cart/reports/coverMe.tsx index 0084e85..3104c46 100644 --- a/pages/cart/reports/coverMe.tsx +++ b/pages/cart/reports/coverMe.tsx @@ -1,144 +1,206 @@ -//page to show all repots in the database with a link to the report page -import axiosInstance from '../../../src/axiosSecure'; import { useEffect, useState } from "react"; -import toast from "react-hot-toast"; -import { useRouter } from "next/router"; -import Link from "next/link"; -import { useSession } from "next-auth/react" -//const common = require('src/helpers/common'); -import common from '../../../src/helpers/common'; +import axiosInstance from "../../../src/axiosSecure"; +import { useSession } from "next-auth/react"; import Layout from "../../../components/layout"; -import ProtectedRoute from '../../../components/protectedRoute'; -import { Location, Shift, UserRole, EventLog, EventType, EventLogType } from "@prisma/client"; -import { set } from 'date-fns'; +import ProtectedRoute from "../../../components/protectedRoute"; +import { UserRole, EventLogType } from "@prisma/client"; +const timeFilters = [ + { label: "1 седмица", value: 7 }, + { label: "1 месец", value: 30 }, + { label: "3 месеца", value: 90 }, + { label: "Всички", value: null }, +]; + +const eventTypes = [ + { label: "Заявки", value: EventLogType.AssignmentReplacementRequested }, + { label: "Приети замествания", value: EventLogType.AssignmentReplacementAccepted }, + { label: "Ръчно въведени замествания", value: EventLogType.AssignmentReplacementManual }, +]; export default function EventLogList() { const [eventLogs, setEventLog] = useState([]); const [requestedAssignments, setRequestedAssignments] = useState([]); - const router = useRouter(); + const [showOpenRequests, setShowOpenRequests] = useState(false); + const [selectedTimeFilter, setSelectedTimeFilter] = useState(null); // Time filter state + const [selectedEventTypes, setSelectedEventTypes] = useState(eventTypes.map((et) => et.value)); // Default: all types const { data: session } = useSession(); - const [locations, setLocations] = useState([]); - const [showOpenRequests, setShowOpenRequests] = useState(false); - useEffect(() => { - const fetchLocations = async () => { + const fetchEventLogs = async () => { try { - const { data: eventLogsDataold } = await axiosInstance.get(`/api/data/prisma/eventLog?where={"type":"${EventLogType.AssignmentReplacementAccepted}"}&include={"publisher":{"select":{"firstName":true,"lastName":true}},"shift":{"include":{"assignments":{"include":{"publisher":{"select":{"firstName":true,"lastName":true}}}}}}}`); + const where = encodeURIComponent( + JSON.stringify({ + OR: selectedEventTypes.map((type) => ({ type })), + }) + ); - // const where = encodeURIComponent(`{OR: [{type: "${EventLogType.AssignmentReplacementAccepted}"}, {type: "${EventLogType.AssignmentReplacementManual}"}]}`); - const where = encodeURIComponent(JSON.stringify({ - OR: [ - { type: EventLogType.AssignmentReplacementAccepted }, - { type: EventLogType.AssignmentReplacementManual } - ] - })); - - const { data: eventLogsData } = await axiosInstance.get(`/api/data/prisma/eventLog?where=${where}&include={"publisher":{"select":{"firstName":true,"lastName":true}},"shift":{"include":{"assignments":{"include":{"publisher":{"select":{"firstName":true,"lastName":true}}}}}}}`); + const { data: eventLogsData } = await axiosInstance.get( + `/api/data/prisma/eventLog?where=${where}&include={"publisher":{"select":{"firstName":true,"lastName":true}},"shift":{"include":{"assignments":{"include":{"publisher":{"select":{"firstName":true,"lastName":true}}}}}}}` + ); setEventLog(eventLogsData); - const { data: shiftsData } = await axiosInstance.get(`/api/data/prisma/assignment?where={"publicGuid":{"not":"null"}}&include={"shift":{"include":{"assignments":{"include":{"publisher":{"select":{"firstName":true,"lastName":true}}}}}},"publisher":{"select":{"firstName":true,"lastName":true}}}`); + const { data: shiftsData } = await axiosInstance.get( + `/api/data/prisma/assignment?where={"publicGuid":{"not":"null"}}&include={"shift":{"include":{"assignments":{"include":{"publisher":{"select":{"firstName":true,"lastName":true}}}}}},"publisher":{"select":{"firstName":true,"lastName":true}}}` + ); setRequestedAssignments(shiftsData); - } catch (error) { console.error(error); } }; - if (!locations.length) { - fetchLocations(); - } - }, []); + fetchEventLogs(); + }, [selectedEventTypes]); + // Filter events based on the selected time range + const filteredEventLogs = eventLogs.filter((event) => { + if (!selectedTimeFilter) return true; + const eventDate = new Date(event.date); + const cutoffDate = new Date(); + cutoffDate.setDate(cutoffDate.getDate() - selectedTimeFilter); + return eventDate >= cutoffDate; + }); + + // Toggle event type selection + const toggleEventType = (eventType) => { + setSelectedEventTypes((prev) => + prev.includes(eventType) + ? prev.filter((type) => type !== eventType) + : [...prev, eventType] + ); + }; return ( -

Заявки за заместване

- {/* - - */} -
-
-
- - +
+ +
+
); } - - diff --git a/styles/styles.css b/styles/styles.css index b924acf..1b136bb 100644 --- a/styles/styles.css +++ b/styles/styles.css @@ -2,7 +2,9 @@ box-sizing: border-box; } */ body { - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, + "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; padding: 0 1rem 1rem 1rem; max-width: 768px; margin: 0 auto; @@ -52,7 +54,7 @@ iframe { padding: 20px; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); - + z-index: 1051; /* High z-index */ } @@ -119,7 +121,6 @@ iframe { /* Add any additional styles you need */ } - .disabled { opacity: 0.6; pointer-events: none; @@ -162,11 +163,11 @@ iframe { overflow-y: auto; /* Vertical scroll only when needed */ } - /* CALENDAR */ - .icon-large { +/* CALENDAR */ +.icon-large { font-size: 16px; /* Example size, adjust as needed */ } - .rbc-calendar { +.rbc-calendar { font-family: sans-serif; font-size: 18px; } @@ -179,13 +180,12 @@ iframe { margin: 0 10px; /* Adding margin for spacing */ border-radius: 4px; /* Optional: rounding the corners for a softer look */ background-color: #ecf0f1; /* Light background color to make it stand out */ - box-shadow: 0 2px 4px rgba(0,0,0,0.1); /* Optional: adding a subtle shadow for depth */ + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* Optional: adding a subtle shadow for depth */ display: inline-block; /* To apply padding and background color correctly */ - /* Adding glow to the text */ + /* Adding glow to the text */ /* text-shadow: 0 0 2px rgba(252, 252, 252, 0.8); Adjust color and glow size as needed */ } - .mobile-calendar .rbc-btn-group button { padding: 4px 6px; /* Smaller buttons */ font-size: 16px; /* Smaller button text */ @@ -232,8 +232,7 @@ iframe { cursor: pointer; transition: all 0.3s; } */ -.rbc-calendar .rbc-month-view .rbc-event -{ +.rbc-calendar .rbc-month-view .rbc-event { padding: 2; margin: 2; background-color: transparent; @@ -246,14 +245,10 @@ iframe { /* min-height:150px !important; * / } */ - - .react-responsive-carousel .control-arrow { - width: 25%; + width: 25%; } - - /* Custom CSS for responsive table */ @media (max-width: 768px) { /* Hide table headers on small screens */ @@ -291,4 +286,3 @@ iframe { align-items: center; justify-content: center; /* Optional: center buttons in the group */ } -