From acd776e98881ec9134eec668fda3756c7f6c3dde Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 26 Mar 2024 01:08:57 +0200 Subject: [PATCH 01/30] renames --- components/ExampleForm.js | 8 +++---- components/availability/AvailabilityForm.js | 2 +- .../AvailabilityFormDatePicker.js | 10 ++++---- components/availability/AvailabilityList.js | 2 +- components/calendar/ShiftComponent.tsx | 2 +- components/calendar/avcalendar.tsx | 12 +++++----- components/cartevent/CartEventForm.tsx | 6 ++--- components/location/LocationCard.js | 4 ++-- components/location/LocationForm.js | 10 ++++---- components/publisher/PublisherCard.js | 4 ++-- components/publisher/PublisherForm.js | 8 +++---- components/publisher/PublisherSearchBox.js | 4 ++-- components/publisher/ShiftsList.tsx | 2 +- components/sidebar.tsx | 2 +- pages/api/index.ts | 4 ++-- pages/api/schedule.ts | 2 +- pages/api/shiftgenerate.ts | 10 ++++---- pages/cart/availabilities/index.tsx | 10 ++++---- pages/cart/calendar/index.tsx | 18 +++++++-------- pages/cart/cartevents/index.tsx | 2 +- pages/cart/publishers/import.tsx | 10 ++++---- pages/cart/publishers/index.tsx | 2 +- pages/cart/publishers/stats.tsx | 6 ++--- pages/cart/reports/list.tsx | 12 ++++++++++ pages/dash.tsx | 6 ++--- prisma/bl/subqueries.js | 4 ++-- .../20221130072538_updates/migration.sql | 6 ++--- .../migrations/20221201223336_/migration.sql | 4 ++-- .../migration.sql | 2 +- .../migration.sql | 4 ++-- .../20240325214807_misc_renames/migration.sql | 15 ++++++++++++ prisma/schema.prisma | 23 +++++++++++++------ prisma/seed.sql | 6 ++--- server.js | 4 ++-- src/helpers/data.js | 6 ++--- src/helpers/excel.js | 14 +++++------ src/sql/dev-test.sql | 4 ++-- 37 files changed, 143 insertions(+), 107 deletions(-) create mode 100644 prisma/migrations/20240325214807_misc_renames/migration.sql diff --git a/components/ExampleForm.js b/components/ExampleForm.js index 45f49f8..bf9050f 100644 --- a/components/ExampleForm.js +++ b/components/ExampleForm.js @@ -40,7 +40,7 @@ class ExampleForm extends React.Component { } const [item, set] = useState({ - isactive: true, + isActive: true, }); const router = useRouter(); @@ -63,7 +63,7 @@ class ExampleForm extends React.Component { handleChange = ({ target }) => { - if (target.name === "isactive") { + if (target.name === "isActive") { set({ ...item, [target.name]: target.checked }); } else if (target.name === "age") { set({ ...item, [target.name]: parseInt(target.value) }); @@ -100,8 +100,8 @@ class ExampleForm extends React.Component {

{router.query?.id ? "Редактирай" : "Създай"} Item

- -
diff --git a/components/availability/AvailabilityForm.js b/components/availability/AvailabilityForm.js index f95870e..19d09a4 100644 --- a/components/availability/AvailabilityForm.js +++ b/components/availability/AvailabilityForm.js @@ -39,7 +39,7 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o dayOfMonth: null, // startTime: "08:00", // endTime: "20:00", - isactive: true, + isActive: true, repeatWeekly: false, endDate: null, isFirst: false, diff --git a/components/availability/AvailabilityFormDatePicker.js b/components/availability/AvailabilityFormDatePicker.js index 5d8f4fc..e7a3f26 100644 --- a/components/availability/AvailabilityFormDatePicker.js +++ b/components/availability/AvailabilityFormDatePicker.js @@ -36,7 +36,7 @@ model Availability { weekOfMonth Int? startTime DateTime endTime DateTime - isactive Boolean @default(true) + isActive Boolean @default(true) type AvailabilityType @default(Weekly) isWithTransport Boolean @default(false) isFromPreviousAssignment Boolean @default(false) @@ -69,7 +69,7 @@ export default function AvailabilityForm({ publisherId, existingItem, inline, on dayOfMonth: null, startTime: "08:00", endTime: "20:00", - isactive: true, + isActive: true, repeatWeekly: false, endDate: null, }); @@ -554,11 +554,11 @@ export default function AvailabilityForm({ publisherId, existingItem, inline, on
- - + +
- {/* */} + {/* */}
diff --git a/components/availability/AvailabilityList.js b/components/availability/AvailabilityList.js index 65bdf6d..cb9cc56 100644 --- a/components/availability/AvailabilityList.js +++ b/components/availability/AvailabilityList.js @@ -56,7 +56,7 @@ export default function AvailabilityList({ publisher, showNew }) { {items?.sort((a, b) => new Date(a.startTime) - new Date(b.startTime)).map(item => ( - + {item.dayOfMonth ? `${common.getDateFormated(new Date(item.startTime))}` : `Всеки(Всяка) ${common.getDayOfWeekName(new Date(item.startTime))}`} {/* {common.getDateFormated(new Date(item.startTime))} */} diff --git a/components/calendar/ShiftComponent.tsx b/components/calendar/ShiftComponent.tsx index 0802bc8..a50db70 100644 --- a/components/calendar/ShiftComponent.tsx +++ b/components/calendar/ShiftComponent.tsx @@ -70,7 +70,7 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a const newAssignment = { publisher: { connect: { id: publisher.id } }, shift: { connect: { id: shiftId } }, - //isactive: true, + //isActive: true, isConfirmed: true, }; const { data } = await axiosInstance.post("/api/data/assignments", newAssignment); diff --git a/components/calendar/avcalendar.tsx b/components/calendar/avcalendar.tsx index 8fd7026..c631c72 100644 --- a/components/calendar/avcalendar.tsx +++ b/components/calendar/avcalendar.tsx @@ -206,7 +206,7 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => { // startTime: start, // endTime: end, // dayOfMonth: start.getDate(), - // isactive: true, + // isActive: true, // publisherId: publisherId, // // Add any other initial values needed // //set dayOfMonth to null, so that we repeat the availability every week @@ -273,9 +273,9 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => { //if event.type is availability show in blue. if it is schedule - green if confirmed, yellow if not confirmed //if event is not active - show in gray let bgColorClass = 'bg-gray-500'; // Default color for inactive events - var bgColor = event.isactive ? "" : "bg-gray-500"; + var bgColor = event.isActive ? "" : "bg-gray-500"; if (event.type === "assignment") { - bgColor = event.isTentative ? "bg-red-500" : (event.isConfirmed ? "bg-green-500" : "bg-yellow-500"); + bgColor = event.isBySystem ? "bg-red-500" : (event.isConfirmed ? "bg-green-500" : "bg-yellow-500"); //event.title = event.publisher.name; //ToDo: add other publishers names //event.title = common.getTimeFomatted(event.startTime) + " - " + common.getTimeFomatted(event.endTime); @@ -319,7 +319,7 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => { toast.info("Потвърдено!", { autoClose: 2000 }); // Update the event data event.isConfirmed = true; - event.isTentative = false; + event.isBySystem = false; // Update the events array by first removing the old event and then adding the updated one setEvents(currentEvents => { const filteredEvents = currentEvents.filter(e => e.id !== event.id); @@ -328,7 +328,7 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => { //store the updated event in the database var assignment = { isConfirmed: true, - isTentative: false + isBySystem: false }; axiosInstance.put('/api/data/assignments/' + event.id, assignment) .then((response) => { @@ -388,7 +388,7 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => { // orange-500 from Tailwind CSS backgroundColor = '#f56565'; } - if (event.isactive) { + if (event.isActive) { switch (event.type) { case 'assignment': backgroundColor = event.isConfirmed ? '#48bb78' : '#f6e05e'; // green-500 and yellow-300 from Tailwind CSS diff --git a/components/cartevent/CartEventForm.tsx b/components/cartevent/CartEventForm.tsx index 1399799..d6d6fdd 100644 --- a/components/cartevent/CartEventForm.tsx +++ b/components/cartevent/CartEventForm.tsx @@ -15,7 +15,7 @@ model CartEvent { shiftDuration Int shifts Shift[] dayofweek DayOfWeek - isactive Boolean @default(true) + isActive Boolean @default(true) }*/ interface Location { id: number; @@ -174,8 +174,8 @@ export default function CartEventForm(props: IProps) {
- - + +
diff --git a/components/location/LocationCard.js b/components/location/LocationCard.js index 2a2a3ec..adaf15c 100644 --- a/components/location/LocationCard.js +++ b/components/location/LocationCard.js @@ -28,11 +28,11 @@ export default function LocationCard({ location }) { <>
router.push(`/cart/locations/edit/${location.id}`)} >
- {location.name} ({location.isactive ? "active" : "inactive"}) + {location.name} ({location.isActive ? "active" : "inactive"})

{location.address} diff --git a/components/location/LocationForm.js b/components/location/LocationForm.js index 098186a..4f58fdb 100644 --- a/components/location/LocationForm.js +++ b/components/location/LocationForm.js @@ -19,7 +19,7 @@ const common = require('src/helpers/common'); // id Int @id @default(autoincrement()) // name String // address String -// isactive Boolean @default(true) +// isActive Boolean @default(true) // content String? @db.Text // cartEvents CartEvent[] // reports Report[] @@ -65,7 +65,7 @@ export default function LocationForm() { const [location, set] = useState({ name: "", address: "", - isactive: true, + isActive: true, }); // const [isEdit, setIsEdit] = useState(false); @@ -171,11 +171,11 @@ export default function LocationForm() {

- {/* UI for Location.isactive */} + {/* UI for Location.isActive */}
- - + +
{/* backupLocation */} diff --git a/components/publisher/PublisherCard.js b/components/publisher/PublisherCard.js index a993240..248f067 100644 --- a/components/publisher/PublisherCard.js +++ b/components/publisher/PublisherCard.js @@ -57,7 +57,7 @@ export default function PublisherCard({ publisher }) { return isCardVisible ? ( // className="block p-6 max-w-sm bg-white rounded-lg border border-gray-200 shadow-md hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700 mb-3"
- {publisher.firstName} {publisher.lastName} ({publisher.isactive ? "active" : "inactive"}) + {publisher.firstName} {publisher.lastName} ({publisher.isActive ? "active" : "inactive"})

{publisher.assignments.length} смени общо

diff --git a/components/publisher/PublisherForm.js b/components/publisher/PublisherForm.js index f5f1f44..a95e520 100644 --- a/components/publisher/PublisherForm.js +++ b/components/publisher/PublisherForm.js @@ -23,7 +23,7 @@ import { UserRole } from "@prisma/client"; // lastName String // email String @unique // phone String? -// isactive Boolean @default(true) +// isActive Boolean @default(true) // isImported Boolean @default(false) // age Int? // availabilities Availability[] @@ -75,7 +75,7 @@ export default function PublisherForm({ item, me }) { }, []); const [publisher, set] = useState(item || { - isactive: true, + isActive: true, }); const handleChange = ({ target }) => { @@ -259,8 +259,8 @@ export default function PublisherForm({ item, me }) {
- - + + diff --git a/components/publisher/PublisherSearchBox.js b/components/publisher/PublisherSearchBox.js index 605b70c..4926504 100644 --- a/components/publisher/PublisherSearchBox.js +++ b/components/publisher/PublisherSearchBox.js @@ -18,7 +18,7 @@ function PublisherSearchBox({ selectedId, onChange, isFocused, filterDate, showS const fetchPublishers = async () => { console.log("fetchPublishers called"); try { - let url = `/api/?action=filterPublishers&select=id,firstName,lastName,email,isactive&searchText=${searchText}&availabilities=false`; + let url = `/api/?action=filterPublishers&select=id,firstName,lastName,email,isActive&searchText=${searchText}&availabilities=false`; if (filterDate) { url += `&filterDate=${common.getISODateOnly(filterDate)}`; @@ -29,7 +29,7 @@ function PublisherSearchBox({ selectedId, onChange, isFocused, filterDate, showS const { data: publishersData } = await axiosInstance.get(url); //setPublishers(publishersData); - const activePublishers = publishersData.filter(publisher => publisher.isactive === true); + const activePublishers = publishersData.filter(publisher => publisher.isActive === true); setPublishers(activePublishers); } catch (error) { diff --git a/components/publisher/ShiftsList.tsx b/components/publisher/ShiftsList.tsx index 49cc71a..ac3bb30 100644 --- a/components/publisher/ShiftsList.tsx +++ b/components/publisher/ShiftsList.tsx @@ -35,7 +35,7 @@ const ShiftsList = ({ assignments, selectedtab }: ShiftsListProps) => { try { var assignment = (await axiosInstance.get("/api/data/assignments/" + id)).data; assignment.isConfirmed = false; - assignment.isTentative = true; + // ! assignment.isTentative = true; // assignment.isDeleted = true; await axiosInstance.put("/api/data/assignments/" + id, assignment); toast.success("Shift Tentative", { diff --git a/components/sidebar.tsx b/components/sidebar.tsx index b0d4838..b20a168 100644 --- a/components/sidebar.tsx +++ b/components/sidebar.tsx @@ -99,7 +99,7 @@ export default function Sidebar({ isSidebarOpen, toggleSidebar }) { try { const response = await axiosInstance.get('/api/data/locations'); // Adjust the API endpoint as needed const locationsData = response.data - .filter(location => location.isactive === true) + .filter(location => location.isActive === true) .map(location => ({ text: location.name, url: `/cart/locations/${location.id}`, diff --git a/pages/api/index.ts b/pages/api/index.ts index 260bc92..6979920 100644 --- a/pages/api/index.ts +++ b/pages/api/index.ts @@ -143,7 +143,7 @@ export default async function handler(req, res) { case "getUnassignedPublishers": //let monthInfo = common.getMonthDatesInfo(date); - let allPubs = await filterPublishers("id,firstName,lastName,email,isactive".split(","), "", date, true, true, false); + let allPubs = await filterPublishers("id,firstName,lastName,email,isActive".split(","), "", date, true, true, false); let unassignedPubs = allPubs.filter(pub => pub.currentMonthAssignments == 0 && pub.availabilities.length > 0); res.status(200).json(unassignedPubs); break; @@ -690,7 +690,7 @@ async function replaceInAssignment(oldPublisherId, newPublisherId, shiftId) { data: { publisherId: newPublisherId, isConfirmed: false, - isTentative: true, + isBySystem: true, isMailSent: false } }); diff --git a/pages/api/schedule.ts b/pages/api/schedule.ts index 22ae3d9..e322568 100644 --- a/pages/api/schedule.ts +++ b/pages/api/schedule.ts @@ -89,7 +89,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const shifts = await prisma.shift.findMany({ where: { - isactive: true, + isActive: true, startTime: { gte: fromDate, lt: toDate, diff --git a/pages/api/shiftgenerate.ts b/pages/api/shiftgenerate.ts index 64b2104..4d44052 100644 --- a/pages/api/shiftgenerate.ts +++ b/pages/api/shiftgenerate.ts @@ -68,7 +68,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { case "test": var data = prisma.shift.findMany({ where: { - isactive: true + isActive: true } }); @@ -110,7 +110,7 @@ async function GenerateSchedule(axios: Axios, date: string, copyFromPreviousMont } console.log("finding shifts for previous 3 months for statistics (between " + new Date(monthInfo.date.getFullYear(), monthInfo.date.getMonth() - 3, 1).toISOString() + " and " + monthInfo.firstDay.toISOString() + ")"); - const { data: events } = await axios.get(`/api/data/cartevents?where={"isactive":{"$eq":true}}`); + const { data: events } = await axios.get(`/api/data/cartevents?where={"isActive":{"$eq":true}}`); //// let [shiftsLastMonth, publishers] = await getShiftsAndPublishersForPreviousMonths(lastMonthInfo); //use filterPublishers from /pages/api/data/index.ts to get publishers with stats @@ -308,7 +308,7 @@ async function GenerateSchedule(axios: Axios, date: string, copyFromPreviousMont assignments: 'true', availabilities: 'true', date: common.getISODateOnly(shiftStart), - select: 'id,firstName,lastName,isactive,desiredShiftsPerMonth' + select: 'id,firstName,lastName,isActive,desiredShiftsPerMonth' }); let allAvailablePublishers = (await axios.get(`/api/?${queryParams.toString()}`)).data; let availablePublishers = allAvailablePublishers; @@ -616,12 +616,12 @@ async function ImportShiftsFromDocx(axios: Axios) { // prisma.publisher.findMany({ // where: { -// isactive: true, +// isActive: true, // }, // include: { // availabilities: { // where: { -// isactive: true, +// isActive: true, // }, // }, // assignments: { diff --git a/pages/cart/availabilities/index.tsx b/pages/cart/availabilities/index.tsx index 4cd257b..0cd158a 100644 --- a/pages/cart/availabilities/index.tsx +++ b/pages/cart/availabilities/index.tsx @@ -30,7 +30,7 @@ export default function AvPage({ initialItems, id }: IProps) { date: new Date(item.startTime), start: new Date(item.startTime), end: new Date(item.endTime), - isactive: item.isactive, + isActive: item.isActive, publisherId: item.publisher.id, dayOfMonth: item.dayOfMonth, dayOfWeek: item.dayOfWeek, @@ -66,9 +66,9 @@ export default function AvPage({ initialItems, id }: IProps) { {initialItems?.map((item: Availability) => ( - + - {item.id} {item.isactive} + {item.id} {item.isActive} {item.publisher.lastName}, {item.publisher.firstName} @@ -133,14 +133,14 @@ export const getServerSideProps = async (context) => { const role = session?.user.role; console.log("server role: " + role); - var queryUrl = process.env.NEXTAUTH_URL + "/api/data/availabilities?select=id,name,isactive,dayofweek,dayOfMonth,startTime,endTime,publisher.firstName,publisher.lastName,publisher.id"; + var queryUrl = process.env.NEXTAUTH_URL + "/api/data/availabilities?select=id,name,isActive,dayofweek,dayOfMonth,startTime,endTime,publisher.firstName,publisher.lastName,publisher.id"; if (role === UserRole.USER || context.query.my) { queryUrl += `&where={"publisherId":"${session?.user.id}"}`; } else if (role == UserRole.ADMIN) { if (context.query.id) { queryUrl += `&where={"publisherId":"${context.query.id}"}`; } else { - queryUrl += `&where={"isactive":true}`; + queryUrl += `&where={"isActive":true}`; } } var resp = await axios.get( diff --git a/pages/cart/calendar/index.tsx b/pages/cart/calendar/index.tsx index a3f5746..77b2d4a 100644 --- a/pages/cart/calendar/index.tsx +++ b/pages/cart/calendar/index.tsx @@ -100,7 +100,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) { console.log("Setting date to '" + date.toLocaleDateString() + "' from '" + selectedDate.toLocaleDateString() + "'. ISO: " + date.toISOString(), "locale ISO:", common.getISODateOnly(date)); if (isCheckboxChecked) { console.log(`getting unassigned publishers for ${common.getMonthName(date.getMonth())} ${date.getFullYear()}`); - const { data: availablePubsForDate } = await axiosInstance.get(`/api/?action=getUnassignedPublishers&date=${dateStr}&select=id,firstName,lastName,isactive,desiredShiftsPerMonth`); + const { data: availablePubsForDate } = await axiosInstance.get(`/api/?action=getUnassignedPublishers&date=${dateStr}&select=id,firstName,lastName,isActive,desiredShiftsPerMonth`); setAvailablePubs(availablePubsForDate); } else { @@ -108,7 +108,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) { try { const { data: shiftsForDate } = await axiosInstance.get(`/api/?action=getShiftsForDay&date=${dateStr}`); setShifts(shiftsForDate); - let { data: availablePubsForDate } = await axiosInstance.get(`/api/?action=filterPublishers&assignments=true&availabilities=true&date=${dateStr}&select=id,firstName,lastName,isactive,desiredShiftsPerMonth`); + let { data: availablePubsForDate } = await axiosInstance.get(`/api/?action=filterPublishers&assignments=true&availabilities=true&date=${dateStr}&select=id,firstName,lastName,isActive,desiredShiftsPerMonth`); availablePubsForDate.forEach(pub => { pub.canTransport = pub.availabilities.some(av => @@ -172,8 +172,8 @@ export default function CalendarPage({ initialEvents, initialShifts }) { // currentMonthAssignments and previousMonthAssignments properties // Sort publishers based on availability and then by assignment counts. const sortedPubs = updatedPubs.sort((a, b) => { - if (a.isactive !== b.isactive) { - return a.isactive ? -1 : 1; + if (a.isActive !== b.isActive) { + return a.isActive ? -1 : 1; } // First, sort by isselected. if (a.isSelected !== b.isSelected) { @@ -355,7 +355,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) { const newAssignment = { publisher: { connect: { id: publisher.id } }, shift: { connect: { id: shiftId } }, - isactive: true, + isActive: true, isConfirmed: true }; const { data } = await axiosInstance.post("/api/data/assignments", newAssignment); @@ -669,7 +669,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) { // Determine border class if selected const selectedBorderClass = pub.isSelected ? 'border-blue-400 border-b-4' : ''; // Determine opacity class - const activeOpacityClass = pub.isactive ? '' : 'opacity-25'; + const activeOpacityClass = pub.isActive ? '' : 'opacity-25'; return ( @@ -878,20 +878,20 @@ export const getServerSideProps = async (context) => { const url = `/api/data/shifts?where={"startTime":{"$and":[{"$gte":"${common.getISODateOnly(firstDayOfMonth)}","$lt":"${common.getISODateOnly(lastDayOfMonth)}"}]}}`; const prismaClient = common.getPrismaClient(); - // let events = await prismaClient.cartEvent.findMany({ where: { isactive: true } }); + // let events = await prismaClient.cartEvent.findMany({ where: { isActive: true } }); // events = events.map(event => ({ // ...event, // // Convert Date objects to ISO strings // startTime: event.startTime.toISOString(), // endTime: event.endTime.toISOString(), // })); - const { data: events } = await axios.get(`/api/data/cartevents?where={"isactive":true}`); + const { data: events } = await axios.get(`/api/data/cartevents?where={"isActive":true}`); //const { data: shifts } = await axios.get(url); // get all shifts for the month, including assigments let shifts = await prismaClient.shift.findMany({ where: { - isactive: true, + isActive: true, startTime: { gte: firstDayOfMonth, //lt: lastDayOfMonth diff --git a/pages/cart/cartevents/index.tsx b/pages/cart/cartevents/index.tsx index c5006c1..0396d9f 100644 --- a/pages/cart/cartevents/index.tsx +++ b/pages/cart/cartevents/index.tsx @@ -69,7 +69,7 @@ export default function CartEventPage({ items, locations }: ICartEventPageProps) {item.shiftDuration} - {item.isactive ? "Yes" : "No"} + {item.isActive ? "Yes" : "No"} + + +
diff --git a/pages/dash.tsx b/pages/dash.tsx index c5f8ced..71718db 100644 --- a/pages/dash.tsx +++ b/pages/dash.tsx @@ -86,7 +86,7 @@ async function getAvailabilities(userId) { select: { id: true, name: true, - isactive: true, + isActive: true, isFromPreviousAssignment: true, dayofweek: true, dayOfMonth: true, @@ -121,7 +121,7 @@ async function getAvailabilities(userId) { shiftId Int publisher Publisher @relation(fields: [publisherId], references: [id], onDelete: Cascade) publisherId String - isactive Boolean @default(true) + isActive Boolean @default(true) isConfirmed Boolean @default(false) isWithTransport Boolean @default(false) Report Report[] @@ -133,7 +133,7 @@ async function getAvailabilities(userId) { }, select: { id: true, - isTentative: true, + isBySystem: true, isConfirmed: true, isWithTransport: true, shift: { diff --git a/prisma/bl/subqueries.js b/prisma/bl/subqueries.js index ab557e0..44f977f 100644 --- a/prisma/bl/subqueries.js +++ b/prisma/bl/subqueries.js @@ -13,7 +13,7 @@ export const publisherSelectWithAvCount = { select: { availability: { where: { - isactive: true + isActive: true } } @@ -40,7 +40,7 @@ export const publisherSelect = { // endTime: true, // dayOfMonth: true, // dayofweek: true, -// isactive: true, +// isActive: true, // count: 'Availability_count' // } // } \ No newline at end of file diff --git a/prisma/migrations/20221130072538_updates/migration.sql b/prisma/migrations/20221130072538_updates/migration.sql index 239a224..978530e 100644 --- a/prisma/migrations/20221130072538_updates/migration.sql +++ b/prisma/migrations/20221130072538_updates/migration.sql @@ -5,7 +5,7 @@ CREATE TABLE `Publisher` ( `lastName` VARCHAR(191) NOT NULL, `email` VARCHAR(191) NOT NULL, `phone` VARCHAR(191) NULL, - `isactive` BOOLEAN NOT NULL DEFAULT true, + `isActive` BOOLEAN NOT NULL DEFAULT true, `age` INTEGER NULL, UNIQUE INDEX `Publisher_email_key`(`email`), @@ -41,7 +41,7 @@ CREATE TABLE `Shift` ( `name` VARCHAR(191) NOT NULL, `startTime` DATETIME(3) NOT NULL, `endTime` DATETIME(3) NOT NULL, - `isactive` BOOLEAN NOT NULL DEFAULT true, + `isActive` BOOLEAN NOT NULL DEFAULT true, `requiresTransport` BOOLEAN NOT NULL DEFAULT false, PRIMARY KEY (`id`) @@ -52,7 +52,7 @@ CREATE TABLE `Location` ( `id` INTEGER NOT NULL AUTO_INCREMENT, `name` VARCHAR(191) NOT NULL, `address` VARCHAR(191) NOT NULL, - `isactive` BOOLEAN NOT NULL DEFAULT true, + `isActive` BOOLEAN NOT NULL DEFAULT true, `dayofweek` ENUM('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday') NOT NULL, PRIMARY KEY (`id`) diff --git a/prisma/migrations/20221201223336_/migration.sql b/prisma/migrations/20221201223336_/migration.sql index 90fe9cb..446e110 100644 --- a/prisma/migrations/20221201223336_/migration.sql +++ b/prisma/migrations/20221201223336_/migration.sql @@ -6,10 +6,10 @@ */ -- AlterTable -ALTER TABLE `Availability` ADD COLUMN `isactive` BOOLEAN NOT NULL DEFAULT true; +ALTER TABLE `Availability` ADD COLUMN `isActive` BOOLEAN NOT NULL DEFAULT true; -- AlterTable -ALTER TABLE `CartEvent` ADD COLUMN `isactive` BOOLEAN NOT NULL DEFAULT true, +ALTER TABLE `CartEvent` ADD COLUMN `isActive` BOOLEAN NOT NULL DEFAULT true, ADD COLUMN `locationId` INTEGER NOT NULL, ADD COLUMN `shiftDuration` INTEGER NOT NULL; diff --git a/prisma/migrations/20221217221944_publisher_to_shift_renamed_assignment/migration.sql b/prisma/migrations/20221217221944_publisher_to_shift_renamed_assignment/migration.sql index a466b86..cd87cb8 100644 --- a/prisma/migrations/20221217221944_publisher_to_shift_renamed_assignment/migration.sql +++ b/prisma/migrations/20221217221944_publisher_to_shift_renamed_assignment/migration.sql @@ -18,7 +18,7 @@ CREATE TABLE `Assignment` ( `id` INTEGER NOT NULL AUTO_INCREMENT, `shiftId` INTEGER NOT NULL, `publisherId` INTEGER NOT NULL, - `isactive` BOOLEAN NOT NULL DEFAULT true, + `isActive` BOOLEAN NOT NULL DEFAULT true, PRIMARY KEY (`id`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; diff --git a/prisma/migrations/20240131113517_assignment_isactive_renamed_istetative/migration.sql b/prisma/migrations/20240131113517_assignment_isactive_renamed_istetative/migration.sql index 0d0703e..55bc254 100644 --- a/prisma/migrations/20240131113517_assignment_isactive_renamed_istetative/migration.sql +++ b/prisma/migrations/20240131113517_assignment_isactive_renamed_istetative/migration.sql @@ -1,11 +1,11 @@ /* Warnings: - - You are about to drop the column `isactive` on the `assignment` table. All the data in the column will be lost. + - You are about to drop the column `isActive` on the `assignment` table. All the data in the column will be lost. */ -- AlterTable -ALTER TABLE `Assignment` DROP COLUMN `isactive`, +ALTER TABLE `Assignment` DROP COLUMN `isActive`, ADD COLUMN `isTentative` BOOLEAN NOT NULL DEFAULT false; -- AlterTable diff --git a/prisma/migrations/20240325214807_misc_renames/migration.sql b/prisma/migrations/20240325214807_misc_renames/migration.sql new file mode 100644 index 0000000..2a2f6e7 --- /dev/null +++ b/prisma/migrations/20240325214807_misc_renames/migration.sql @@ -0,0 +1,15 @@ +/* + Warnings: + + - You are about to drop the column `isTentative` on the `Assignment` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE `Assignment` + ADD COLUMN `isBySystem` BOOLEAN NOT NULL DEFAULT false; +UPDATE `Assignment` SET `isBySystem` = isTentative; + +ALTER TABLE `Assignment` DROP COLUMN `isTentative`, + +-- AlterTable +ALTER TABLE `Report` ADD COLUMN `type` ENUM('ServiceReport', 'Experience', 'Feedback_Problem', 'Feedback_Suggestion', 'Feedback') NOT NULL DEFAULT 'ServiceReport'; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 2ea7b1f..91b56e0 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -81,13 +81,21 @@ enum PublisherType { SpecialPioneer_Missionary } +enum ReportType { + ServiceReport + Experience + Feedback_Problem + Feedback_Suggestion + Feedback +} + model Publisher { id String @id @default(cuid()) firstName String lastName String email String @unique phone String? - isactive Boolean @default(true) + isActive Boolean @default(true) isImported Boolean @default(false) isTrained Boolean @default(false) age Int? @@ -124,7 +132,7 @@ model Availability { weekOfMonth Int? startTime DateTime endTime DateTime - isactive Boolean @default(true) + isActive Boolean @default(true) type AvailabilityType @default(Weekly) isWithTransportIn Boolean @default(false) isWithTransportOut Boolean @default(false) @@ -143,7 +151,7 @@ model CartEvent { shiftDuration Int shifts Shift[] dayofweek DayOfWeek - isactive Boolean @default(true) + isActive Boolean @default(true) location Location @relation(fields: [locationId], references: [id]) locationId Int eventType EventType @default(PW_Cart) @@ -160,7 +168,7 @@ model Shift { name String startTime DateTime endTime DateTime - isactive Boolean @default(true) + isActive Boolean @default(true) requiresTransport Boolean @default(false) notes String? //date DateTime @@ -177,7 +185,7 @@ model Assignment { shiftId Int publisher Publisher @relation(fields: [publisherId], references: [id], onDelete: Cascade) publisherId String - isTentative Boolean @default(false) // if no availability for it, when importing previous schedules + isBySystem Boolean @default(false) // if no availability for it, when importing previous schedules isConfirmed Boolean @default(false) isWithTransport Boolean @default(false) isMailSent Boolean @default(false) @@ -190,7 +198,7 @@ model Location { id Int @id @default(autoincrement()) name String address String - isactive Boolean @default(true) + isActive Boolean @default(true) content String? @db.LongText cartEvents CartEvent[] reports Report[] @@ -219,7 +227,8 @@ model Report { returnVisitInfoCount Int? conversationCount Int? - experienceInfo String? @db.LongText + experienceInfo String? @db.LongText + type ReportType @default(ServiceReport) @@map("Report") } diff --git a/prisma/seed.sql b/prisma/seed.sql index f64a4f5..6261a5c 100644 --- a/prisma/seed.sql +++ b/prisma/seed.sql @@ -30,7 +30,7 @@ INSERT INTO `id`, `name`, `address`, - `isactive` + `isActive` ) VALUES ( 1, @@ -57,7 +57,7 @@ INSERT INTO `startTime`, `endTime`, `dayofweek`, - `isactive`, + `isActive`, `locationId`, `shiftDuration`, `eventType`, @@ -147,7 +147,7 @@ VALUES ( /*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */ ; --- INSERT INTO `cartevent` (`id`, `startTime`, `endTime`, `dayofweek`, `isactive`, `locationId`, `shiftDuration`, `eventType`, `numberOfPublishers`) +-- INSERT INTO `cartevent` (`id`, `startTime`, `endTime`, `dayofweek`, `isActive`, `locationId`, `shiftDuration`, `eventType`, `numberOfPublishers`) -- VALUES -- (2, '2023-12-27 07:00:33.174', '2023-12-27 16:00:33.174', 'Tuesday', 1, 2, 90, 'PW_Cart', 4), -- (3, '2023-12-28 07:00:33.174', '2023-12-28 16:00:33.174', 'Wednesday', 1, 3, 90, 'PW_Cart', 4), diff --git a/server.js b/server.js index bfd1b44..f420718 100644 --- a/server.js +++ b/server.js @@ -259,7 +259,7 @@ nextApp var shifts = await prisma.shift.findMany({ where: { - isactive: true, + isActive: true, startTime: { gte: fromDate, lt: toDate, @@ -410,7 +410,7 @@ nextApp var publishers = await prisma.publisher.findMany({ where: { - isactive: true, + isActive: true, email: { not: "", }, diff --git a/src/helpers/data.js b/src/helpers/data.js index 7c0916b..af888ce 100644 --- a/src/helpers/data.js +++ b/src/helpers/data.js @@ -147,7 +147,7 @@ async function getAvailabilities(userId) { select: { id: true, name: true, - isactive: true, + isActive: true, isFromPreviousAssignment: true, dayofweek: true, dayOfMonth: true, @@ -182,7 +182,7 @@ async function getAvailabilities(userId) { shiftId Int publisher Publisher @relation(fields: [publisherId], references: [id], onDelete: Cascade) publisherId String - isactive Boolean @default(true) + isActive Boolean @default(true) isConfirmed Boolean @default(false) isWithTransport Boolean @default(false) Report Report[] @@ -194,7 +194,7 @@ async function getAvailabilities(userId) { }, select: { id: true, - isTentative: true, + isBySystem: true, isConfirmed: true, isWithTransport: true, shift: { diff --git a/src/helpers/excel.js b/src/helpers/excel.js index 40f2f1c..fd361bc 100644 --- a/src/helpers/excel.js +++ b/src/helpers/excel.js @@ -323,21 +323,21 @@ exports.processEvents = async function (events, year, monthNumber, progressCallb } var shifts = await prisma.shift.findMany({ where: { - isactive: true, + isActive: true, startTime: { gte: monthDatesInfo.firstMonday, lt: monthDatesInfo.lastSunday, }, } }); - var locations = await prisma.location.findMany({ where: { isactive: true, } }); + var locations = await prisma.location.findMany({ where: { isActive: true, } }); - var cartEvents = await prisma.cartEvent.findMany({ where: { isactive: true, } }); + var cartEvents = await prisma.cartEvent.findMany({ where: { isActive: true, } }); var publishers = await prisma.publisher.findMany({ - where: { isactive: true, }, + where: { isActive: true, }, include: { - availabilities: { where: { isactive: true, }, }, + availabilities: { where: { isActive: true, }, }, assignments: { include: { shift: true, }, }, }, }); @@ -472,7 +472,7 @@ exports.processEvents = async function (events, year, monthNumber, progressCallb email: name.toLowerCase().replace(/ /g, "."), // + "@gmail.com" firstName: firstname, lastName: lastname, - isactive: true, + isActive: true, isImported: true, // role: "EXTERNAL", }; @@ -492,7 +492,7 @@ exports.processEvents = async function (events, year, monthNumber, progressCallb // endTime: endTime, // name: `от предишен график, ${publisher.firstName} ${publisher.lastName}`, // isFromPreviousAssignment: true, - // isactive: true, + // isActive: true, // }, // }); // console.log(`Created WEEKLY availability with ID ${availability.id} for date '${date.toDateString()}' and publisher '${publisher.firstName} ${publisher.lastName}'`); diff --git a/src/sql/dev-test.sql b/src/sql/dev-test.sql index d7fe46b..09a3621 100644 --- a/src/sql/dev-test.sql +++ b/src/sql/dev-test.sql @@ -11,7 +11,7 @@ SELECT DISTINCT Publisher.* FROM Publisher INNER JOIN Availability ON Availability.publisherId = Publisher.id WHERE - Availability.isactive = true + Availability.isActive = true AND ( ( Availability.dayOfMonth IS NOT NULL AND Availability.startTime <= '2023-03-30 13:00:00' @@ -30,7 +30,7 @@ SELECT DISTINCT Publisher.* FROM Publisher INNER JOIN Availability ON Availability.publisherId = Publisher.id WHERE - Availability.isactive = true + Availability.isActive = true AND (Availability.dayOfMonth = 5) clfuyo33e005aknvchf1wm3bu All publishers: 121; (118) unique, From 3ccd9ad1064b17b9b5dfd38cc94396195d0e5ec6 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Wed, 27 Mar 2024 09:05:17 +0200 Subject: [PATCH 02/30] schedule is now published to be visible to the public --- pages/api/index.ts | 27 ++++++++++++++++++++++++--- pages/api/schedule.ts | 1 + pages/cart/calendar/index.tsx | 21 ++++++++++++++++++++- pages/cart/publishers/stats.tsx | 9 ++++++++- 4 files changed, 53 insertions(+), 5 deletions(-) diff --git a/pages/api/index.ts b/pages/api/index.ts index 6979920..f5e5d14 100644 --- a/pages/api/index.ts +++ b/pages/api/index.ts @@ -7,6 +7,7 @@ const subq = require('../../prisma/bl/subqueries'); import fs from 'fs'; import path from 'path'; +import { all } from "axios"; /** * @@ -29,7 +30,7 @@ export default async function handler(req, res) { var action = req.query.action; var filter = req.query.filter; - let date: Date; + let date: Date, monthInfo: any; if (req.query.date) { date = new Date(req.query.date); //date.setDate(date.getDate()); // Subtract one day to get the correct date, as calendar sends wrong date (one day ahead) @@ -77,7 +78,7 @@ export default async function handler(req, res) { //gets publisher by names with availabilities and assignments case "deleteAvailabilityForPublisher": let publisherId = req.query.publisherId; - let dateFor, monthInfo; + let dateFor; if (req.query.date) { dateFor = new Date(req.query.date); //get month info from date @@ -212,11 +213,31 @@ export default async function handler(req, res) { case "replaceInAssignment": const { oldPublisherId, newPublisherId, shiftId } = req.method === "POST" ? req.body : req.query; - const prisma = common.getPrismaClient(); + const result = await replaceInAssignment(oldPublisherId, newPublisherId, shiftId); res.status(200).json(result); break; + case "updateShifts": + //get all shifts for the month and publish them (we pass date ) + let monthInfo = common.getMonthDatesInfo(date); + let isPublished = common.parseBool(req.query.isPublished); + let updated = await prisma.shift.updateMany({ + where: { + startTime: { + gte: new Date(monthInfo.firstMonday.getFullYear(), monthInfo.firstMonday.getMonth(), 1), + lt: new Date(monthInfo.lastSunday.getFullYear(), monthInfo.lastSunday.getMonth() + 1, 1), + } + }, + data: { + isPublished: isPublished + } + }); + console.log("Updated shifts: " + updated.count); + res.status(200).json({ "message": "ok" }); + + break; + default: res.status(200).json({ "message": "no action '" + action + "' found" diff --git a/pages/api/schedule.ts b/pages/api/schedule.ts index e322568..087ce81 100644 --- a/pages/api/schedule.ts +++ b/pages/api/schedule.ts @@ -90,6 +90,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const shifts = await prisma.shift.findMany({ where: { isActive: true, + isPublished: true, startTime: { gte: fromDate, lt: toDate, diff --git a/pages/cart/calendar/index.tsx b/pages/cart/calendar/index.tsx index 77b2d4a..f183eb5 100644 --- a/pages/cart/calendar/index.tsx +++ b/pages/cart/calendar/index.tsx @@ -57,7 +57,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) { const [allShifts, setAllShifts] = useState(initialShifts); - const [value, onChange] = useState(new Date()); + const [isPublished, setIsPublished] = useState(() => initialShifts.some(shift => shift.isPublished)); const [value, onChange] = useState(new Date()); const [shifts, setShifts] = React.useState([]); const [error, setError] = React.useState(null); const [availablePubs, setAvailablePubs] = React.useState([]); @@ -108,6 +108,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) { try { const { data: shiftsForDate } = await axiosInstance.get(`/api/?action=getShiftsForDay&date=${dateStr}`); setShifts(shiftsForDate); + setIsPublished(shiftsForDate.some(shift => shift.isPublished)); let { data: availablePubsForDate } = await axiosInstance.get(`/api/?action=filterPublishers&assignments=true&availabilities=true&date=${dateStr}&select=id,firstName,lastName,isActive,desiredShiftsPerMonth`); availablePubsForDate.forEach(pub => { @@ -511,6 +512,18 @@ export default function CalendarPage({ initialEvents, initialShifts }) { } } + const togglePublished = async () => { + try { + const publishState = !isPublished; // Toggle the state + const isPublishedParam = publishState ? 'true' : 'fasle'; + await axiosInstance.get(`/api/?action=updateShifts&isPublished=${isPublishedParam}&date=${common.getISODateOnly(value)}`); + setIsPublished(publishState); // Update state based on the action + + } catch (error) { + console.log(error); + } + } + const [isMenuOpen, setIsMenuOpen] = useState(false); @@ -550,6 +563,12 @@ export default function CalendarPage({ initialEvents, initialShifts }) { }} message="Това ще изпрати имейли до всички участници за смените им през избрания месец. Сигурни ли сте?" /> +
- +
{pub.firstName} {pub.lastName}{pub.firstName} {pub.lastName} {pub.currentMonthAvailabilityDaysCount || 0} | {pub.currentMonthAvailabilityHoursCount || 0} @@ -84,6 +84,13 @@ export const getServerSideProps = async (context) => { publisher.desiredShiftsPerMonth = publisher.desiredShiftsPerMonth || 0; publisher.assignments = publisher.assignments || []; publisher.availabilities = publisher.availabilities || []; + publisher.lastUpdate = publisher.availabilities.reduce((acc, curr) => curr.dateOfEntry > acc ? curr.dateOfEntry : acc, null); + if (publisher.lastUpdate) { + publisher.lastUpdate = common.getDateFormated(publisher.lastUpdate); + } + else { + publisher.lastUpdate = "Няма данни"; + } //serialize dates in publisher.assignments and publisher.availabilities publisher.assignments.forEach(assignment => { if (assignment.shift && assignment.shift.startTime) { From e0dfbc51ecebf68c95b76f146f6315107e050163 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Thu, 28 Mar 2024 18:11:41 +0200 Subject: [PATCH 03/30] new function - copyOldAvailabilities --- pages/api/index.ts | 68 ++++++++++++++++++++++++++++++++ pages/cart/calendar/index.tsx | 8 +++- pages/cart/publishers/import.tsx | 1 + 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/pages/api/index.ts b/pages/api/index.ts index f5e5d14..7e4658f 100644 --- a/pages/api/index.ts +++ b/pages/api/index.ts @@ -210,6 +210,74 @@ export default async function handler(req, res) { res.status(200).json(shiftsForDate); break; + case "copyOldAvailabilities": + //get all publishers that don't have availabilities for the current month + monthInfo = common.getMonthDatesInfo(date); + // await prisma.availability.deleteMany({ + // where: { + // startTime: { + // gte: monthInfo.firstMonday, + // }, + // isFromPreviousMonth: true + // } + // }); + let oldpubs = await prisma.publisher.findMany({ + where: { + availabilities: { + none: { + startTime: { + gte: monthInfo.firstMonday, + } + } + } + }, + select: { + id: true, + firstName: true, + lastName: true, + availabilities: true + } + }); + oldpubs.forEach(async pub => { + console.log("" + pub.firstName + " " + pub.lastName + " copying " + pub.availabilities.length + " availabilities from previous months."); + pub.availabilities.forEach(async avail => { + //get the new date based on the day of week and week of month + let newStart = common.getDateFromWeekNrAndDayOfWeek(avail.weekNr, avail.dayofweek, avail.startTime); + let newEnd = new Date(newStart.getTime()); + newEnd.setHours(avail.endTime.getHours(), avail.endTime.getMinutes(), 0, 0); + await prisma.availability.create({ + data: { + publisherId: pub.id, + dayOfMonth: null, + dayofweek: avail.dayofweek || common.getDayOfWeekNameEnEnum(avail.startTime), + weekOfMonth: avail.weekofMonth || common.getWeekOfMonth(avail.startTime), + dateOfEntry: new Date(), //avail.dateOfEntry || avail.startTime, + startTime: avail.startTime, + endTime: avail.endTime, + weekNr: avail.weekNr, + type: 3, + isFromPreviousMonth: true, + name: avail.name || "старо предпочитание", + } + }); + }); + }); + + //convert old assignments to availabilities + + res.status(200).json({ "message": "ok" }); + break; + case "deleteCopiedAvailabilities": + //delete all availabilities that are copied from previous months + monthInfo = common.getMonthDatesInfo(date); + await prisma.availability.deleteMany({ + where: { + startTime: { + gte: monthInfo.firstMonday, + }, + isFromPreviousMonth: true + } + }); case "replaceInAssignment": const { oldPublisherId, newPublisherId, shiftId } = req.method === "POST" ? req.body : req.query; diff --git a/pages/cart/calendar/index.tsx b/pages/cart/calendar/index.tsx index f183eb5..7a77aec 100644 --- a/pages/cart/calendar/index.tsx +++ b/pages/cart/calendar/index.tsx @@ -57,7 +57,8 @@ export default function CalendarPage({ initialEvents, initialShifts }) { const [allShifts, setAllShifts] = useState(initialShifts); - const [isPublished, setIsPublished] = useState(() => initialShifts.some(shift => shift.isPublished)); const [value, onChange] = useState(new Date()); + const [isPublished, setIsPublished] = useState(() => initialShifts.some(shift => shift.isPublished)); + const [value, onChange] = useState(new Date()); const [shifts, setShifts] = React.useState([]); const [error, setError] = React.useState(null); const [availablePubs, setAvailablePubs] = React.useState([]); @@ -528,6 +529,10 @@ export default function CalendarPage({ initialEvents, initialShifts }) { const [isMenuOpen, setIsMenuOpen] = useState(false); const [isConfirmModalOpen, setConfirmModalOpen] = useState(false); + async function copyOldAvailabilities(event: MouseEvent): Promise { + await axiosInstance.get(`/api/?action=copyOldAvailabilities&date=${common.getISODateOnly(value)}`); + } + return ( <> @@ -610,6 +615,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) { + )} diff --git a/pages/cart/publishers/import.tsx b/pages/cart/publishers/import.tsx index 5ed1e4b..7e10eb7 100644 --- a/pages/cart/publishers/import.tsx +++ b/pages/cart/publishers/import.tsx @@ -136,6 +136,7 @@ export default function ImportPage() { const handleSave = async () => { try { common.logger.debug("handleSave to: " + common.getBaseUrl()); + console.log("handleSave to: " + common.getBaseUrl()); const header = rawData[mode.headerRow]; for (let i = mode.headerRow + 1; i < rawData.length; i++) { //fullData.length; each publisher //update status.info with current publisher From a6b7c62768e606dbf6cc56cf0d77d36c57dbf359 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Thu, 28 Mar 2024 18:12:16 +0200 Subject: [PATCH 04/30] js error log fix --- src/helpers/common.js | 96 ++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 43 deletions(-) diff --git a/src/helpers/common.js b/src/helpers/common.js index 4cc84e7..d706006 100644 --- a/src/helpers/common.js +++ b/src/helpers/common.js @@ -4,8 +4,9 @@ const levenshtein = require('fastest-levenshtein'); -const fs = require("fs"); -const path = require("path"); +const fs = typeof window === 'undefined' ? require('fs') : undefined; +const path = typeof window === 'undefined' ? require('path') : undefined; + const { PrismaClient } = require('@prisma/client'); const DayOfWeek = require("@prisma/client").DayOfWeek; @@ -75,43 +76,42 @@ exports.setBaseUrl = function (req) { }; exports.getBaseUrl = function (relative = "", req = null) { - const filePath = path.join(__dirname, 'baseUrl.txt'); + if (typeof window === 'undefined') { + // Server-side logic + // Read the base URL from env (NEXTAUTH_URL): + return process.env.NEXTAUTH_URL + relative; - try { - if (fs.existsSync(filePath)) { - const baseUrl = fs.readFileSync(filePath, 'utf8').trim(); - const fullUrl = relative ? new URL(relative, baseUrl).toString() : baseUrl; - return fullUrl; - } else { - if (req) { - const baseUrl = exports.setBaseUrl(req); // Correctly reference setBaseUrl - return `${baseUrl}/${relative.replace(/^\/|\/$/g, '')}`; - } - console.log('Base URL file does not exist.'); - return null; - } - } catch (error) { - console.error('Error reading the base URL file:', error); - return null; + // const filePath = path.join(__dirname, 'baseUrl.txt'); + + // try { + // if (fs.existsSync(filePath)) { + // const baseUrl = fs.readFileSync(filePath, 'utf8').trim(); + // const fullUrl = relative ? new URL(relative, baseUrl).toString() : baseUrl; + // return fullUrl; + // } else { + // if (req) { + // // Assuming setBaseUrl is defined somewhere in this file + // const baseUrl = exports.setBaseUrl(req); + // return `${baseUrl}/${relative.replace(/^\/|\/$/g, '')}`; + // } + // console.log('Base URL file does not exist.'); + // return null; + // } + // } catch (error) { + // console.error('Error reading the base URL file:', error); + // return null; + // } + } else { + // Client-side logic + // Fetch the base URL from the server endpoint you've set up + const baseUrl = window.location.origin; + const fullUrl = relative ? `${baseUrl}/${relative.replace(/^\/|\/$/g, '')}` : baseUrl; + //console.log("getBaseUrl()=", fullUrl); + return fullUrl.toString(); } - // const host = process.env.NEXT_PUBLIC_HOST || '127.0.0.1'; - // const port = process.env.NEXT_PUBLIC_PORT ? `:${ process.env.NEXT_PUBLIC_PORT } ` : ''; - // const protocol = process.env.NEXT_PUBLIC_PROTOCOL || "https" - - // //const url = `${ protocol }://${host}${port}/${relative.replace(/^\/|\/$/g, '')}/`; - // const isRelativeEmpty = !relative || relative.trim() === ''; - // const formattedRelative = !isRelativeEmpty ? '/' + relative.replace(/^\/|\/$/g, '') : ''; - // const url = `${protocol}://${host}${port}${formattedRelative}`; - - - // logger.debug("NODE_ENV = ", process.env.NODE_ENV, "protocol:", protocol); - // logger.debug("getBaseURL = ", url); - - // return url; }; - let prisma; exports.getPrismaClient = function getPrismaClient() { if (!prisma) { @@ -228,15 +228,25 @@ exports.getDayOfWeekDate = function (dayOfWeekName, date = new Date()) { return date; }; //common.getWeekOfMonth(date) -// exports.getWeekOfMonth = function (date) { -// // Copy date so don't modify original -// date = new Date(date); -// // Adjust to Monday of this week -// date.setDate(date.getDate() + 3 - (date.getDayEuropean() + 6) % 7); -// // Return week number -// const weekNumber = Math.floor((date.getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000 / 7); -// return weekNumber; -// } +exports.getWeekOfMonth = function (inputDate) { + let date = new Date(inputDate); + let firstDayOfMonth = new Date(date.getFullYear(), date.getMonth(), 1); + let firstMonday = new Date(firstDayOfMonth); + + // Adjust firstDayOfMonth to the first Monday of the month + if (firstDayOfMonth.getDay() === 0) { // Sunday + firstMonday.setDate(2); + } else if (firstDayOfMonth.getDay() !== 1) { // Not Monday + firstMonday.setDate(9 - firstDayOfMonth.getDay()); + } + + // Calculate the difference in days + let diff = (date - firstMonday) / (1000 * 60 * 60 * 24); + // Calculate week number + let weekNumber = Math.ceil((diff + 1) / 7); + + return weekNumber; +}; exports.getMonthDatesInfo = function (date) { // get first day of the month From a26dd954c0b8a8228524b2d8fabcb1f383ab9472 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Thu, 28 Mar 2024 22:55:35 +0200 Subject: [PATCH 05/30] availability serf reference; fix copying last month; --- components/calendar/avcalendar.tsx | 8 ++ pages/api/index.ts | 73 +++++++++++++------ pages/cart/publishers/stats.tsx | 5 ++ .../20240325214807_misc_renames/migration.sql | 14 +++- .../migration.sql | 5 ++ prisma/schema.prisma | 5 +- server.js | 4 +- src/helpers/common.js | 32 +++++++- src/helpers/data.js | 33 +++------ src/helpers/excel.js | 70 +++++++++--------- src/helpers/imports.js | 4 - 11 files changed, 163 insertions(+), 90 deletions(-) create mode 100644 prisma/migrations/20240328162213_add_availability_self_ref/migration.sql delete mode 100644 src/helpers/imports.js diff --git a/components/calendar/avcalendar.tsx b/components/calendar/avcalendar.tsx index c631c72..577c53e 100644 --- a/components/calendar/avcalendar.tsx +++ b/components/calendar/avcalendar.tsx @@ -274,6 +274,11 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => { //if event is not active - show in gray let bgColorClass = 'bg-gray-500'; // Default color for inactive events var bgColor = event.isActive ? "" : "bg-gray-500"; + //ToDo: fix this. maybe we're missing some properties + // if (event.isFromPreviousMonth) { + // // set opacity to 0.5 + // bgColor = "bg-orange-500"; + // } if (event.type === "assignment") { bgColor = event.isBySystem ? "bg-red-500" : (event.isConfirmed ? "bg-green-500" : "bg-yellow-500"); @@ -297,11 +302,14 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => { } } + eventStyle = { ...style, // backgroundColor: bgColorClass, //height: "50px", //color: 'white', + //if (event.isFromPreviousAssignment) { set opacity to 0.5 } + // opacity: event.isFromPreviousMonth ? 0.5 : 1, whiteSpace: 'normal', // Allow the text to wrap to the next line overflow: 'hidden', // Hide overflowed content textOverflow: 'ellipsis' // Add ellipsis to text that's too long to fit diff --git a/pages/api/index.ts b/pages/api/index.ts index 7e4658f..4aa8313 100644 --- a/pages/api/index.ts +++ b/pages/api/index.ts @@ -1,6 +1,6 @@ import { getToken } from "next-auth/jwt"; import { NextApiRequest, NextApiResponse } from 'next' -import { DayOfWeek } from '@prisma/client'; +import { DayOfWeek, AvailabilityType } from '@prisma/client'; const common = require('../../src/helpers/common'); const data = require('../../src/helpers/data'); const subq = require('../../prisma/bl/subqueries'); @@ -221,7 +221,7 @@ export default async function handler(req, res) { // isFromPreviousMonth: true // } // }); - let oldpubs = await prisma.publisher.findMany({ + let outdatedPubs = await prisma.publisher.findMany({ where: { availabilities: { none: { @@ -238,28 +238,55 @@ export default async function handler(req, res) { availabilities: true } }); - oldpubs.forEach(async pub => { + outdatedPubs.forEach(async pub => { + // avail.startTime >= monthInfo.firstMonday + //get prev month date: + let prevMonth = new Date(monthInfo.firstMonday); + prevMonth.setMonth(prevMonth.getMonth() - 1); + let prevMonthInfo = common.getMonthDatesInfo(prevMonth); + pub.availabilities = pub.availabilities.filter(avail => avail.startTime > prevMonthInfo.firstMonday); console.log("" + pub.firstName + " " + pub.lastName + " copying " + pub.availabilities.length + " availabilities from previous months."); pub.availabilities.forEach(async avail => { //get the new date based on the day of week and week of month - let newStart = common.getDateFromWeekNrAndDayOfWeek(avail.weekNr, avail.dayofweek, avail.startTime); + if (!avail.weekOfMonth) { + avail.weekOfMonth = common.getWeekOfMonth(avail.startTime) + } + let origMonthInfo = common.getMonthDatesInfo(avail.startTime); + + let newStart = common.getDateFromWeekNrAndDayOfWeek(monthInfo.firstMonday, avail.weekOfMonth, avail.dayofweek, avail.startTime); + //ToDo: fix double check. also check if we're in 5th week and the month has 4 weeks + // const availability = await data.findPublisherAvailability(publisher.id, newStart); + // if (availability) { + // return; + // } let newEnd = new Date(newStart.getTime()); newEnd.setHours(avail.endTime.getHours(), avail.endTime.getMinutes(), 0, 0); - await prisma.availability.create({ - data: { - publisherId: pub.id, - dayOfMonth: null, - dayofweek: avail.dayofweek || common.getDayOfWeekNameEnEnum(avail.startTime), - weekOfMonth: avail.weekofMonth || common.getWeekOfMonth(avail.startTime), - dateOfEntry: new Date(), //avail.dateOfEntry || avail.startTime, - startTime: avail.startTime, - endTime: avail.endTime, - weekNr: avail.weekNr, - type: 3, - isFromPreviousMonth: true, - name: avail.name || "старо предпочитание", - } - }); + let data = { + publisherId: pub.id, + dayOfMonth: null, + dayofweek: avail.dayofweek || common.getDayOfWeekNameEnEnum(avail.startTime), + weekOfMonth: avail.weekofMonth || common.getWeekOfMonth(avail.startTime), + dateOfEntry: new Date(), //avail.dateOfEntry || avail.startTime, + startTime: newStart, + endTime: newEnd, + type: AvailabilityType.Monthly, + isFromPreviousMonth: true, + name: avail.name || "старо предпочитание", + parentAvailabilityId: avail.id + } + await prisma.availability.create({ data: data }); + + //if month has 5 weeks and the monthInfo has 4 weeks copy the availabilities also from the 1st week to the 5th week + if (monthInfo.nrOfWeeks == 5 && avail.weekOfMonth == 1 && origMonthInfo.nrOfWeeks == 4) { + newStart = common.getDateFromWeekNrAndDayOfWeek(monthInfo.firstMonday, 5, avail.dayofweek, avail.startTime); + newEnd = new Date(newStart.getTime()); + newEnd.setHours(avail.endTime.getHours(), avail.endTime.getMinutes(), 0, 0); + data.weekOfMonth = 5; + data.startTime = newStart; + data.endTime = newEnd; + await prisma.availability.create({ data: data }); + } + }); }); @@ -531,8 +558,8 @@ export async function filterPublishers(selectFields, searchText, filterDate, fet // also, permanent weekly availabilities will have dayOfMonth = null and type = 0 // for 0 we will match by dayOfWeekEnum and times // for 1 we will match by exact date and times - // for 2 we will match by dayofweek, weeknr and times - // for 3 we will match by dayofweek, weeknr and times - this is the same as 2, but we will not count them as availabilities for the current month + // for 2 we will match by dayofweek, weekOfMonth and times + // for 3 we will match by dayofweek, weekOfMonth and times - this is the same as 2, but we will not count them as availabilities for the current month // generaion of schedule: @@ -562,7 +589,7 @@ export async function filterPublishers(selectFields, searchText, filterDate, fet { dayOfMonth: null, dayofweek: dayOfWeekEnum, - // ToDo: and weekNr + // ToDo: and weekOfMonth //startTime: { gte: currentMonthStart }, } ] @@ -614,7 +641,7 @@ export async function filterPublishers(selectFields, searchText, filterDate, fet // dayOfMonth: true, // startTime: true, // endTime: true, - // weekNr: true, + // weekOfMonth: true, // type: true // }, // where: { diff --git a/pages/cart/publishers/stats.tsx b/pages/cart/publishers/stats.tsx index c0161a9..d881b1f 100644 --- a/pages/cart/publishers/stats.tsx +++ b/pages/cart/publishers/stats.tsx @@ -107,8 +107,13 @@ export const getServerSideProps = async (context) => { } } }); + //remove availabilities that isFromPreviousAssignment + publisher.availabilities = publisher.availabilities.filter(availability => !availability.isFromPreviousAssignment); + }); + //remove publishers without availabilities + publishers = publishers.filter(publisher => publisher.availabilities.length > 0); return { props: { diff --git a/prisma/migrations/20240325214807_misc_renames/migration.sql b/prisma/migrations/20240325214807_misc_renames/migration.sql index 2a2f6e7..890be7a 100644 --- a/prisma/migrations/20240325214807_misc_renames/migration.sql +++ b/prisma/migrations/20240325214807_misc_renames/migration.sql @@ -4,12 +4,18 @@ - You are about to drop the column `isTentative` on the `Assignment` table. All the data in the column will be lost. */ + -- AlterTable -ALTER TABLE `Assignment` - ADD COLUMN `isBySystem` BOOLEAN NOT NULL DEFAULT false; +ALTER TABLE `Assignment` + ADD COLUMN `isBySystem` BOOLEAN NOT NULL DEFAULT FALSE; + +-- Depending on your DBMS, you might need to execute one statement at a time. +-- Especially, the UPDATE statement should be run separately. UPDATE `Assignment` SET `isBySystem` = isTentative; -ALTER TABLE `Assignment` DROP COLUMN `isTentative`, +-- Drop the isTentative column +ALTER TABLE `Assignment` DROP COLUMN `isTentative`; -- AlterTable -ALTER TABLE `Report` ADD COLUMN `type` ENUM('ServiceReport', 'Experience', 'Feedback_Problem', 'Feedback_Suggestion', 'Feedback') NOT NULL DEFAULT 'ServiceReport'; +ALTER TABLE `Report` + ADD COLUMN `type` ENUM('ServiceReport', 'Experience', 'Feedback_Problem', 'Feedback_Suggestion', 'Feedback') NOT NULL DEFAULT 'ServiceReport'; diff --git a/prisma/migrations/20240328162213_add_availability_self_ref/migration.sql b/prisma/migrations/20240328162213_add_availability_self_ref/migration.sql new file mode 100644 index 0000000..c2d2a1e --- /dev/null +++ b/prisma/migrations/20240328162213_add_availability_self_ref/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE `availability` ADD COLUMN `parentAvailabilityId` INTEGER NULL; + +-- AddForeignKey +ALTER TABLE `Availability` ADD CONSTRAINT `Availability_parentAvailabilityId_fkey` FOREIGN KEY (`parentAvailabilityId`) REFERENCES `Availability`(`id`) ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 91b56e0..b76fc17 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -141,7 +141,10 @@ model Availability { 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 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 + parentAvailabilityId Int? + parentAvailability Availability? @relation("ParentAvailability", fields: [parentAvailabilityId], references: [id]) + ChildAvailabilities Availability[] @relation("ParentAvailability") } model CartEvent { diff --git a/server.js b/server.js index f420718..324eb33 100644 --- a/server.js +++ b/server.js @@ -84,6 +84,8 @@ nextApp next(); }); server.use("/favicon.ico", express.static("styles/favicon_io/favicon.ico")); + // server.use("/robots.txt", express.static("styles/favicon_io/robots.txt")); + // server.use("/sitemap.xml", express.static("styles/favicon_io/sitemap.xml")); server.get("/last_schedule_json", (req, res) => { // var data = JSON.parse(fs.readFileSync("./content/sources/march_flat.json", "utf8")); @@ -557,7 +559,7 @@ nextApp }); //check if ssl is enabled - if (process.env.SSL_ENABLED === "true") { + if (process.env.SSL_ENABLED === "true" || 1 == 1) { console.log("SSL_ENABLED = true"); // Redirect from http to https // server.use((req, res, next) => { diff --git a/src/helpers/common.js b/src/helpers/common.js index d706006..a72ab2f 100644 --- a/src/helpers/common.js +++ b/src/helpers/common.js @@ -248,6 +248,33 @@ exports.getWeekOfMonth = function (inputDate) { return weekNumber; }; +exports.getDateFromWeekNrAndDayOfWeek = function (firstMonday, weekNr, dayOfWeekEnum, startTime) { + firstMonday = new Date(firstMonday); + startTime = new Date(startTime); + if (!weekNr || weekNr < 1 || weekNr > 5) { + weekNr = this.getWeekOfMonth(startTime); + } + //get int from dayOfWeekEnum + let dayOfWeekNr = this.getDayOfWeekIndex(dayOfWeekEnum); + if (dayOfWeekNr < 0 || dayOfWeekNr > 6) { + dayOfWeekNr = 0; + } + + // Calculate the day offset from the first Monday of the month + // Note: Assuming dayOfWeekEnum starts from 0 (Monday) to 6 (Sunday) + const daysFromFirstMonday = (weekNr - 1) * 7 + dayOfWeekNr; + + // Calculate the new date + let newStart = new Date(firstMonday); + newStart.setDate(firstMonday.getDate() + daysFromFirstMonday); + + // Extract time from startTime and apply it to newStart + const time = new Date(startTime); + newStart.setHours(time.getHours(), time.getMinutes(), time.getSeconds()); + + return newStart; +} + exports.getMonthDatesInfo = function (date) { // get first day of the month var firstDay = new Date(date.getFullYear(), date.getMonth(), 1); @@ -285,6 +312,9 @@ exports.getMonthDatesInfo = function (date) { // lastSunday.setDate(firstDayNextMonth.getDate() - firstDayNextMonth.getDay()); //logger.debug("Last Sunday: ", lastSunday); + const diffInDays = (lastSunday - firstMonday) / (1000 * 60 * 60 * 24); + // Calculate number of weeks, rounding up for partial weeks + const nrOfWeeks = Math.ceil((diffInDays + 1) / 7); return { firstDay: firstDay, @@ -295,7 +325,7 @@ exports.getMonthDatesInfo = function (date) { date: date, monthName: monthName, year: date.getFullYear(), - nrOfWeeks: Math.ceil((lastMonday.getDate() - firstMonday.getDate()) / 7) + nrOfWeeks: nrOfWeeks }; }; exports.getMonthInfo = exports.getMonthDatesInfo; diff --git a/src/helpers/data.js b/src/helpers/data.js index af888ce..dc39ff2 100644 --- a/src/helpers/data.js +++ b/src/helpers/data.js @@ -79,10 +79,7 @@ async function findPublisher(names, email, select, getAll = false) { } async function findPublisherAvailability(publisherId, date) { - const prisma = common.getPrismaClient(); - const dayOfWeek = common.getDayOfWeekNameEnEnum(date); // Assuming common.getDayOfWeekNameEnEnum returns the day of week - //const weekOfMonth = common.getWeekOfMonth(date); // Assuming common.getWeekOfMonth returns the week of month date = new Date(date); // Convert to date object if not already const hours = date.getHours(); const minutes = date.getMinutes(); @@ -90,32 +87,24 @@ async function findPublisherAvailability(publisherId, date) { const potentialAvailabilities = await prisma.availability.findMany({ where: { publisherId: publisherId, - OR: [ + AND: [ // Ensure both conditions must be met { - // Exact date match startTime: { - gte: new Date(date.setHours(0, 0, 0, 0)), - lt: new Date(date.setHours(23, 59, 59, 999)) - } + lte: new Date(date), // startTime is less than or equal to the date + }, }, { - // Correct day of week and before the date, with endDate consideration - dayofweek: dayOfWeek, - OR: [ - { - endDate: null - }, - { - endDate: { - gt: date - } - } - ] - } - ] + endTime: { + gte: new Date(date), // endTime is greater than or equal to the date + }, + }, + ], } }); + if (potentialAvailabilities.length === 0) { + return null; // No availability found + } // Filter the results based on time and other criteria when not exact date match const availability = potentialAvailabilities.find(avail => { const availStartHours = avail.startTime.getHours(); diff --git a/src/helpers/excel.js b/src/helpers/excel.js index fd361bc..30efda8 100644 --- a/src/helpers/excel.js +++ b/src/helpers/excel.js @@ -481,23 +481,22 @@ exports.processEvents = async function (events, year, monthNumber, progressCallb // create availability with the same date as the event. //ToDo: add parameter to control if we want to create availability for each event. can be done whe we import previous shifts. - // if (createAvailabilities) { - // const dayofWeek = common.getDayOfWeekNameEnEnum(date); - // const availability = await prisma.availability.create({ - // data: { - // publisherId: publisher.id, - // //date: date, - // dayofweek: dayofWeek, - // startTime: startTime, - // endTime: endTime, - // name: `от предишен график, ${publisher.firstName} ${publisher.lastName}`, - // isFromPreviousAssignment: true, - // isActive: true, - // }, - // }); - // console.log(`Created WEEKLY availability with ID ${availability.id} for date '${date.toDateString()}' and publisher '${publisher.firstName} ${publisher.lastName}'`); - // } - // const personResponse = await axiosInstance.post("/publishers", manualPub); + if (createAvailabilities) { + const dayofWeek = common.getDayOfWeekNameEnEnum(date); + const availability = await prisma.availability.create({ + data: { + publisherId: publisher.id, + dayofweek: dayofWeek, + startTime: startTime, + endTime: endTime, + name: `от график, ${publisher.firstName} ${publisher.lastName}`, + isFromPreviousAssignment: true, + isActive: true, + }, + }); + console.log(`Created WEEKLY availability with ID ${availability.id} for date '${date.toDateString()}' and publisher '${publisher.firstName} ${publisher.lastName}'`); + } + const personResponse = await axiosInstance.post("/publishers", manualPub); // let personId = personResponse.data.id; } catch (e) { @@ -533,23 +532,26 @@ exports.processEvents = async function (events, year, monthNumber, progressCallb }); //ToDo: fix findPublisherAvailability and creation of availabilities // check if there is an availability for this publisher on this date, and if not, create one - // const availability = await data.findPublisherAvailability(publisher.id, start); - // if (!availability && createAvailabilities) { - // const dayofWeek = common.getDayOfWeekNameEnEnum(date); - // const availability = await prisma.availability.create({ - // data: { - // publisherId: publisher.id, - // //date: date, - // dayofweek: dayofWeek, - // //weekOfMonth: common.getWeekOfMonth(date), - // startTime: start, - // endTime: end, - // name: `от предишен график, ${publisher.firstName} ${publisher.lastName}`, - // isFromPreviousAssignment: true, - // }, - // }); - // console.log(`Created WEEKLY availability with ID ${availability.id} for date '${date.toDateString()}' and publisher '${publisher.firstName} ${publisher.lastName}'`); - // } + //ToDo: check if that works + const availability = await data.findPublisherAvailability(publisher.id, start); + if (!availability && createAvailabilities) { + const dayofWeek = common.getDayOfWeekNameEnEnum(date); + const availability = await prisma.availability.create({ + data: { + publisherId: publisher.id, + //date: date, + dayofweek: dayofWeek, + //weekOfMonth: common.getWeekOfMonth(date), + startTime: start, + endTime: end, + name: `от предишен график, ${publisher.firstName} ${publisher.lastName}`, + isFromPreviousAssignment: true, + isWithTransportIn: isWithTransport && event.shiftNr == 1, + isWithTransportOut: isWithTransport && event.shiftNr > 1, + }, + }); + console.log(`Created SYSTEM availability with ID ${availability.id} for date '${date.toDateString()}' and publisher '${publisher.firstName} ${publisher.lastName}'`); + } console.log(`Created assignment with ID ${assignment.id} for date '${date.toDateString()}' and location '${event.placeOfEvent}'. publisher: ${publisher.firstName} ${publisher.lastName}}`); } diff --git a/src/helpers/imports.js b/src/helpers/imports.js deleted file mode 100644 index a866ff6..0000000 --- a/src/helpers/imports.js +++ /dev/null @@ -1,4 +0,0 @@ -//??? can we consolidate all imports into one file? -import ProtectedRoute from '../../../components/protectedRoute'; -import axiosInstance from '../../../src/axiosSecure'; -import Layout from "../../../components/layout"; \ No newline at end of file From 8350e177df8d87a632cf544cc01f2a78f6f524cb Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Thu, 28 Mar 2024 23:07:12 +0200 Subject: [PATCH 06/30] increment build v --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 90f08fe..fa7b767 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pwwa", - "version": "1.0.1", + "version": "1.1.1", "private": true, "description": "JW PW Web App", "repository": "http://git.d-popov.com/popov/next-cart-app.git", From 838c3ec19674a0e77d1b7f13a629f6218af13831 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Thu, 28 Mar 2024 23:25:59 +0200 Subject: [PATCH 07/30] update packages ; fix SQL migration CASE --- package-lock.json | 68 +++++++++---------- package.json | 6 +- .../migration.sql | 2 +- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/package-lock.json b/package-lock.json index 21a5428..f9dac5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pwwa", - "version": "0.9.9", + "version": "1.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pwwa", - "version": "0.9.9", + "version": "1.1.1", "dependencies": { "@auth/prisma-adapter": "^1.4.0", "@emotion/react": "^11.11.3", @@ -16,7 +16,7 @@ "@mui/material": "^5.15.10", "@mui/x-date-pickers": "^6.19.4", "@premieroctet/next-crud": "^3.0.0", - "@prisma/client": "^5.10.2", + "@prisma/client": "^5.11.0", "@react-pdf/renderer": "^3.3.8", "@tailwindcss/forms": "^0.5.7", "@types/multer": "^1.4.11", @@ -90,7 +90,7 @@ "devDependencies": { "cross-env": "^7.0.3", "depcheck": "^1.4.7", - "prisma": "^5.10.2" + "prisma": "^5.11.0" } }, "node_modules/@alloc/quick-lru": { @@ -2282,9 +2282,9 @@ } }, "node_modules/@prisma/client": { - "version": "5.10.2", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.10.2.tgz", - "integrity": "sha512-ef49hzB2yJZCvM5gFHMxSFL9KYrIP9udpT5rYo0CsHD4P9IKj473MbhU1gjKKftiwWBTIyrt9jukprzZXazyag==", + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.11.0.tgz", + "integrity": "sha512-SWshvS5FDXvgJKM/a0y9nDC1rqd7KG0Q6ZVzd+U7ZXK5soe73DJxJJgbNBt2GNXOa+ysWB4suTpdK5zfFPhwiw==", "hasInstallScript": true, "engines": { "node": ">=16.13" @@ -2299,39 +2299,39 @@ } }, "node_modules/@prisma/debug": { - "version": "5.10.2", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.10.2.tgz", - "integrity": "sha512-bkBOmH9dpEBbMKFJj8V+Zp8IZHIBjy3fSyhLhxj4FmKGb/UBSt9doyfA6k1UeUREsMJft7xgPYBbHSOYBr8XCA==", + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.11.0.tgz", + "integrity": "sha512-N6yYr3AbQqaiUg+OgjkdPp3KPW1vMTAgtKX6+BiB/qB2i1TjLYCrweKcUjzOoRM5BriA4idrkTej9A9QqTfl3A==", "devOptional": true }, "node_modules/@prisma/engines": { - "version": "5.10.2", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.10.2.tgz", - "integrity": "sha512-HkSJvix6PW8YqEEt3zHfCYYJY69CXsNdhU+wna+4Y7EZ+AwzeupMnUThmvaDA7uqswiHkgm5/SZ6/4CStjaGmw==", + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.11.0.tgz", + "integrity": "sha512-gbrpQoBTYWXDRqD+iTYMirDlF9MMlQdxskQXbhARhG6A/uFQjB7DZMYocMQLoiZXO/IskfDOZpPoZE8TBQKtEw==", "devOptional": true, "hasInstallScript": true, "dependencies": { - "@prisma/debug": "5.10.2", - "@prisma/engines-version": "5.10.0-34.5a9203d0590c951969e85a7d07215503f4672eb9", - "@prisma/fetch-engine": "5.10.2", - "@prisma/get-platform": "5.10.2" + "@prisma/debug": "5.11.0", + "@prisma/engines-version": "5.11.0-15.efd2449663b3d73d637ea1fd226bafbcf45b3102", + "@prisma/fetch-engine": "5.11.0", + "@prisma/get-platform": "5.11.0" } }, "node_modules/@prisma/engines-version": { - "version": "5.10.0-34.5a9203d0590c951969e85a7d07215503f4672eb9", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.10.0-34.5a9203d0590c951969e85a7d07215503f4672eb9.tgz", - "integrity": "sha512-uCy/++3Jx/O3ufM+qv2H1L4tOemTNqcP/gyEVOlZqTpBvYJUe0tWtW0y3o2Ueq04mll4aM5X3f6ugQftOSLdFQ==", + "version": "5.11.0-15.efd2449663b3d73d637ea1fd226bafbcf45b3102", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.11.0-15.efd2449663b3d73d637ea1fd226bafbcf45b3102.tgz", + "integrity": "sha512-WXCuyoymvrS4zLz4wQagSsc3/nE6CHy8znyiMv8RKazKymOMd5o9FP5RGwGHAtgoxd+aB/BWqxuP/Ckfu7/3MA==", "devOptional": true }, "node_modules/@prisma/fetch-engine": { - "version": "5.10.2", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.10.2.tgz", - "integrity": "sha512-dSmXcqSt6DpTmMaLQ9K8ZKzVAMH3qwGCmYEZr/uVnzVhxRJ1EbT/w2MMwIdBNq1zT69Rvh0h75WMIi0mrIw7Hg==", + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.11.0.tgz", + "integrity": "sha512-994viazmHTJ1ymzvWugXod7dZ42T2ROeFuH6zHPcUfp/69+6cl5r9u3NFb6bW8lLdNjwLYEVPeu3hWzxpZeC0w==", "devOptional": true, "dependencies": { - "@prisma/debug": "5.10.2", - "@prisma/engines-version": "5.10.0-34.5a9203d0590c951969e85a7d07215503f4672eb9", - "@prisma/get-platform": "5.10.2" + "@prisma/debug": "5.11.0", + "@prisma/engines-version": "5.11.0-15.efd2449663b3d73d637ea1fd226bafbcf45b3102", + "@prisma/get-platform": "5.11.0" } }, "node_modules/@prisma/generator-helper": { @@ -2348,12 +2348,12 @@ "integrity": "sha512-tZ+MOjWlVvz1kOEhNYMa4QUGURY+kgOUBqLHYIV8jmCsMuvA1tWcn7qtIMLzYWCbDcQT4ZS8xDgK0R2gl6/0wA==" }, "node_modules/@prisma/get-platform": { - "version": "5.10.2", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.10.2.tgz", - "integrity": "sha512-nqXP6vHiY2PIsebBAuDeWiUYg8h8mfjBckHh6Jezuwej0QJNnjDiOq30uesmg+JXxGk99nqyG3B7wpcOODzXvg==", + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.11.0.tgz", + "integrity": "sha512-rxtHpMLxNTHxqWuGOLzR2QOyQi79rK1u1XYAVLZxDGTLz/A+uoDnjz9veBFlicrpWjwuieM4N6jcnjj/DDoidw==", "devOptional": true, "dependencies": { - "@prisma/debug": "5.10.2" + "@prisma/debug": "5.11.0" } }, "node_modules/@prisma/internals": { @@ -9294,13 +9294,13 @@ "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==" }, "node_modules/prisma": { - "version": "5.10.2", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.10.2.tgz", - "integrity": "sha512-hqb/JMz9/kymRE25pMWCxkdyhbnIWrq+h7S6WysJpdnCvhstbJSNP/S6mScEcqiB8Qv2F+0R3yG+osRaWqZacQ==", + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.11.0.tgz", + "integrity": "sha512-KCLiug2cs0Je7kGkQBN9jDWoZ90ogE/kvZTUTgz2h94FEo8pczCkPH7fPNXkD1sGU7Yh65risGGD1HQ5DF3r3g==", "devOptional": true, "hasInstallScript": true, "dependencies": { - "@prisma/engines": "5.10.2" + "@prisma/engines": "5.11.0" }, "bin": { "prisma": "build/index.js" diff --git a/package.json b/package.json index fa7b767..296bcf9 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@mui/material": "^5.15.10", "@mui/x-date-pickers": "^6.19.4", "@premieroctet/next-crud": "^3.0.0", - "@prisma/client": "^5.10.2", + "@prisma/client": "^5.11.0", "@react-pdf/renderer": "^3.3.8", "@tailwindcss/forms": "^0.5.7", "@types/multer": "^1.4.11", @@ -107,6 +107,6 @@ "devDependencies": { "cross-env": "^7.0.3", "depcheck": "^1.4.7", - "prisma": "^5.10.2" + "prisma": "^5.11.0" } -} \ No newline at end of file +} diff --git a/prisma/migrations/20240328162213_add_availability_self_ref/migration.sql b/prisma/migrations/20240328162213_add_availability_self_ref/migration.sql index c2d2a1e..bd11572 100644 --- a/prisma/migrations/20240328162213_add_availability_self_ref/migration.sql +++ b/prisma/migrations/20240328162213_add_availability_self_ref/migration.sql @@ -1,5 +1,5 @@ -- AlterTable -ALTER TABLE `availability` ADD COLUMN `parentAvailabilityId` INTEGER NULL; +ALTER TABLE `Availability` ADD COLUMN `parentAvailabilityId` INTEGER NULL; -- AddForeignKey ALTER TABLE `Availability` ADD CONSTRAINT `Availability_parentAvailabilityId_fkey` FOREIGN KEY (`parentAvailabilityId`) REFERENCES `Availability`(`id`) ON DELETE SET NULL ON UPDATE CASCADE; From f145812232cbd64b7804171db72cf78cb9670e4e Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Thu, 28 Mar 2024 23:32:03 +0200 Subject: [PATCH 08/30] revert dev change which went on prod --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index 324eb33..82128dd 100644 --- a/server.js +++ b/server.js @@ -559,7 +559,7 @@ nextApp }); //check if ssl is enabled - if (process.env.SSL_ENABLED === "true" || 1 == 1) { + if (process.env.SSL_ENABLED === "true") { console.log("SSL_ENABLED = true"); // Redirect from http to https // server.use((req, res, next) => { From 89a2b65ff5a54bd9c6dba74cb96d5753f53a0dc7 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Fri, 29 Mar 2024 00:27:38 +0200 Subject: [PATCH 09/30] local dev SSL always on (config not working) --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index 324eb33..82128dd 100644 --- a/server.js +++ b/server.js @@ -559,7 +559,7 @@ nextApp }); //check if ssl is enabled - if (process.env.SSL_ENABLED === "true" || 1 == 1) { + if (process.env.SSL_ENABLED === "true") { console.log("SSL_ENABLED = true"); // Redirect from http to https // server.use((req, res, next) => { From af8a62a5261239b558da53a2af1c4d76398696d7 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Fri, 29 Mar 2024 00:36:22 +0200 Subject: [PATCH 10/30] disable auto availability create as we can import after user entered new availabilities (for now) --- src/helpers/excel.js | 69 ++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/src/helpers/excel.js b/src/helpers/excel.js index 30efda8..4b18578 100644 --- a/src/helpers/excel.js +++ b/src/helpers/excel.js @@ -481,21 +481,22 @@ exports.processEvents = async function (events, year, monthNumber, progressCallb // create availability with the same date as the event. //ToDo: add parameter to control if we want to create availability for each event. can be done whe we import previous shifts. - if (createAvailabilities) { - const dayofWeek = common.getDayOfWeekNameEnEnum(date); - const availability = await prisma.availability.create({ - data: { - publisherId: publisher.id, - dayofweek: dayofWeek, - startTime: startTime, - endTime: endTime, - name: `от график, ${publisher.firstName} ${publisher.lastName}`, - isFromPreviousAssignment: true, - isActive: true, - }, - }); - console.log(`Created WEEKLY availability with ID ${availability.id} for date '${date.toDateString()}' and publisher '${publisher.firstName} ${publisher.lastName}'`); - } + // if (createAvailabilities) { + // const dayofWeek = common.getDayOfWeekNameEnEnum(date); + // const availability = await prisma.availability.create({ + // data: { + // publisherId: publisher.id, + // dayofweek: dayofWeek, + // startTime: startTime, + // endTime: endTime, + // name: `от график, ${publisher.firstName} ${publisher.lastName}`, + // isFromPreviousAssignment: true, + // isActive: true, + // }, + // }); + // console.log(`Created WEEKLY availability with ID ${availability.id} for date '${date.toDateString()}' and publisher '${publisher.firstName} ${publisher.lastName}'`); + // } + const personResponse = await axiosInstance.post("/publishers", manualPub); // let personId = personResponse.data.id; @@ -533,25 +534,25 @@ exports.processEvents = async function (events, year, monthNumber, progressCallb //ToDo: fix findPublisherAvailability and creation of availabilities // check if there is an availability for this publisher on this date, and if not, create one //ToDo: check if that works - const availability = await data.findPublisherAvailability(publisher.id, start); - if (!availability && createAvailabilities) { - const dayofWeek = common.getDayOfWeekNameEnEnum(date); - const availability = await prisma.availability.create({ - data: { - publisherId: publisher.id, - //date: date, - dayofweek: dayofWeek, - //weekOfMonth: common.getWeekOfMonth(date), - startTime: start, - endTime: end, - name: `от предишен график, ${publisher.firstName} ${publisher.lastName}`, - isFromPreviousAssignment: true, - isWithTransportIn: isWithTransport && event.shiftNr == 1, - isWithTransportOut: isWithTransport && event.shiftNr > 1, - }, - }); - console.log(`Created SYSTEM availability with ID ${availability.id} for date '${date.toDateString()}' and publisher '${publisher.firstName} ${publisher.lastName}'`); - } + // const availability = await data.findPublisherAvailability(publisher.id, start); + // if (!availability && createAvailabilities) { + // const dayofWeek = common.getDayOfWeekNameEnEnum(date); + // const availability = await prisma.availability.create({ + // data: { + // publisherId: publisher.id, + // //date: date, + // dayofweek: dayofWeek, + // //weekOfMonth: common.getWeekOfMonth(date), + // startTime: start, + // endTime: end, + // name: `от предишен график, ${publisher.firstName} ${publisher.lastName}`, + // isFromPreviousAssignment: true, + // isWithTransportIn: isWithTransport && event.shiftNr == 1, + // isWithTransportOut: isWithTransport && event.shiftNr > 1, + // }, + // }); + // console.log(`Created SYSTEM availability with ID ${availability.id} for date '${date.toDateString()}' and publisher '${publisher.firstName} ${publisher.lastName}'`); + // } console.log(`Created assignment with ID ${assignment.id} for date '${date.toDateString()}' and location '${event.placeOfEvent}'. publisher: ${publisher.firstName} ${publisher.lastName}}`); } From 40e1136e902bf920ab500dca6a2b911e918b9005 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Sun, 31 Mar 2024 18:39:21 +0300 Subject: [PATCH 11/30] auto copying old availabilities leaves dateOfEntry null --- _doc/ToDo.md | 9 +++++++++ pages/api/index.ts | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/_doc/ToDo.md b/_doc/ToDo.md index ae6c5fd..bd32c11 100644 --- a/_doc/ToDo.md +++ b/_doc/ToDo.md @@ -187,3 +187,12 @@ fix availability repeat checks sometimes delete from mycalendar fails saturday shifts start at 12:00 / dymamic +------------------------------- +Add availability type UNAVAILABLE/ AWAY (like Estelle, Rick, Me) + +why "Александра Чернъшова" seems available every shift thursdays? +fix Time ZONE (currently Z, but it leads to shift when the DST changes ( winter entries are shifter in summer)) +защо Марсел Клайнер е червен четв 11 април? - има предпочитания и е в номата +fix repeating availabilities - Tanq kolcjanova only blue first thursday +add assignment in calendar planner +fix database diff --git a/pages/api/index.ts b/pages/api/index.ts index 4aa8313..624d363 100644 --- a/pages/api/index.ts +++ b/pages/api/index.ts @@ -266,7 +266,8 @@ export default async function handler(req, res) { dayOfMonth: null, dayofweek: avail.dayofweek || common.getDayOfWeekNameEnEnum(avail.startTime), weekOfMonth: avail.weekofMonth || common.getWeekOfMonth(avail.startTime), - dateOfEntry: new Date(), //avail.dateOfEntry || avail.startTime, + // null for auto generated availabilities + //dateOfEntry: new Date(), //avail.dateOfEntry || avail.startTime, startTime: newStart, endTime: newEnd, type: AvailabilityType.Monthly, From e5ba7a33a13036ca359007bfe8220fc7f74441aa Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Sun, 31 Mar 2024 20:17:06 +0300 Subject: [PATCH 12/30] refactor .env usage due to unexpexted env values --- .env | 10 ++++---- .env.demo | 4 ++-- .env.development | 9 +++---- .env.homelab | 37 ----------------------------- .env.production | 4 ++-- .env.test | 17 +++++++------ .vscode/launch.json | 4 ++-- package.json | 4 ++-- pages/api/auth/[...nextauth].ts | 2 +- pages/api/shiftgenerate.ts | 2 +- pages/cart/availabilities/index.tsx | 4 ++-- pages/cart/availabilities/new.tsx | 2 +- pages/cart/calendar/index.tsx | 2 +- pages/cart/cartevents/edit/[id].tsx | 4 ++-- pages/cart/cartevents/new.tsx | 4 ++-- pages/cart/locations/[id].tsx | 4 ++-- pages/cart/locations/edit/[id].tsx | 2 +- pages/cart/locations/new.tsx | 2 +- pages/cart/publishers/edit/[id].tsx | 2 +- pages/cart/publishers/new.tsx | 2 +- pages/cart/reports/experience.tsx | 2 +- pages/cart/reports/report.tsx | 2 +- process.d.ts | 2 +- server.js | 12 ++++++---- src/helpers/common.js | 6 +++-- 25 files changed, 53 insertions(+), 92 deletions(-) delete mode 100644 .env.homelab diff --git a/.env b/.env index 5b30dbb..827cefb 100644 --- a/.env +++ b/.env @@ -1,11 +1,9 @@ #NODE_TLS_REJECT_UNAUTHORIZED='0' -SSL_ENABLED=false -NEXT_PUBLIC_PROTOCOL=https -NEXT_PUBLIC_HOST=localhost -NEXT_PUBLIC_PORT=3003 -NEXTAUTH_URL=https://localhost:3003 -# NEXTAUTH_URL_INTERNAL=http://127.0.0.1:3003 +# SSL_ENABLED=false +# NEXT_PUBLIC_HOST=localhost +# NEXT_PUBLIC_PORT=3003 +# PUBLIC_URL=http://localhost:3003 # Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32 NEXTAUTH_SECRET=ed8a9681efc414df89dfd03cd188ed58 diff --git a/.env.demo b/.env.demo index 17f98ce..02a1a51 100644 --- a/.env.demo +++ b/.env.demo @@ -1,7 +1,7 @@ -NEXT_PUBLIC_PROTOCOL=https +SSL_ENABLED=false NEXT_PUBLIC_PORT= NEXT_PUBLIC_HOST=staging.mwhitnessing.com -NEXTAUTH_URL= https://staging.mwhitnessing.com +PUBLIC_URL=https://staging.mwhitnessing.com # Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32 NEXTAUTH_SECRET=1dd8a5457970d1dda50600be28e935ecc4513ff27c49c431849e6746f158d638 diff --git a/.env.development b/.env.development index afec269..4167c2c 100644 --- a/.env.development +++ b/.env.development @@ -1,15 +1,12 @@ NODE_TLS_REJECT_UNAUTHORIZED=0 # NODE_EXTRA_CA_CERTS=C:\\Users\\popov\\AppData\\Local\\mkcert - -NEXT_PUBLIC_PROTOCOL=https +PROTOCOL=https NEXT_PUBLIC_HOST=localhost NEXT_PUBLIC_PORT=3003 -NEXTAUTH_URL=https://localhost:3003 +PUBLIC_URL=https://localhost:3003 -SSL_ENABLED=true -TELEGRAM_BOT=true SSL_KEY=./certificates/localhost-key.pem SSL_CERT=./certificates/localhost.pem 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 \ No newline at end of file diff --git a/.env.homelab b/.env.homelab deleted file mode 100644 index 2a2aa9a..0000000 --- a/.env.homelab +++ /dev/null @@ -1,37 +0,0 @@ -NODE_TLS_REJECT_UNAUTHORIZED='0' -# DATABASE_URL="file:./src/data/dev.db" -# DATABASE_URL="mysql://root:Zelen0ku4e@192.168.0.10:3306/cart" - -NEXT_PUBLIC_PORT= -# NEXT_PUBLIC_NEXTAUTH_URL=https://cart.d-popov.com -NEXT_PUBLIC_PROTOCOL=https -NEXT_PUBLIC_HOST=cart.d-popov.com -NEXTAUTH_URL=https://cart.d-popov.com -# NEXTAUTH_URL= https://demo.mwhitnessing.com - -# Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32 -NEXTAUTH_SECRET=ed8a9681efc414df89dfd03cd188ed58 -DATABASE_URL=mysql://cart:cart2023@192.168.0.10:3306/cart_demo - -APPLE_ID= -APPLE_TEAM_ID= -APPLE_PRIVATE_KEY= -APPLE_KEY_ID= - -AUTH0_ID=Aa9f3HJowauUrmBVY4iQzQJ7fYsaZDbK -AUTH0_SECRET=_c0O9GkyRXkoWMQW7jNExnl6UoXN6O4oD3mg7NZ_uHVeAinCUtcTAkeQmcKXpZ4x -AUTH0_ISSUER=https://dev-wkzi658ckibr1amv.us.auth0.com - -FACEBOOK_ID= -FACEBOOK_SECRET= - -GITHUB_ID= -GITHUB_SECRET= -# GOOGLE_ID=926212607479-d3m8hm8f8esp3rf1639prskn445sa01v.apps.googleusercontent.com -# GOOGLE_SECRET=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 - -TWITTER_ID= -TWITTER_SECRET= - -EMAIL_SERVER=smtp://8ec69527ff2104:c7bc05f171c96c@smtp.mailtrap.io:2525 -EMAIL_FROM=noreply@example.com diff --git a/.env.production b/.env.production index a3438f2..3f4db06 100644 --- a/.env.production +++ b/.env.production @@ -1,7 +1,7 @@ -NEXT_PUBLIC_PROTOCOL=https NEXT_PUBLIC_PORT= NEXT_PUBLIC_HOST=sofia.mwhitnessing.com -NEXTAUTH_URL= https://sofia.mwhitnessing.com +SSL_ENABLED=false # we're behind a reverse proxy. SSL is handled by the proxy +PUBLIC_URL= https://sofia.mwhitnessing.com # Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32 NEXTAUTH_SECRET=1dd8a5457970d1dda50600be28e935ecc4513ff27c49c431849e6746f158d638 diff --git a/.env.test b/.env.test index 1b9eef8..44c7087 100644 --- a/.env.test +++ b/.env.test @@ -1,13 +1,15 @@ NODE_TLS_REJECT_UNAUTHORIZED='0' +# DATABASE_URL="file:./src/data/dev.db" +# DATABASE_URL="mysql://root:Zelen0ku4e@192.168.0.10:3306/cart" -NEXT_PUBLIC_PORT=5001 -NEXT_PUBLIC_PROTOCOL=https +SSL_ENABLED=true +NEXT_PUBLIC_PORT= NEXT_PUBLIC_HOST=cart.d-popov.com -NEXTAUTH_URL=https://cart.d-popov.com +PUBLIC_URL=https://cart.d-popov.com # Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32 NEXTAUTH_SECRET=ed8a9681efc414df89dfd03cd188ed58 -DATABASE_URL=mysql://cart:cartpw@192.168.0.10:3306/cart_dev +DATABASE_URL=mysql://cart:cart2023@192.168.0.10:3306/cart_demo APPLE_ID= APPLE_TEAM_ID= @@ -23,14 +25,11 @@ FACEBOOK_SECRET= GITHUB_ID= GITHUB_SECRET= -GOOGLE_ID=926212607479-d3m8hm8f8esp3rf1639prskn445sa01v.apps.googleusercontent.com -GOOGLE_SECRET=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 +# GOOGLE_ID=926212607479-d3m8hm8f8esp3rf1639prskn445sa01v.apps.googleusercontent.com +# GOOGLE_SECRET=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 TWITTER_ID= TWITTER_SECRET= EMAIL_SERVER=smtp://8ec69527ff2104:c7bc05f171c96c@smtp.mailtrap.io:2525 EMAIL_FROM=noreply@example.com - -GMAIL_EMAIL_USERNAME= -GMAIL_EMAIL_APP_PASS= diff --git a/.vscode/launch.json b/.vscode/launch.json index b11332d..963bb15 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,7 +6,7 @@ "configurations": [ { "name": "Run npm nodemon (DEV)", - "command": "npm run debug-env", + "command": "npm run debug", "request": "launch", "type": "node-terminal", "preLaunchTask": "killInspector", @@ -35,7 +35,7 @@ "request": "launch", "type": "node-terminal", "cwd": "${workspaceFolder}", - "command": "conda activate node && npm run debug-env", + "command": "conda activate node && npm run debug", }, { "name": "Run conda npm TEST", diff --git a/package.json b/package.json index 296bcf9..ce05476 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "homepage": "https://git.d-popov.com/popov/next-cart-app", "scripts": { "debug": "nodemon --inspect server.js", - "debug-env": "cross-env NODE_ENV=development dotenv -e .env.development -- nodemon --inspect server.js", + "debug-env-dev": "dotenv -e .env.development -- nodemon --inspect server.js", "build": "next build", "buildWin": "npm run build", "start": "next start", @@ -109,4 +109,4 @@ "depcheck": "^1.4.7", "prisma": "^5.11.0" } -} +} \ No newline at end of file diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts index 764362a..e0acd8a 100644 --- a/pages/api/auth/[...nextauth].ts +++ b/pages/api/auth/[...nextauth].ts @@ -24,7 +24,7 @@ import { isLoggedIn, setAuthTokens, clearAuthTokens, getAccessToken, getRefreshT export const authOptions: NextAuthOptions = { // https://next-auth.js.org/configuration/providers/oauth - site: process.env.NEXTAUTH_URL, + site: process.env.PUBLIC_URL, secret: process.env.NEXTAUTH_SECRET, // Ensure you have this set in your .env file //adapter: PrismaAdapter(prisma), providers: [ diff --git a/pages/api/shiftgenerate.ts b/pages/api/shiftgenerate.ts index 4d44052..409d580 100644 --- a/pages/api/shiftgenerate.ts +++ b/pages/api/shiftgenerate.ts @@ -444,7 +444,7 @@ async function GenerateSchedule(axios: Axios, date: string, copyFromPreviousMont } //create shifts using API - // const { data: createdShifts } = await axios.post(`${process.env.NEXTAUTH_URL}/api/data/shifts`, shiftsToCreate); + // const { data: createdShifts } = await axios.post(`${process.env.PUBLIC_URL}/api/data/shifts`, shiftsToCreate); //const { data: allshifts } = await axios.get(`/api/data/shifts`); return {}; //allshifts; diff --git a/pages/cart/availabilities/index.tsx b/pages/cart/availabilities/index.tsx index 0cd158a..23a14c1 100644 --- a/pages/cart/availabilities/index.tsx +++ b/pages/cart/availabilities/index.tsx @@ -133,7 +133,7 @@ export const getServerSideProps = async (context) => { const role = session?.user.role; console.log("server role: " + role); - var queryUrl = process.env.NEXTAUTH_URL + "/api/data/availabilities?select=id,name,isActive,dayofweek,dayOfMonth,startTime,endTime,publisher.firstName,publisher.lastName,publisher.id"; + var queryUrl = process.env.PUBLIC_URL + "/api/data/availabilities?select=id,name,isActive,dayofweek,dayOfMonth,startTime,endTime,publisher.firstName,publisher.lastName,publisher.id"; if (role === UserRole.USER || context.query.my) { queryUrl += `&where={"publisherId":"${session?.user.id}"}`; } else if (role == UserRole.ADMIN) { @@ -145,7 +145,7 @@ export const getServerSideProps = async (context) => { } var resp = await axios.get( queryUrl - // process.env.NEXTAUTH_URL + "/api/data/availabilities?include=publisher", + // process.env.PUBLIC_URL + "/api/data/availabilities?include=publisher", , { decompress: true }); var items = resp.data; console.log("got " + items.length + " availabilities"); diff --git a/pages/cart/availabilities/new.tsx b/pages/cart/availabilities/new.tsx index f281459..e10fd2b 100644 --- a/pages/cart/availabilities/new.tsx +++ b/pages/cart/availabilities/new.tsx @@ -31,7 +31,7 @@ export const getServerSideProps = async (context) => { }; } const { data: item } = await axios.get( - process.env.NEXTAUTH_URL + "/api/data/availabilities/" + context.params.id + process.env.PUBLIC_URL + "/api/data/availabilities/" + context.params.id ); return { diff --git a/pages/cart/calendar/index.tsx b/pages/cart/calendar/index.tsx index 7a77aec..594c22e 100644 --- a/pages/cart/calendar/index.tsx +++ b/pages/cart/calendar/index.tsx @@ -893,7 +893,7 @@ export const getServerSideProps = async (context) => { const axios = await axiosServer(context); const baseUrl = common.getBaseUrl(); console.log('runtime BaseUrl: ' + baseUrl); - console.log('runtime NEXTAUTH_URL: ' + process.env.NEXTAUTH_URL); + console.log('runtime PUBLIC_URL: ' + process.env.PUBLIC_URL); console.log('Runtime Axios Base URL:', axios.defaults.baseURL); const currentDate = new Date(); diff --git a/pages/cart/cartevents/edit/[id].tsx b/pages/cart/cartevents/edit/[id].tsx index 81fca35..08b8428 100644 --- a/pages/cart/cartevents/edit/[id].tsx +++ b/pages/cart/cartevents/edit/[id].tsx @@ -7,9 +7,9 @@ export const getServerSideProps = async (context) => { console.log("edit page getServerSideProps"); const axios = await axiosServer(context); const { id } = context.query; - const { data } = await axios.get(`${process.env.NEXTAUTH_URL}/api/data/cartevents/` + id); + const { data } = await axios.get(`${process.env.PUBLIC_URL}/api/data/cartevents/` + id); const locations = await axios - .get(`${process.env.NEXTAUTH_URL}/api/data/locations?select=id,name`) + .get(`${process.env.PUBLIC_URL}/api/data/locations?select=id,name`) .then((res) => { console.log("locations: " + JSON.stringify(res.data)); return res.data; diff --git a/pages/cart/cartevents/new.tsx b/pages/cart/cartevents/new.tsx index 0503430..522f489 100644 --- a/pages/cart/cartevents/new.tsx +++ b/pages/cart/cartevents/new.tsx @@ -26,7 +26,7 @@ export const getServerSideProps = async (context) => { const axios = await axiosServer(context); const locations = await axios - .get(`${process.env.NEXTAUTH_URL}/api/data/locations?select=id,name`) + .get(`${process.env.PUBLIC_URL}/api/data/locations?select=id,name`) .then((res) => { console.log("locations: " + JSON.stringify(res.data)); return res.data; @@ -41,7 +41,7 @@ export const getServerSideProps = async (context) => { const { id } = context.query.id; const { data: item } = await axiosInstance.get( - process.env.NEXTAUTH_URL + "/api/data/cartevents/" + context.params.id + process.env.PUBLIC_URL + "/api/data/cartevents/" + context.params.id ); return { diff --git a/pages/cart/locations/[id].tsx b/pages/cart/locations/[id].tsx index f66a6bc..523478b 100644 --- a/pages/cart/locations/[id].tsx +++ b/pages/cart/locations/[id].tsx @@ -99,11 +99,11 @@ export const getServerSideProps: GetServerSideProps = async (context) => { const axios = await axiosServer(context); const { data: location } = await axios.get( - `${process.env.NEXTAUTH_URL}/api/data/locations/${context.params.id}` + `${process.env.PUBLIC_URL}/api/data/locations/${context.params.id}` ); if (location.backupLocationId !== null) { const { data: backupLocation } = await axios.get( - process.env.NEXTAUTH_URL + "/api/data/locations/" + location.backupLocationId + process.env.PUBLIC_URL + "/api/data/locations/" + location.backupLocationId ); location.backupLocationName = backupLocation.name; location.backupLocationContent = backupLocation ? backupLocation.content : ""; diff --git a/pages/cart/locations/edit/[id].tsx b/pages/cart/locations/edit/[id].tsx index ef1b7b8..90ba81f 100644 --- a/pages/cart/locations/edit/[id].tsx +++ b/pages/cart/locations/edit/[id].tsx @@ -29,7 +29,7 @@ export const getServerSideProps = async (context) => { }; } const { data: item } = await axios.get( - process.env.NEXTAUTH_URL + "/api/data/locations/" + context.params.id + process.env.PUBLIC_URL + "/api/data/locations/" + context.params.id ); console.log(item) //this is the location object context.res.setHeader("Cache-Control", "s-maxage=1, stale-while-revalidate"); diff --git a/pages/cart/locations/new.tsx b/pages/cart/locations/new.tsx index be77ea0..e1c7137 100644 --- a/pages/cart/locations/new.tsx +++ b/pages/cart/locations/new.tsx @@ -32,7 +32,7 @@ export const getServerSideProps = async (context) => { } const { data: loc } = await axios.get( - `${process.env.NEXTAUTH_URL}api/data/locations/` + context.params.id + `${process.env.PUBLIC_URL}api/data/locations/` + context.params.id ); console.log(location) //this is the location object context.res.setHeader("Cache-Control", "s-maxage=1, stale-while-revalidate"); diff --git a/pages/cart/publishers/edit/[id].tsx b/pages/cart/publishers/edit/[id].tsx index 680fb41..484910f 100644 --- a/pages/cart/publishers/edit/[id].tsx +++ b/pages/cart/publishers/edit/[id].tsx @@ -44,7 +44,7 @@ export const getServerSideProps = async (context) => { props: {} }; } - var url = process.env.NEXTAUTH_URL + "/api/data/publishers/" + context.query.id + "?include=availabilities,assignments,assignments.shift"; + var url = process.env.PUBLIC_URL + "/api/data/publishers/" + context.query.id + "?include=availabilities,assignments,assignments.shift"; console.log("GET PUBLISHER FROM:" + url) const { data: item } = await axios.get(url); diff --git a/pages/cart/publishers/new.tsx b/pages/cart/publishers/new.tsx index fb99ae4..f9f62fb 100644 --- a/pages/cart/publishers/new.tsx +++ b/pages/cart/publishers/new.tsx @@ -47,7 +47,7 @@ export const getServerSideProps = async (context) => { props: {} }; } - var url = process.env.NEXTAUTH_URL + "/api/data/publishers/" + context.query.id + "?include=availabilities,shifts"; + var url = process.env.PUBLIC_URL + "/api/data/publishers/" + context.query.id + "?include=availabilities,shifts"; console.log("GET PUBLISHER FROM:" + url) const { data } = await axios.get(url); diff --git a/pages/cart/reports/experience.tsx b/pages/cart/reports/experience.tsx index 5cb4db8..c41079a 100644 --- a/pages/cart/reports/experience.tsx +++ b/pages/cart/reports/experience.tsx @@ -32,7 +32,7 @@ export const getServerSideProps = async (context) => { // }; // } // const { data: loc } = await axiosInstance.get( - // `${process.env.NEXTAUTH_URL}api/data/locations/` + context.params.id + // `${process.env.PUBLIC_URL}api/data/locations/` + context.params.id // ); // console.log(location) //this is the location object diff --git a/pages/cart/reports/report.tsx b/pages/cart/reports/report.tsx index ef3b971..b416704 100644 --- a/pages/cart/reports/report.tsx +++ b/pages/cart/reports/report.tsx @@ -33,7 +33,7 @@ export const getServerSideProps = async (context) => { // } // const { data: loc } = await axiosInstance.get( - // `${process.env.NEXTAUTH_URL}api/data/locations/` + context.params.id + // `${process.env.PUBLIC_URL}api/data/locations/` + context.params.id // ); // console.log(location) //this is the location object // context.res.setHeader("Cache-Control", "s-maxage=1, stale-while-revalidate"); diff --git a/process.d.ts b/process.d.ts index b140ecb..b31f4de 100644 --- a/process.d.ts +++ b/process.d.ts @@ -1,6 +1,6 @@ declare namespace NodeJS { export interface ProcessEnv { - NEXTAUTH_URL: string + PUBLIC_URL: string NEXTAUTH_SECRET: string GITHUB_ID: string GITHUB_SECRET: string diff --git a/server.js b/server.js index 82128dd..61eb531 100644 --- a/server.js +++ b/server.js @@ -28,21 +28,23 @@ let baseUrlGlobal; // require('dotenv').config(); // } -console.log("initial process.env.NODE_ENV = ", process.env.NODE_ENV); +console.log("initial process.env.NODE_ENV = ", process.env.NODE_ENV); //NODE_ENV can be passed as docker param require('dotenv').config({ path: `.env.${process.env.NODE_ENV}` }); console.log("process.env.NODE_ENV = ", process.env.NODE_ENV); +const PROTOCOL = process.env.PROTOCOL; const PORT = process.env.NEXT_PUBLIC_PORT || 3000; const HOST = process.env.NEXT_PUBLIC_HOST; +const LOAD_CERTS = process.env.PROTOCOL === 'https'; + const dev = process.env.NODE_ENV !== "production"; -const PROTOCOL = process.env.NEXT_PUBLIC_PROTOCOL; const nextApp = next({ dev }); const nextHandler = nextApp.getRequestHandler(); -console.log("process.env.SSL_ENABLED = ", process.env.SSL_ENABLED); -console.log("process.env.NEXTAUTH_URL = ", process.env.NEXTAUTH_URL); +console.log("process.env.PROTOCOL = ", process.env.PROTOCOL); +console.log("process.env.PUBLIC_URL = ", process.env.PUBLIC_URL); console.log("process.env.NEXT_PUBLIC_PORT = ", process.env.NEXT_PUBLIC_PORT); console.log("process.env.TELEGRAM_BOT = ", process.env.TELEGRAM_BOT); @@ -559,7 +561,7 @@ nextApp }); //check if ssl is enabled - if (process.env.SSL_ENABLED === "true") { + if (LOAD_CERTS) { console.log("SSL_ENABLED = true"); // Redirect from http to https // server.use((req, res, next) => { diff --git a/src/helpers/common.js b/src/helpers/common.js index a72ab2f..288f906 100644 --- a/src/helpers/common.js +++ b/src/helpers/common.js @@ -78,8 +78,8 @@ exports.setBaseUrl = function (req) { exports.getBaseUrl = function (relative = "", req = null) { if (typeof window === 'undefined') { // Server-side logic - // Read the base URL from env (NEXTAUTH_URL): - return process.env.NEXTAUTH_URL + relative; + // Read the base URL from env (PUBLIC_URL): + return process.env.PUBLIC_URL + relative; // const filePath = path.join(__dirname, 'baseUrl.txt'); @@ -122,6 +122,8 @@ exports.getPrismaClient = function getPrismaClient() { datasources: { db: { url: process.env.DATABASE_URL } }, }); } + logger.debug("getPrismaClient: process.env.DATABASE_URL = ", process.env.DATABASE_URL); + return prisma; } From d47297e2f7d998788f2f18ec6a89b5dbc2fb6fe7 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Mon, 1 Apr 2024 09:50:28 +0300 Subject: [PATCH 13/30] more ENV refactoring --- .env.development | 2 +- next.config.js | 2 +- server.js | 57 ++++++++++++++++++++++++------------------------ 3 files changed, 30 insertions(+), 31 deletions(-) diff --git a/.env.development b/.env.development index 4167c2c..9204bc9 100644 --- a/.env.development +++ b/.env.development @@ -1,6 +1,6 @@ NODE_TLS_REJECT_UNAUTHORIZED=0 # NODE_EXTRA_CA_CERTS=C:\\Users\\popov\\AppData\\Local\\mkcert -PROTOCOL=https +NEXT_PUBLIC_PROTOCOL=https NEXT_PUBLIC_HOST=localhost NEXT_PUBLIC_PORT=3003 PUBLIC_URL=https://localhost:3003 diff --git a/next.config.js b/next.config.js index 2bc690b..865380e 100644 --- a/next.config.js +++ b/next.config.js @@ -12,7 +12,7 @@ module.exports = { pageExtensions: ['ts', 'tsx', 'md', 'mdx'], // Replace `jsx?` with `tsx?` env: { env: process.env.NODE_ENV, - server: 'http://' + process.env.NEXT_PUBLIC_HOST + ':' + process.env.NEXT_PUBLIC_PORT + '', + server: process.env.NEXT_PUBLIC_PROTOCOL + '://' + process.env.NEXT_PUBLIC_HOST + ':' + process.env.NEXT_PUBLIC_PORT + '', }, webpack(config, { isServer }) { diff --git a/server.js b/server.js index 61eb531..21637f2 100644 --- a/server.js +++ b/server.js @@ -35,15 +35,14 @@ require('dotenv').config({ console.log("process.env.NODE_ENV = ", process.env.NODE_ENV); -const PROTOCOL = process.env.PROTOCOL; +const PROTOCOL = process.env.NEXT_PUBLIC_PROTOCOL; const PORT = process.env.NEXT_PUBLIC_PORT || 3000; const HOST = process.env.NEXT_PUBLIC_HOST; -const LOAD_CERTS = process.env.PROTOCOL === 'https'; const dev = process.env.NODE_ENV !== "production"; const nextApp = next({ dev }); const nextHandler = nextApp.getRequestHandler(); -console.log("process.env.PROTOCOL = ", process.env.PROTOCOL); +console.log("process.env.NEXT_PUBLIC_PROTOCOL = ", process.env.NEXT_PUBLIC_PROTOCOL); console.log("process.env.PUBLIC_URL = ", process.env.PUBLIC_URL); console.log("process.env.NEXT_PUBLIC_PORT = ", process.env.NEXT_PUBLIC_PORT); console.log("process.env.TELEGRAM_BOT = ", process.env.TELEGRAM_BOT); @@ -64,12 +63,37 @@ const uploadTmp = multer({ storage: storageMem }); const prisma = common.getPrismaClient(); +const server = express(); +//check if ssl is enabled +if (process.env.NEXT_PUBLIC_PROTOCOL === 'https') { + console.log("SSL_ENABLED = true"); + // Redirect from http to https + // server.use((req, res, next) => { + // if (req.headers['x-forwarded-proto'] !== 'https') { + // return res.redirect(`https://${req.headers.host}${req.url}`); + // } + // next(); + // }); + if (process.env.SSL_KEY && process.env.SSL_CERT) { + const options = { + key: fs.readFileSync(process.env.SSL_KEY), + cert: fs.readFileSync(process.env.SSL_CERT), + secureProtocol: 'TLSv1_2_method', // Example: Force TLS 1.2 + }; + https.createServer(options, server).listen(PORT); + } +} +else { + server.listen(PORT, (err) => { + if (err) throw err; + console.log(`> Ready on ${PROTOCOL}://${HOST}:${PORT}`); + }); +} // handlers nextApp .prepare() .then(() => { - const server = express(); // Add the middleware to set 'x-forwarded-host' header server.use((req, res, next) => { @@ -560,31 +584,6 @@ nextApp return nextHandler(req, res); }); - //check if ssl is enabled - if (LOAD_CERTS) { - console.log("SSL_ENABLED = true"); - // Redirect from http to https - // server.use((req, res, next) => { - // if (req.headers['x-forwarded-proto'] !== 'https') { - // return res.redirect(`https://${req.headers.host}${req.url}`); - // } - // next(); - // }); - if (process.env.SSL_KEY && process.env.SSL_CERT) { - const options = { - key: fs.readFileSync(process.env.SSL_KEY), - cert: fs.readFileSync(process.env.SSL_CERT), - secureProtocol: 'TLSv1_2_method', // Example: Force TLS 1.2 - }; - https.createServer(options, server).listen(PORT); - } - } - else { - server.listen(PORT, (err) => { - if (err) throw err; - console.log(`> Ready on ${PROTOCOL}://${HOST}:${PORT}`); - }); - } }) .catch((ex) => { console.warn(`Error starting server on ${HOST}:${PORT}`) From f83a3e9bd918572a1ee4f380b5c51752b5387556 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Mon, 1 Apr 2024 11:11:23 +0300 Subject: [PATCH 14/30] staging has standard test environment now --- .env.development | 2 +- .env.test | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/.env.development b/.env.development index 9204bc9..8029d98 100644 --- a/.env.development +++ b/.env.development @@ -1,8 +1,8 @@ NODE_TLS_REJECT_UNAUTHORIZED=0 # NODE_EXTRA_CA_CERTS=C:\\Users\\popov\\AppData\\Local\\mkcert NEXT_PUBLIC_PROTOCOL=https -NEXT_PUBLIC_HOST=localhost NEXT_PUBLIC_PORT=3003 +NEXT_PUBLIC_HOST=localhost PUBLIC_URL=https://localhost:3003 SSL_KEY=./certificates/localhost-key.pem diff --git a/.env.test b/.env.test index 44c7087..78ba247 100644 --- a/.env.test +++ b/.env.test @@ -1,15 +1,12 @@ -NODE_TLS_REJECT_UNAUTHORIZED='0' -# DATABASE_URL="file:./src/data/dev.db" -# DATABASE_URL="mysql://root:Zelen0ku4e@192.168.0.10:3306/cart" - -SSL_ENABLED=true +NEXT_PUBLIC_PROTOCOL=http NEXT_PUBLIC_PORT= -NEXT_PUBLIC_HOST=cart.d-popov.com -PUBLIC_URL=https://cart.d-popov.com +NEXT_PUBLIC_HOST=staging.mwhitnessing.com +PUBLIC_URL=https://staging.mwhitnessing.com # Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32 -NEXTAUTH_SECRET=ed8a9681efc414df89dfd03cd188ed58 -DATABASE_URL=mysql://cart:cart2023@192.168.0.10:3306/cart_demo +NEXTAUTH_SECRET=1dd8a5457970d1dda50600be28e935ecc4513ff27c49c431849e6746f158d638 +# ? do we need to duplicate this? already defined in the deoployment yml file +DATABASE_URL=mysql://jwpwsofia_demo:dwxhns9p9vp248@mariadb:3306/jwpwsofia_demo APPLE_ID= APPLE_TEAM_ID= From f488fa971a2e360959fa28aa7236a16b6efdba37 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Mon, 1 Apr 2024 11:12:00 +0300 Subject: [PATCH 15/30] fix and simplify baseurl --- .env | 8 +++----- .env.demo | 9 --------- .env.development | 8 ++++---- .env.production | 8 ++++---- .env.test | 8 ++++---- next.config.js | 2 +- server.js | 14 +++++++------- src/helpers/common.js | 34 +--------------------------------- 8 files changed, 24 insertions(+), 67 deletions(-) delete mode 100644 .env.demo diff --git a/.env b/.env index 827cefb..eec3b83 100644 --- a/.env +++ b/.env @@ -1,9 +1,7 @@ - #NODE_TLS_REJECT_UNAUTHORIZED='0' -# SSL_ENABLED=false -# NEXT_PUBLIC_HOST=localhost -# NEXT_PUBLIC_PORT=3003 -# PUBLIC_URL=http://localhost:3003 +# HOST=localhost +# PORT=3003 +# NEXT_PUBLIC_PUBLIC_URL=http://localhost:3003 # Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32 NEXTAUTH_SECRET=ed8a9681efc414df89dfd03cd188ed58 diff --git a/.env.demo b/.env.demo deleted file mode 100644 index 02a1a51..0000000 --- a/.env.demo +++ /dev/null @@ -1,9 +0,0 @@ -SSL_ENABLED=false -NEXT_PUBLIC_PORT= -NEXT_PUBLIC_HOST=staging.mwhitnessing.com -PUBLIC_URL=https://staging.mwhitnessing.com - -# Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32 -NEXTAUTH_SECRET=1dd8a5457970d1dda50600be28e935ecc4513ff27c49c431849e6746f158d638 -# ? do we need to duplicate this? already defined in the deoployment yml file -DATABASE_URL=mysql://jwpwsofia_demo:dwxhns9p9vp248@mariadb:3306/jwpwsofia_demo \ No newline at end of file diff --git a/.env.development b/.env.development index 8029d98..21fcc42 100644 --- a/.env.development +++ b/.env.development @@ -1,9 +1,9 @@ NODE_TLS_REJECT_UNAUTHORIZED=0 # NODE_EXTRA_CA_CERTS=C:\\Users\\popov\\AppData\\Local\\mkcert -NEXT_PUBLIC_PROTOCOL=https -NEXT_PUBLIC_PORT=3003 -NEXT_PUBLIC_HOST=localhost -PUBLIC_URL=https://localhost:3003 +PROTOCOL=https +PORT=3003 +HOST=localhost +NEXT_PUBLIC_PUBLIC_URL=https://localhost:3003 SSL_KEY=./certificates/localhost-key.pem SSL_CERT=./certificates/localhost.pem diff --git a/.env.production b/.env.production index 3f4db06..8f9c4eb 100644 --- a/.env.production +++ b/.env.production @@ -1,7 +1,7 @@ -NEXT_PUBLIC_PORT= -NEXT_PUBLIC_HOST=sofia.mwhitnessing.com -SSL_ENABLED=false # we're behind a reverse proxy. SSL is handled by the proxy -PUBLIC_URL= https://sofia.mwhitnessing.com +PORT= +HOST=sofia.mwhitnessing.com +PROTOCOL=http # we're behind a reverse proxy. SSL is handled by the proxy +NEXT_PUBLIC_PUBLIC_URL= https://sofia.mwhitnessing.com # Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32 NEXTAUTH_SECRET=1dd8a5457970d1dda50600be28e935ecc4513ff27c49c431849e6746f158d638 diff --git a/.env.test b/.env.test index 78ba247..0fbca9e 100644 --- a/.env.test +++ b/.env.test @@ -1,7 +1,7 @@ -NEXT_PUBLIC_PROTOCOL=http -NEXT_PUBLIC_PORT= -NEXT_PUBLIC_HOST=staging.mwhitnessing.com -PUBLIC_URL=https://staging.mwhitnessing.com +PROTOCOL=http +HOST=staging.mwhitnessing.com +PORT= +NEXT_PUBLIC_PUBLIC_URL=https://staging.mwhitnessing.com # Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32 NEXTAUTH_SECRET=1dd8a5457970d1dda50600be28e935ecc4513ff27c49c431849e6746f158d638 diff --git a/next.config.js b/next.config.js index 865380e..32d4f12 100644 --- a/next.config.js +++ b/next.config.js @@ -12,7 +12,7 @@ module.exports = { pageExtensions: ['ts', 'tsx', 'md', 'mdx'], // Replace `jsx?` with `tsx?` env: { env: process.env.NODE_ENV, - server: process.env.NEXT_PUBLIC_PROTOCOL + '://' + process.env.NEXT_PUBLIC_HOST + ':' + process.env.NEXT_PUBLIC_PORT + '', + server: process.env.NEXT_PUBLIC_PUBLIC_URL }, webpack(config, { isServer }) { diff --git a/server.js b/server.js index 21637f2..c48323b 100644 --- a/server.js +++ b/server.js @@ -35,16 +35,16 @@ require('dotenv').config({ console.log("process.env.NODE_ENV = ", process.env.NODE_ENV); -const PROTOCOL = process.env.NEXT_PUBLIC_PROTOCOL; -const PORT = process.env.NEXT_PUBLIC_PORT || 3000; -const HOST = process.env.NEXT_PUBLIC_HOST; +const PROTOCOL = process.env.PROTOCOL; +const PORT = process.env.PORT || 3000; +const HOST = process.env.HOST; const dev = process.env.NODE_ENV !== "production"; const nextApp = next({ dev }); const nextHandler = nextApp.getRequestHandler(); -console.log("process.env.NEXT_PUBLIC_PROTOCOL = ", process.env.NEXT_PUBLIC_PROTOCOL); -console.log("process.env.PUBLIC_URL = ", process.env.PUBLIC_URL); -console.log("process.env.NEXT_PUBLIC_PORT = ", process.env.NEXT_PUBLIC_PORT); +console.log("process.env.PROTOCOL = ", process.env.PROTOCOL); +console.log("process.env.PUBLIC_URL = ", process.env.NEXT_PUBLIC_PUBLIC_URL); +console.log("process.env.PORT = ", process.env.PORT); console.log("process.env.TELEGRAM_BOT = ", process.env.TELEGRAM_BOT); //require('module-alias/register'); @@ -66,7 +66,7 @@ const prisma = common.getPrismaClient(); const server = express(); //check if ssl is enabled -if (process.env.NEXT_PUBLIC_PROTOCOL === 'https') { +if (process.env.PROTOCOL === 'https') { console.log("SSL_ENABLED = true"); // Redirect from http to https // server.use((req, res, next) => { diff --git a/src/helpers/common.js b/src/helpers/common.js index 288f906..e580a4b 100644 --- a/src/helpers/common.js +++ b/src/helpers/common.js @@ -76,39 +76,7 @@ exports.setBaseUrl = function (req) { }; exports.getBaseUrl = function (relative = "", req = null) { - if (typeof window === 'undefined') { - // Server-side logic - // Read the base URL from env (PUBLIC_URL): - return process.env.PUBLIC_URL + relative; - - // const filePath = path.join(__dirname, 'baseUrl.txt'); - - // try { - // if (fs.existsSync(filePath)) { - // const baseUrl = fs.readFileSync(filePath, 'utf8').trim(); - // const fullUrl = relative ? new URL(relative, baseUrl).toString() : baseUrl; - // return fullUrl; - // } else { - // if (req) { - // // Assuming setBaseUrl is defined somewhere in this file - // const baseUrl = exports.setBaseUrl(req); - // return `${baseUrl}/${relative.replace(/^\/|\/$/g, '')}`; - // } - // console.log('Base URL file does not exist.'); - // return null; - // } - // } catch (error) { - // console.error('Error reading the base URL file:', error); - // return null; - // } - } else { - // Client-side logic - // Fetch the base URL from the server endpoint you've set up - const baseUrl = window.location.origin; - const fullUrl = relative ? `${baseUrl}/${relative.replace(/^\/|\/$/g, '')}` : baseUrl; - //console.log("getBaseUrl()=", fullUrl); - return fullUrl.toString(); - } + return process.env.NEXT_PUBLIC_PUBLIC_URL + relative; }; From 5a658d4e19c615aff33a22953e26331f69cb8d50 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Mon, 1 Apr 2024 13:05:35 +0300 Subject: [PATCH 16/30] fix availability ui bug --- components/availability/AvailabilityForm.js | 58 ++++++++++++------- .../AvailabilityFormDatePicker.js | 4 +- pages/api/index.ts | 10 +++- 3 files changed, 49 insertions(+), 23 deletions(-) diff --git a/components/availability/AvailabilityForm.js b/components/availability/AvailabilityForm.js index 19d09a4..868ccc1 100644 --- a/components/availability/AvailabilityForm.js +++ b/components/availability/AvailabilityForm.js @@ -1,5 +1,5 @@ import axiosInstance from '../../src/axiosSecure'; -import { useEffect, useState, useCallback } from "react"; +import { useEffect, useState, useCallback, use } from "react"; import toast from "react-hot-toast"; import { useRouter } from "next/router"; import { DatePicker } from '@mui/x-date-pickers/DatePicker'; @@ -26,9 +26,6 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o const [editMode, setEditMode] = useState(existingItems.length > 0); const [publisher, setPublisher] = useState({ id: publisherId }); const [day, setDay] = useState(new Date(date)); - const [doRepeat, setDoRepeat] = useState(false); - const [repeatFrequency, setRepeatFrequency] = useState(1); - const [repeatUntil, setRepeatUntil] = useState(null); const [canUpdate, setCanUpdate] = useState(true); const [timeSlots, setTimeSlots] = useState([]); @@ -46,6 +43,10 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o isLast: false, }]); + const [doRepeat, setDoRepeat] = useState(existingItems && existingItems.length > 0 ? existingItems[0].repeatWeekly : false); + const [repeatFrequency, setRepeatFrequency] = useState(1); + const [repeatUntil, setRepeatUntil] = useState(null); + const [isInline, setInline] = useState(inline || false); const [config, setConfig] = useState(null); useEffect(() => { @@ -69,6 +70,7 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o const response = await axiosInstance.get(`/api/data/availabilities/${id}`); setAvailabilities([response.data]); setEditMode(true); + setDoRepeat(response.data.repeatWeekly); } catch (error) { console.error(error); toast.error("Error fetching availability data."); @@ -202,10 +204,24 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o availability.isWithTransportIn = group[0].isFirst && timeSlots[0].isWithTransport; availability.isWithTransportOut = group[group.length - 1].isLast && timeSlots[timeSlots.length - 1].isWithTransport; - availability.repeatWeekly = doRepeat; - availability.dayOfMonth = doRepeat ? null : availability.startTime.getDate(); - availability.endDate = doRepeat ? repeatUntil : null; + delete availability.weekOfMonth; + if (doRepeat) { + availability.repeatWeekly = true; + availability.dayOfMonth = null; + availability.weekOfMonth = 0; + availability.endDate = repeatUntil; + } else { + availability.repeatWeekly = false; + availability.dayOfMonth = availability.startTime.getDate(); + availability.endDate = null; + } + availability.dateOfEntry = new Date(); + if (availability.parentAvailabilityId) { + availability.parentAvailability = { connect: { id: parentAvailabilityId } }; + } + delete availability.parentAvailabilityId; + return availability; } @@ -288,8 +304,7 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o const TimeSlotCheckboxes = ({ slots, setSlots, items: [] }) => { - const [allDay, setAllDay] = useState(false); - + const [allDay, setAllDay] = useState(slots.every(slot => slot.isChecked)); const handleAllDayChange = (e) => { const updatedSlots = slots.map(slot => ({ ...slot, @@ -297,7 +312,9 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o })); setSlots(updatedSlots); setAllDay(e.target.checked) - setCanUpdate(true); + // setCanUpdate(slots.some(slot => slot.isChecked)); + const anyChecked = updatedSlots.some(slot => slot.isChecked); + setCanUpdate(anyChecked); console.log("handleAllDayChange: allDay: " + allDay + ", updatedSlots: " + JSON.stringify(updatedSlots)); }; useEffect(() => { @@ -352,9 +369,9 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o return (
-
*/ } - {/* + {/* Телеграм Телеграм */} From 1e1c4888d870984e9766ed99ce15f1fd4b2cc1b5 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 2 Apr 2024 01:42:54 +0300 Subject: [PATCH 22/30] email related publisher settings: data model --- prisma/schema.prisma | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index b76fc17..1faea21 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -106,20 +106,21 @@ model Publisher { userId String? @unique user User? @relation(fields: [userId], references: [id]) - role UserRole @default(USER) - desiredShiftsPerMonth Int @default(4) - isMale Boolean @default(true) - isNameForeign Boolean @default(false) - - familyHeadId String? // Optional familyHeadId for each family member - familyHead Publisher? @relation("FamilyMember", fields: [familyHeadId], references: [id]) - familyMembers Publisher[] @relation("FamilyMember") - alwaysAsFamily Boolean? @default(false) //NEW v1.0.1 // New field to indicate if the publisher always wants to be assigned with the family - type PublisherType @default(Publisher) - town String? - comments String? - reports Report[] - Message Message[] + role UserRole @default(USER) + desiredShiftsPerMonth Int @default(4) + isMale Boolean @default(true) + isNameForeign Boolean @default(false) + isSubscribedToCoverMe Boolean @default(false) + isSubscribedToReminders Boolean @default(false) + familyHeadId String? // Optional familyHeadId for each family member + familyHead Publisher? @relation("FamilyMember", fields: [familyHeadId], references: [id]) + familyMembers Publisher[] @relation("FamilyMember") + alwaysAsFamily Boolean? @default(false) //NEW v1.0.1 // New field to indicate if the publisher always wants to be assigned with the family + type PublisherType @default(Publisher) + town String? + comments String? + reports Report[] + Message Message[] } model Availability { From 31ad2bf9976451d02b3cc2defe1c4589ba9a5b92 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 2 Apr 2024 01:51:00 +0300 Subject: [PATCH 23/30] typos --- .env.test | 4 ++-- _deploy/deoloy.azure.demo.yml | 2 +- _deploy/deoloy.azure.production.yml | 2 +- _deploy/entrypoint.sh | 2 +- pages/api/auth/[...nextauth].ts | 2 +- pages/api/index.ts | 1 + 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.env.test b/.env.test index 0fbca9e..2e62731 100644 --- a/.env.test +++ b/.env.test @@ -1,7 +1,7 @@ PROTOCOL=http -HOST=staging.mwhitnessing.com +HOST=staging.mwitnessing.com PORT= -NEXT_PUBLIC_PUBLIC_URL=https://staging.mwhitnessing.com +NEXT_PUBLIC_PUBLIC_URL=https://staging.mwitnessing.com # Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32 NEXTAUTH_SECRET=1dd8a5457970d1dda50600be28e935ecc4513ff27c49c431849e6746f158d638 diff --git a/_deploy/deoloy.azure.demo.yml b/_deploy/deoloy.azure.demo.yml index 924858a..d81bbbb 100644 --- a/_deploy/deoloy.azure.demo.yml +++ b/_deploy/deoloy.azure.demo.yml @@ -1,6 +1,6 @@ version: "3" services: - nextjs-app: # https://sofia.mwhitnessing.com/ + nextjs-app: # https://sofia.mwitnessing.com/ hostname: jwpw-app-staging # jwpw-nextjs-app-1 image: docker.d-popov.com/jwpw:latest volumes: diff --git a/_deploy/deoloy.azure.production.yml b/_deploy/deoloy.azure.production.yml index 1ebca74..d653294 100644 --- a/_deploy/deoloy.azure.production.yml +++ b/_deploy/deoloy.azure.production.yml @@ -1,6 +1,6 @@ version: "3" services: - nextjs-app: # https://sofia.mwhitnessing.com/ + nextjs-app: # https://sofia.mwitnessing.com/ hostname: jwpw-app # jwpw-nextjs-app-1 image: docker.d-popov.com/jwpw:latest deploy: diff --git a/_deploy/entrypoint.sh b/_deploy/entrypoint.sh index 8a7d603..f0ea095 100644 --- a/_deploy/entrypoint.sh +++ b/_deploy/entrypoint.sh @@ -10,7 +10,7 @@ if [ "$UPDATE_CODE_FROM_GIT" = "true" ]; then mkdir /tmp/clone # Clone the repository - git clone -b ${GIT_BRANCH:-main} --depth 1 https://$GIT_USERNAME:${GIT_PASSWORD//@/%40}@git.d-popov.com/popov/mwhitnessing.git /tmp/clone || exit 1 + git clone -b ${GIT_BRANCH:-main} --depth 1 https://$GIT_USERNAME:${GIT_PASSWORD//@/%40}@git.d-popov.com/popov/mwitnessing.git /tmp/clone || exit 1 # Synchronize all files except package.json and package-lock.json to /app rsync -av --delete --exclude 'package.json' --exclude 'package-lock.json' /tmp/clone/ /app/ || echo "Rsync failed: Issue synchronizing files" diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts index e0acd8a..675ea24 100644 --- a/pages/api/auth/[...nextauth].ts +++ b/pages/api/auth/[...nextauth].ts @@ -29,7 +29,7 @@ export const authOptions: NextAuthOptions = { //adapter: PrismaAdapter(prisma), providers: [ // register new URL at https://console.cloud.google.com/apis/credentials/oauthclient/926212607479-d3m8hm8f8esp3rf1639prskn445sa01v.apps.googleusercontent.com?project=grand-forge-108716 - //Request details: redirect_uri=http://20.101.62.76:8005/api/auth/callback/google https://s.mwhitnessing.com/ + //Request details: redirect_uri=http://20.101.62.76:8005/api/auth/callback/google https://s.mwitnessingmwitnessing.com/ GoogleProvider({ clientId: process.env.GOOGLE_ID, clientSecret: process.env.GOOGLE_SECRET, diff --git a/pages/api/index.ts b/pages/api/index.ts index a6ee908..42f47c6 100644 --- a/pages/api/index.ts +++ b/pages/api/index.ts @@ -617,6 +617,7 @@ export async function filterPublishers(selectFields, searchText, filterDate, fet dayOfMonth: null, dayofweek: dayOfWeekEnum, } + ] } }; } From 8117a74a092897c1b407918b3e5d1c17933a0721 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 2 Apr 2024 02:04:45 +0300 Subject: [PATCH 24/30] rename PUBLIC_URL to NEXT_PUBLIC_PUBLIC_URL --- pages/api/auth/[...nextauth].ts | 2 +- pages/api/shiftgenerate.ts | 2 +- pages/cart/availabilities/index.tsx | 4 ++-- pages/cart/availabilities/new.tsx | 2 +- pages/cart/calendar/index.tsx | 6 +++--- pages/cart/cartevents/edit/[id].tsx | 4 ++-- pages/cart/cartevents/new.tsx | 4 ++-- pages/cart/locations/[id].tsx | 4 ++-- pages/cart/locations/edit/[id].tsx | 2 +- pages/cart/locations/new.tsx | 2 +- pages/cart/publishers/edit/[id].tsx | 2 +- pages/cart/publishers/new.tsx | 2 +- pages/cart/reports/experience.tsx | 2 +- pages/cart/reports/report.tsx | 2 +- server.js | 2 +- 15 files changed, 21 insertions(+), 21 deletions(-) diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts index 675ea24..ce77c0b 100644 --- a/pages/api/auth/[...nextauth].ts +++ b/pages/api/auth/[...nextauth].ts @@ -24,7 +24,7 @@ import { isLoggedIn, setAuthTokens, clearAuthTokens, getAccessToken, getRefreshT export const authOptions: NextAuthOptions = { // https://next-auth.js.org/configuration/providers/oauth - site: process.env.PUBLIC_URL, + site: process.env.NEXT_PUBLIC_PUBLIC_URL, secret: process.env.NEXTAUTH_SECRET, // Ensure you have this set in your .env file //adapter: PrismaAdapter(prisma), providers: [ diff --git a/pages/api/shiftgenerate.ts b/pages/api/shiftgenerate.ts index 409d580..f0137f6 100644 --- a/pages/api/shiftgenerate.ts +++ b/pages/api/shiftgenerate.ts @@ -444,7 +444,7 @@ async function GenerateSchedule(axios: Axios, date: string, copyFromPreviousMont } //create shifts using API - // const { data: createdShifts } = await axios.post(`${process.env.PUBLIC_URL}/api/data/shifts`, shiftsToCreate); + // const { data: createdShifts } = await axios.post(`${process.env.NEXT_PUBLIC_PUBLIC_URL}/api/data/shifts`, shiftsToCreate); //const { data: allshifts } = await axios.get(`/api/data/shifts`); return {}; //allshifts; diff --git a/pages/cart/availabilities/index.tsx b/pages/cart/availabilities/index.tsx index 23a14c1..2f44dc3 100644 --- a/pages/cart/availabilities/index.tsx +++ b/pages/cart/availabilities/index.tsx @@ -133,7 +133,7 @@ export const getServerSideProps = async (context) => { const role = session?.user.role; console.log("server role: " + role); - var queryUrl = process.env.PUBLIC_URL + "/api/data/availabilities?select=id,name,isActive,dayofweek,dayOfMonth,startTime,endTime,publisher.firstName,publisher.lastName,publisher.id"; + var queryUrl = process.env.NEXT_PUBLIC_PUBLIC_URL + "/api/data/availabilities?select=id,name,isActive,dayofweek,dayOfMonth,startTime,endTime,publisher.firstName,publisher.lastName,publisher.id"; if (role === UserRole.USER || context.query.my) { queryUrl += `&where={"publisherId":"${session?.user.id}"}`; } else if (role == UserRole.ADMIN) { @@ -145,7 +145,7 @@ export const getServerSideProps = async (context) => { } var resp = await axios.get( queryUrl - // process.env.PUBLIC_URL + "/api/data/availabilities?include=publisher", + // process.env.NEXT_PUBLIC_PUBLIC_URL + "/api/data/availabilities?include=publisher", , { decompress: true }); var items = resp.data; console.log("got " + items.length + " availabilities"); diff --git a/pages/cart/availabilities/new.tsx b/pages/cart/availabilities/new.tsx index e10fd2b..06a91b7 100644 --- a/pages/cart/availabilities/new.tsx +++ b/pages/cart/availabilities/new.tsx @@ -31,7 +31,7 @@ export const getServerSideProps = async (context) => { }; } const { data: item } = await axios.get( - process.env.PUBLIC_URL + "/api/data/availabilities/" + context.params.id + process.env.NEXT_PUBLIC_PUBLIC_URL + "/api/data/availabilities/" + context.params.id ); return { diff --git a/pages/cart/calendar/index.tsx b/pages/cart/calendar/index.tsx index 594c22e..5bb9269 100644 --- a/pages/cart/calendar/index.tsx +++ b/pages/cart/calendar/index.tsx @@ -891,9 +891,9 @@ import axiosServer from '../../../src/axiosServer'; import { start } from 'repl'; export const getServerSideProps = async (context) => { const axios = await axiosServer(context); - const baseUrl = common.getBaseUrl(); - console.log('runtime BaseUrl: ' + baseUrl); - console.log('runtime PUBLIC_URL: ' + process.env.PUBLIC_URL); + // const baseUrl = common.getBaseUrl(); + // console.log('runtime BaseUrl: ' + baseUrl); + console.log('runtime NEXT_PUBLIC_PUBLIC_URL: ' + process.env.NEXT_PUBLIC_PUBLIC_URL); console.log('Runtime Axios Base URL:', axios.defaults.baseURL); const currentDate = new Date(); diff --git a/pages/cart/cartevents/edit/[id].tsx b/pages/cart/cartevents/edit/[id].tsx index 08b8428..689c487 100644 --- a/pages/cart/cartevents/edit/[id].tsx +++ b/pages/cart/cartevents/edit/[id].tsx @@ -7,9 +7,9 @@ export const getServerSideProps = async (context) => { console.log("edit page getServerSideProps"); const axios = await axiosServer(context); const { id } = context.query; - const { data } = await axios.get(`${process.env.PUBLIC_URL}/api/data/cartevents/` + id); + const { data } = await axios.get(`${process.env.NEXT_PUBLIC_PUBLIC_URL}/api/data/cartevents/` + id); const locations = await axios - .get(`${process.env.PUBLIC_URL}/api/data/locations?select=id,name`) + .get(`${process.env.NEXT_PUBLIC_PUBLIC_URL}/api/data/locations?select=id,name`) .then((res) => { console.log("locations: " + JSON.stringify(res.data)); return res.data; diff --git a/pages/cart/cartevents/new.tsx b/pages/cart/cartevents/new.tsx index 522f489..0e098f6 100644 --- a/pages/cart/cartevents/new.tsx +++ b/pages/cart/cartevents/new.tsx @@ -26,7 +26,7 @@ export const getServerSideProps = async (context) => { const axios = await axiosServer(context); const locations = await axios - .get(`${process.env.PUBLIC_URL}/api/data/locations?select=id,name`) + .get(`${process.env.NEXT_PUBLIC_PUBLIC_URL}/api/data/locations?select=id,name`) .then((res) => { console.log("locations: " + JSON.stringify(res.data)); return res.data; @@ -41,7 +41,7 @@ export const getServerSideProps = async (context) => { const { id } = context.query.id; const { data: item } = await axiosInstance.get( - process.env.PUBLIC_URL + "/api/data/cartevents/" + context.params.id + process.env.NEXT_PUBLIC_PUBLIC_URL + "/api/data/cartevents/" + context.params.id ); return { diff --git a/pages/cart/locations/[id].tsx b/pages/cart/locations/[id].tsx index 523478b..c66f338 100644 --- a/pages/cart/locations/[id].tsx +++ b/pages/cart/locations/[id].tsx @@ -99,11 +99,11 @@ export const getServerSideProps: GetServerSideProps = async (context) => { const axios = await axiosServer(context); const { data: location } = await axios.get( - `${process.env.PUBLIC_URL}/api/data/locations/${context.params.id}` + `${process.env.NEXT_PUBLIC_PUBLIC_URL}/api/data/locations/${context.params.id}` ); if (location.backupLocationId !== null) { const { data: backupLocation } = await axios.get( - process.env.PUBLIC_URL + "/api/data/locations/" + location.backupLocationId + process.env.NEXT_PUBLIC_PUBLIC_URL + "/api/data/locations/" + location.backupLocationId ); location.backupLocationName = backupLocation.name; location.backupLocationContent = backupLocation ? backupLocation.content : ""; diff --git a/pages/cart/locations/edit/[id].tsx b/pages/cart/locations/edit/[id].tsx index 90ba81f..a48f89a 100644 --- a/pages/cart/locations/edit/[id].tsx +++ b/pages/cart/locations/edit/[id].tsx @@ -29,7 +29,7 @@ export const getServerSideProps = async (context) => { }; } const { data: item } = await axios.get( - process.env.PUBLIC_URL + "/api/data/locations/" + context.params.id + process.env.NEXT_PUBLIC_PUBLIC_URL + "/api/data/locations/" + context.params.id ); console.log(item) //this is the location object context.res.setHeader("Cache-Control", "s-maxage=1, stale-while-revalidate"); diff --git a/pages/cart/locations/new.tsx b/pages/cart/locations/new.tsx index e1c7137..a76cf0a 100644 --- a/pages/cart/locations/new.tsx +++ b/pages/cart/locations/new.tsx @@ -32,7 +32,7 @@ export const getServerSideProps = async (context) => { } const { data: loc } = await axios.get( - `${process.env.PUBLIC_URL}api/data/locations/` + context.params.id + `${process.env.NEXT_PUBLIC_PUBLIC_URL}api/data/locations/` + context.params.id ); console.log(location) //this is the location object context.res.setHeader("Cache-Control", "s-maxage=1, stale-while-revalidate"); diff --git a/pages/cart/publishers/edit/[id].tsx b/pages/cart/publishers/edit/[id].tsx index 484910f..0e93b9a 100644 --- a/pages/cart/publishers/edit/[id].tsx +++ b/pages/cart/publishers/edit/[id].tsx @@ -44,7 +44,7 @@ export const getServerSideProps = async (context) => { props: {} }; } - var url = process.env.PUBLIC_URL + "/api/data/publishers/" + context.query.id + "?include=availabilities,assignments,assignments.shift"; + var url = process.env.NEXT_PUBLIC_PUBLIC_URL + "/api/data/publishers/" + context.query.id + "?include=availabilities,assignments,assignments.shift"; console.log("GET PUBLISHER FROM:" + url) const { data: item } = await axios.get(url); diff --git a/pages/cart/publishers/new.tsx b/pages/cart/publishers/new.tsx index f9f62fb..c0b1988 100644 --- a/pages/cart/publishers/new.tsx +++ b/pages/cart/publishers/new.tsx @@ -47,7 +47,7 @@ export const getServerSideProps = async (context) => { props: {} }; } - var url = process.env.PUBLIC_URL + "/api/data/publishers/" + context.query.id + "?include=availabilities,shifts"; + var url = process.env.NEXT_PUBLIC_PUBLIC_URL + "/api/data/publishers/" + context.query.id + "?include=availabilities,shifts"; console.log("GET PUBLISHER FROM:" + url) const { data } = await axios.get(url); diff --git a/pages/cart/reports/experience.tsx b/pages/cart/reports/experience.tsx index c41079a..9e4df08 100644 --- a/pages/cart/reports/experience.tsx +++ b/pages/cart/reports/experience.tsx @@ -32,7 +32,7 @@ export const getServerSideProps = async (context) => { // }; // } // const { data: loc } = await axiosInstance.get( - // `${process.env.PUBLIC_URL}api/data/locations/` + context.params.id + // `${process.env.NEXT_PUBLIC_PUBLIC_URL}api/data/locations/` + context.params.id // ); // console.log(location) //this is the location object diff --git a/pages/cart/reports/report.tsx b/pages/cart/reports/report.tsx index b416704..8c7bcff 100644 --- a/pages/cart/reports/report.tsx +++ b/pages/cart/reports/report.tsx @@ -33,7 +33,7 @@ export const getServerSideProps = async (context) => { // } // const { data: loc } = await axiosInstance.get( - // `${process.env.PUBLIC_URL}api/data/locations/` + context.params.id + // `${process.env.NEXT_PUBLIC_PUBLIC_URL}api/data/locations/` + context.params.id // ); // console.log(location) //this is the location object // context.res.setHeader("Cache-Control", "s-maxage=1, stale-while-revalidate"); diff --git a/server.js b/server.js index c48323b..9c355ab 100644 --- a/server.js +++ b/server.js @@ -43,7 +43,7 @@ const dev = process.env.NODE_ENV !== "production"; const nextApp = next({ dev }); const nextHandler = nextApp.getRequestHandler(); console.log("process.env.PROTOCOL = ", process.env.PROTOCOL); -console.log("process.env.PUBLIC_URL = ", process.env.NEXT_PUBLIC_PUBLIC_URL); +console.log("process.env.NEXT_PUBLIC_PUBLIC_URL = ", process.env.NEXT_PUBLIC_PUBLIC_URL); console.log("process.env.PORT = ", process.env.PORT); console.log("process.env.TELEGRAM_BOT = ", process.env.TELEGRAM_BOT); From 78ea5937e135ec052596247c6c9c341fed57b6ce Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 2 Apr 2024 02:12:59 +0300 Subject: [PATCH 25/30] new migration: add_publisher_email_sbscription_options --- .../migration.sql | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 prisma/migrations/20240401231200_add_publisher_email_sbscription_options/migration.sql diff --git a/prisma/migrations/20240401231200_add_publisher_email_sbscription_options/migration.sql b/prisma/migrations/20240401231200_add_publisher_email_sbscription_options/migration.sql new file mode 100644 index 0000000..1e84220 --- /dev/null +++ b/prisma/migrations/20240401231200_add_publisher_email_sbscription_options/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE `publisher` ADD COLUMN `isSubscribedToCoverMe` BOOLEAN NOT NULL DEFAULT false, + ADD COLUMN `isSubscribedToReminders` BOOLEAN NOT NULL DEFAULT false; From 647f0d1ee19e3c04036fe157818e39aeae9814a0 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 2 Apr 2024 02:28:35 +0300 Subject: [PATCH 26/30] define NEXTAUTH_URL required by next-auth in node startup file --- server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server.js b/server.js index 9c355ab..30fbd44 100644 --- a/server.js +++ b/server.js @@ -44,6 +44,7 @@ const nextApp = next({ dev }); const nextHandler = nextApp.getRequestHandler(); console.log("process.env.PROTOCOL = ", process.env.PROTOCOL); console.log("process.env.NEXT_PUBLIC_PUBLIC_URL = ", process.env.NEXT_PUBLIC_PUBLIC_URL); +process.env.NEXTAUTH_URL = process.env.NEXT_PUBLIC_PUBLIC_URL; //NEXTAUTH_URL mandatory for next-auth console.log("process.env.PORT = ", process.env.PORT); console.log("process.env.TELEGRAM_BOT = ", process.env.TELEGRAM_BOT); From 655f5ba9c65aeb3a3c4ffb39c412c3dc46e22613 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 2 Apr 2024 02:33:15 +0300 Subject: [PATCH 27/30] logs --- server.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index 30fbd44..8e3982c 100644 --- a/server.js +++ b/server.js @@ -43,8 +43,9 @@ const dev = process.env.NODE_ENV !== "production"; const nextApp = next({ dev }); const nextHandler = nextApp.getRequestHandler(); console.log("process.env.PROTOCOL = ", process.env.PROTOCOL); -console.log("process.env.NEXT_PUBLIC_PUBLIC_URL = ", process.env.NEXT_PUBLIC_PUBLIC_URL); process.env.NEXTAUTH_URL = process.env.NEXT_PUBLIC_PUBLIC_URL; //NEXTAUTH_URL mandatory for next-auth +console.log("process.env.NEXT_PUBLIC_PUBLIC_URL = ", process.env.NEXT_PUBLIC_PUBLIC_URL); +console.log("process.env.NEXTAUTH_URL = ", process.env.NEXTAUTH_URL); console.log("process.env.PORT = ", process.env.PORT); console.log("process.env.TELEGRAM_BOT = ", process.env.TELEGRAM_BOT); From 63d0ab868732ec973f3a96707344d06dba4366d6 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 2 Apr 2024 10:42:37 +0300 Subject: [PATCH 28/30] fix migration CamelCase --- pages/_app.tsx | 2 +- .../migration.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/_app.tsx b/pages/_app.tsx index e89920c..6538651 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -35,7 +35,7 @@ export default function App({ rel="stylesheet" /> - + diff --git a/prisma/migrations/20240401231200_add_publisher_email_sbscription_options/migration.sql b/prisma/migrations/20240401231200_add_publisher_email_sbscription_options/migration.sql index 1e84220..e7f91bc 100644 --- a/prisma/migrations/20240401231200_add_publisher_email_sbscription_options/migration.sql +++ b/prisma/migrations/20240401231200_add_publisher_email_sbscription_options/migration.sql @@ -1,3 +1,3 @@ -- AlterTable -ALTER TABLE `publisher` ADD COLUMN `isSubscribedToCoverMe` BOOLEAN NOT NULL DEFAULT false, +ALTER TABLE `Publisher` ADD COLUMN `isSubscribedToCoverMe` BOOLEAN NOT NULL DEFAULT false, ADD COLUMN `isSubscribedToReminders` BOOLEAN NOT NULL DEFAULT false; From 4aebc8a45df933088eb7eb921598f27eef06417c Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Thu, 4 Apr 2024 00:02:03 +0300 Subject: [PATCH 29/30] fix calenar UI bug --- components/availability/AvailabilityForm.js | 21 ++++++++++++--------- components/calendar/avcalendar.tsx | 9 ++++++++- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/components/availability/AvailabilityForm.js b/components/availability/AvailabilityForm.js index 868ccc1..a24f2af 100644 --- a/components/availability/AvailabilityForm.js +++ b/components/availability/AvailabilityForm.js @@ -87,27 +87,29 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o e.preventDefault(); try { const groupedTimeSlots = mergeCheckedTimeSlots(timeSlots); - + let avs = availabilities.filter(av => av.type !== "assignment"); // Determine if we need to delete and recreate, or just update - const shouldRecreate = availabilities.length !== groupedTimeSlots.length || availabilities.some(av => !av.id); - + let shouldRecreate = avs.length > 0 && avs.length !== groupedTimeSlots.length || avs.some(av => !av.id); + shouldRecreate = shouldRecreate || ( avs.length == 0 && availabilities.length > 0); + //create availability if we open a form with assignment without availability + if (shouldRecreate) { // Delete existing availabilities if they have an ID console.log("Recreating availabilities"); - await Promise.all(availabilities.filter(av => av.id).map(av => axiosInstance.delete(`${urls.apiUrl}${av.id}`))); + await Promise.all(avs.filter(av => av.id).map(av => axiosInstance.delete(`${urls.apiUrl}${av.id}`))); // Create new availabilities - const createdAvailabilities = await Promise.all(groupedTimeSlots.map(async group => { + avs = await Promise.all(groupedTimeSlots.map(async group => { const newAvailability = createAvailabilityFromGroup(group, publisher.id); const response = await axiosInstance.post(urls.apiUrl, newAvailability); return response.data; // Assuming the new availability is returned })); - setAvailabilities(createdAvailabilities); + setAvailabilities(avs); } else { // Update existing availabilities console.log("Updating existing availabilities"); - const updatedAvailabilities = await Promise.all(availabilities.map(async (availability, index) => { + avs = await Promise.all(avs.map(async (availability, index) => { const group = groupedTimeSlots[index]; const id = availability.id; const updatedAvailability = updateAvailabilityFromGroup(availability, group); @@ -121,7 +123,7 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o return updatedAvailability; })); - setAvailabilities(updatedAvailabilities); + setAvailabilities(avs); } handleCompletion({ updated: true }); @@ -228,7 +230,8 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o const handleDelete = async (e) => { e.preventDefault(); try { - const deletePromises = availabilities.map(async (availability) => { + let avs = availabilities.filter(av => av.type !== "assignment"); + const deletePromises = avs.map(async (availability) => { if (availability.id) { // console.log("deleting publisher id = ", router.query.id, "; url=" + urls.apiUrl + router.query.id); await axiosInstance.delete(urls.apiUrl + availability.id); diff --git a/components/calendar/avcalendar.tsx b/components/calendar/avcalendar.tsx index 577c53e..5403f1f 100644 --- a/components/calendar/avcalendar.tsx +++ b/components/calendar/avcalendar.tsx @@ -56,7 +56,14 @@ const AvCalendar = ({ publisherId, events, selectedDate }) => { // Update internal state when `events` prop changes useEffect(() => { - const updatedEvents = events.map(event => ({ + //if we have isBySystem - set type to assignment + let updatedEvents = events.map(event => { + if (event.isBySystem) { + event.type = "assignment"; + } + return event; + }); + updatedEvents = events.map(event => ({ ...event, date: new Date(event.startTime).setHours(0, 0, 0, 0), startTime: new Date(event.startTime), From 1584d122a3416cef7b77ba2d7bbc01e828fcf5a5 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Thu, 4 Apr 2024 00:02:21 +0300 Subject: [PATCH 30/30] apple id script --- _deploy/appleKey.p8 | 6 ++++++ _deploy/appleKey_modified.p8 | 1 + _deploy/setupAppleId.mjs | 9 +++++++-- 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 _deploy/appleKey.p8 create mode 100644 _deploy/appleKey_modified.p8 diff --git a/_deploy/appleKey.p8 b/_deploy/appleKey.p8 new file mode 100644 index 0000000..4c686a8 --- /dev/null +++ b/_deploy/appleKey.p8 @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgL3WoWMr7zzqtZdF/ +wNEJ9+yMP2qNJV305gTdF+++hLOgCgYIKoZIzj0DAQehRANCAATqlUN+GE7/r8UQ +c93hRG9UxCtBcJEcgSGwYVPtZvA5igUBxY/6+RO/Tcnq9xT/6PZD0A82vMNSjoJ6 +/KyhaFLl +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/_deploy/appleKey_modified.p8 b/_deploy/appleKey_modified.p8 new file mode 100644 index 0000000..e9ed0ed --- /dev/null +++ b/_deploy/appleKey_modified.p8 @@ -0,0 +1 @@ +-----BEGIN PRIVATE KEY----- MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgL3WoWMr7zzqtZdF/ wNEJ9+yMP2qNJV305gTdF+++hLOgCgYIKoZIzj0DAQehRANCAATqlUN+GE7/r8UQ c93hRG9UxCtBcJEcgSGwYVPtZvA5igUBxY/6+RO/Tcnq9xT/6PZD0A82vMNSjoJ6 /KyhaFLl -----END PRIVATE KEY----- diff --git a/_deploy/setupAppleId.mjs b/_deploy/setupAppleId.mjs index e8ceacb..00e85a0 100644 --- a/_deploy/setupAppleId.mjs +++ b/_deploy/setupAppleId.mjs @@ -11,8 +11,13 @@ if (process.argv.includes("--help") || process.argv.includes("-h")) { Usage: node apple.mjs [--kid] [--iss] [--private_key] [--sub] [--expires_in] [--exp] - - node setupAppleId.mjs --kid YOUR_KEY_ID --iss YOUR_TEAM_ID --private_key "$(cat key.p8)" --sub YOUR_CLIENT_ID --expires_in 15778800 + APPLE_ID=com.mwhitnessing.sofia +APPLE_TEAM_ID=XC57P9SXDK +APPLE_KEY_ID=TB3V355G5Y +APPLE_KEY=-----BEGIN PRIVATE KEY----- MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgL3WoWMr7zzqtZdF/wNEJ9+yMP2qNJV305gTdF+++hLOgCgYIKoZIzj0DAQehRANCAATqlUN+GE7/r8UQc93hRG9UxCtBcJEcgSGwYVPtZvA5igUBxY/6+RO/Tcnq9xT/6PZD0A82vMNSjoJ6/KyhaFLl -----END PRIVATE KEY----- +node setupAppleId.mjs --kid YOUR_KEY_ID --iss YOUR_TEAM_ID --private_key "$(cat key.p8)" --sub YOUR_CLIENT_ID --expires_in 15778800 + + node setupAppleId.mjs --kid TB3V355G5Y --iss XC57P9SXDK --sub com.mwhitnessing.sofia --private_key "-----BEGIN PRIVATE KEY----- MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgL3WoWMr7zzqtZdF/ wNEJ9+yMP2qNJV305gTdF+++hLOgCgYIKoZIzj0DAQehRANCAATqlUN+GE7/r8UQ c93hRG9UxCtBcJEcgSGwYVPtZvA5igUBxY/6+RO/Tcnq9xT/6PZD0A82vMNSjoJ6 /KyhaFLl -----END PRIVATE KEY-----" Options: