Merge branch 'main' into production

This commit is contained in:
Dobromir Popov
2024-03-05 16:53:27 +02:00
7 changed files with 82 additions and 47 deletions

View File

@ -11,5 +11,5 @@ TELEGRAM_BOT=true
SSL_KEY=./certificates/localhost-key.pem SSL_KEY=./certificates/localhost-key.pem
SSL_CERT=./certificates/localhost.pem SSL_CERT=./certificates/localhost.pem
# DATABASE_URL=mysql://root:Zelen0ku4e@192.168.0.10:3306/cart_dev DATABASE_URL=mysql://root:Zelen0ku4e@192.168.0.10:3306/cart_dev
DATABASE_URL=mysql://cart:cartpw@localhost:3306/cart # DATABASE_URL=mysql://cart:cartpw@localhost:3306/cart

View File

@ -109,7 +109,7 @@ next start
export OPENAI_API_KEY=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 # personal export OPENAI_API_KEY=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 # personal
export OPENAI_API_KEY=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 # dev-bro export OPENAI_API_KEY=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 # dev-bro
# -------------update PRISMA schema/sync database ------------------------ # # ----------------------------------------------update PRISMA schema/sync database ----------------------------------------------- #
# prisma migrate dev --create-only # prisma migrate dev --create-only
npx prisma generate npx prisma generate
npx prisma migrate dev --name fix_nextauth_schema --create-only npx prisma migrate dev --name fix_nextauth_schema --create-only

View File

@ -56,30 +56,27 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o
}, []); }, []);
// Define the minimum and maximum times // Define the minimum and maximum times
const minTime = new Date(); const minTime = new Date();
minTime.setHours(8, 0, 0, 0); // 8:00 AM minTime.setHours(8, 0, 0, 0); // 8:00 AM
const maxTime = new Date(); const maxTime = new Date();
maxTime.setHours(20, 0, 0, 0); // 8:00 PM maxTime.setHours(20, 0, 0, 0); // 8:00 PM
const fetchItemFromDB = async () => {
const id = parseInt(router.query.id);
if (existingItems.length == 0 && id) {
try {
const response = await axiosInstance.get(`/api/data/availabilities/${id}`);
setAvailabilities([response.data]);
setEditMode(true);
} catch (error) {
console.error(error);
toast.error("Error fetching availability data.");
}
}
};
useEffect(() => { useEffect(() => {
const fetchItemFromDB = async () => {
const id = parseInt(router.query.id);
if (existingItems.length == 0 && id) {
try {
const response = await axiosInstance.get(`/api/data/availabilities/${id}`);
setAvailabilities([response.data]);
setEditMode(true);
} catch (error) {
console.error(error);
toast.error("Error fetching availability data.");
}
}
};
fetchItemFromDB(); fetchItemFromDB();
}, [router.query.id]); }, [router.query.id]);
@ -193,6 +190,7 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o
repeatWeekly: doRepeat, repeatWeekly: doRepeat,
dayOfMonth: doRepeat ? null : startTime.getDate(), dayOfMonth: doRepeat ? null : startTime.getDate(),
endDate: doRepeat ? repeatUntil : null, endDate: doRepeat ? repeatUntil : null,
dateOfEntry: new Date(),
}; };
} }
@ -207,13 +205,10 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o
availability.repeatWeekly = doRepeat; availability.repeatWeekly = doRepeat;
availability.dayOfMonth = doRepeat ? null : availability.startTime.getDate(); availability.dayOfMonth = doRepeat ? null : availability.startTime.getDate();
availability.endDate = doRepeat ? repeatUntil : null; availability.endDate = doRepeat ? repeatUntil : null;
availability.dateOfEntry = new Date();
return availability; return availability;
} }
const handleDelete = async (e) => { const handleDelete = async (e) => {
e.preventDefault(); e.preventDefault();
try { try {
@ -231,9 +226,10 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o
handleCompletion({ deleted: true }); handleCompletion({ deleted: true });
} }
} catch (error) { } catch (error) {
alert("Нещо се обърка при изтриването. Моля, опитайте отново или се свържете с нас"); //alert("Нещо се обърка при изтриването. Моля, опитайте отново или се свържете с нас");
console.log(JSON.stringify(error)); console.log(JSON.stringify(error));
toast.error(error.response?.data?.message || "An error occurred"); toast.error(error.response?.data?.message || "An error occurred");
fetchItemFromDB();
} }
}; };

View File

@ -1,4 +1,4 @@
import React, { useState } from "react"; import React, { useState, useEffect } from "react";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import Link from "next/link"; import Link from "next/link";

View File

@ -6,28 +6,64 @@ import axiosServer from '../../../src/axiosServer';
import common from '../../../src/helpers/common'; import common from '../../../src/helpers/common';
import ShiftsList from '../../../components/publisher/ShiftsList'; import ShiftsList from '../../../components/publisher/ShiftsList';
import { monthNamesBG, GetTimeFormat, GetDateFormat } from "../../../src/helpers/const"
import { useSession, getSession } from 'next-auth/react'; import { useSession, getSession } from 'next-auth/react';
export default function MySchedulePage({ assignments }) { export default function MySchedulePage({ assignments }) {
const { data: session, status } = useSession(); const { data: session, status } = useSession();
if (status === "loading") { if (status === "loading") {
return <div>Loading...</div>; return <div className="flex justify-center items-center h-screen">Loading...</div>;
} }
return ( return (
<Layout> <Layout>
<ProtectedRoute allowedRoles={[UserRole.ADMIN, UserRole.POWERUSER, UserRole.USER]}> <ProtectedRoute allowedRoles={[UserRole.ADMIN, UserRole.POWERUSER, UserRole.USER]}>
<div className="container mx-auto p-4"> <div className="container mx-auto p-4">
<h1 className="text-xl font-semibold mb-4">Моите смени</h1> <h1 className="text-2xl md:text-3xl font-bold text-center my-4">Моите смени</h1>
<ShiftsList assignments={assignments} selectedtab={common.getCurrentYearMonth()} /> <div className="space-y-4">
{assignments && assignments.map((assignment) => (
<div key={assignment.dateStr} className="bg-white shadow overflow-hidden rounded-lg">
<div className="px-4 py-5 sm:px-6">
<h3 className="text-lg leading-6 font-medium text-gray-900">{assignment.dateStr}</h3>
</div>
<div className="border-t border-gray-200">
<dl>
<div className="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt className="text-sm font-medium text-gray-500">Час</dt>
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
{GetTimeFormat(assignment.shift.startTime)} - {GetTimeFormat(assignment.shift.endTime)}
</dd>
</div>
<div className="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt className="text-sm font-medium text-gray-500">Действия</dt>
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
<button
className="mr-2 mb-2 inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md shadow-sm text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500"
onClick={() => AddToGoogleCalendar(assignment.id)}
>
Добави в календар
</button>
<button
className="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
onClick={() => searchReplacement(assignment.id)}
>
Търси заместник
</button>
</dd>
</div>
</dl>
</div>
</div>
))}
</div>
</div> </div>
</ProtectedRoute> </ProtectedRoute>
</Layout> </Layout>
); );
} }
//get future assignmenrs for the current user (session.user.id) //get future assignments for the current user (session.user.id)
export const getServerSideProps = async (context) => { export const getServerSideProps = async (context) => {
const session = await getSession(context); const session = await getSession(context);
@ -72,6 +108,7 @@ export const getServerSideProps = async (context) => {
if (assignment.shift && assignment.shift.startTime) { if (assignment.shift && assignment.shift.startTime) {
return { return {
...assignment, ...assignment,
dateStr: assignment.shift.startTime.toLocaleDateString("bg-BG", { day: "numeric", month: "long" }),
shift: { shift: {
...assignment.shift, ...assignment.shift,
startTime: assignment.shift.startTime.toISOString(), startTime: assignment.shift.startTime.toISOString(),
@ -82,26 +119,10 @@ export const getServerSideProps = async (context) => {
return assignment; return assignment;
}); });
const singleKey = "all";
const assignmentsStructure = {
assignments: {
items: {
[singleKey]: [],
},
keys: [singleKey],
months: {
[singleKey]: "Всички смени",
},
},
selectedtab: singleKey,
};
transformedAssignments.forEach(assignment => {
assignmentsStructure.assignments.items[singleKey].push(assignment);
});
return { return {
props: assignmentsStructure props: { assignments: transformedAssignments }
} }
} }

View File

@ -0,0 +1,18 @@
-- AlterTable
ALTER TABLE `Availability` ADD COLUMN `dateOfEntry` DATETIME(3) NULL;
-- CreateTable
CREATE TABLE `Message` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`publisherId` VARCHAR(191) NOT NULL,
`date` DATETIME(3) NOT NULL,
`content` VARCHAR(191) NOT NULL,
`isRead` BOOLEAN NOT NULL DEFAULT false,
`isPublic` BOOLEAN NOT NULL DEFAULT false,
`type` ENUM('Email', 'SMS', 'Push', 'InApp') NOT NULL DEFAULT 'Email',
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- AddForeignKey
ALTER TABLE `Message` ADD CONSTRAINT `Message_publisherId_fkey` FOREIGN KEY (`publisherId`) REFERENCES `Publisher`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@ -133,7 +133,7 @@ model Availability {
repeatWeekly Boolean? // New field to indicate weekly repetition // until now dayofweek was used for repetition when dayOfMonth is null repeatWeekly Boolean? // New field to indicate weekly repetition // until now dayofweek was used for repetition when dayOfMonth is null
repeatFrequency Int? // New field to indicate repetition frequency repeatFrequency Int? // New field to indicate repetition frequency
endDate DateTime? // New field for the end date of repetition endDate DateTime? // New field for the end date of repetition
//dateOfEntry DateTime? //NEW v1.0.1 trade storage for intuintivity dateOfEntry DateTime? //NEW v1.0.1 trade storage for intuintivity
} }
model CartEvent { model CartEvent {