Merge remote-tracking branch 'origin/main' into production

This commit is contained in:
Dobromir Popov
2024-03-06 02:02:35 +02:00
13 changed files with 195 additions and 134 deletions

View File

@ -1,37 +1,9 @@
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
NEXT_PUBLIC_PORT=
NEXT_PUBLIC_HOST=staging.mwhitnessing.com
NEXTAUTH_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
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
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

37
.env.homelab Normal file
View File

@ -0,0 +1,37 @@
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

View File

@ -1,9 +0,0 @@
NEXT_PUBLIC_PROTOCOL=https
NEXT_PUBLIC_PORT=
NEXT_PUBLIC_HOST=staging.mwhitnessing.com
NEXTAUTH_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:dwxhns9p9vp248V39xJyRthUsZ2gR9@mariadb-staging:3306/jwpwsofia

View File

@ -0,0 +1,39 @@
version: "3"
services:
nextjs-app: # https://sofia.mwhitnessing.com/
hostname: jwpw-app-staging # jwpw-nextjs-app-1
image: docker.d-popov.com/jwpw:latest
volumes:
- /mnt/docker_volumes/pw-demo/app/public/content/uploads/:/app/public/content/uploads
environment:
- NODE_ENV=demo
- TZ=Europe/Sofia
- DATABASE_URL=mysql://jwpwsofia_demo:dwxhns9p9vp248@jwpwsofia:3306/jwpwsofia_demo
- UPDATE_CODE_FROM_GIT=true # Set to true to pull latest code from Git
- GIT_BRANCH=main
- GIT_USERNAME=deploy
- GIT_PASSWORD=L3Kr2R438u4F7
command: sh -c " cd /app && npm install && npx next build && npm run nodeenv; tail -f /dev/null"
tty: true
stdin_open: true
restart: always
networks:
- infrastructure_default
mariadb:
deploy:
replicas: 0
hostname: mariadb-demo
image: mariadb:latest #mariadb:10.4
volumes:
- /mnt/docker_volumes/pw-demo/data/mysql:/var/lib/mysql
environment:
MARIADB_ROOT_PASSWORD: i4966cWBtP3xJ7BLsbsgo93
MYSQL_ROOT_PASSWORD: i4966cWBtP3xJ7BLsbsgo93
MYSQL_DATABASE: jwpwsofia_demo
MYSQL_USER: jwpwsofia_demo
MYSQL_PASSWORD: dwxhns9p9vp248
networks:
- infrastructure_default
networks:
infrastructure_default:
external: true

View File

@ -1,57 +0,0 @@
version: "3"
services:
nextjs-app: # https://sofia.mwhitnessing.com/
hostname: jwpw-app-staging # jwpw-nextjs-app-1
image: docker.d-popov.com/jwpw:latest
volumes:
- /mnt/docker_volumes/pw-staging/app/public/content/uploads/:/app/public/content/uploads
environment:
- NODE_ENV=prod_staging
- TZ=Europe/Sofia
- DATABASE_URL=mysql://jwpwsofia:dwxhns9p9vp248V39xJyRthUsZ2gR9@mariadb-staging:3306/jwpwsofia
- UPDATE_CODE_FROM_GIT=true # Set to true to pull latest code from Git
- GIT_BRANCH=main
- GIT_USERNAME=deploy
- GIT_PASSWORD=L3Kr2R438u4F7
command: sh -c " cd /app && npm install && npm run nodeenv; tail -f /dev/null"
tty: true
stdin_open: true
restart: always
# ports:
# - "3001:3000"
networks:
- infrastructure_default
mariadb:
hostname: mariadb-staging
image: mariadb:latest #mariadb:10.4
volumes:
- /mnt/docker_volumes/pw-staging/data/mysql:/var/lib/mysql
environment:
MARIADB_ROOT_PASSWORD: i4966cWBtP3xJ7BLsbsgo93C8Q5262
MYSQL_ROOT_PASSWORD: i4966cWBtP3xJ7BLsbsgo93C8Q5262
MYSQL_DATABASE: jwpwsofia
MYSQL_USER: jwpwsofia
MYSQL_PASSWORD: dwxhns9p9vp248V39xJyRthUsZ2gR9
#command: ["mysqld", "--max-connections=1000", "--sql-mode=ALLOW_INVALID_DATES,ANSI_QUOTES,ERROR_FOR_DIVISION_BY_ZERO,HIGH_NOT_PRECEDENCE,IGNORE_SPACE,NO_AUTO_CREATE_USER,NO_AUTO_VALUE_ON_ZERO,NO_BACKSLASH_ESCAPES,NO_DIR_IN_CREATE,NO_ENGINE_SUBSTITUTION,NO_FIELD_OPTIONS,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_UNSIGNED_SUBTRACTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,PIPES_AS_CONCAT,REAL_AS_FLOAT,STRICT_ALL_TABLES,STRICT_TRANS_TABLES,ANSI,DB2,MAXDB,MSSQL,MYSQL323,MYSQL40,ORACLE,POSTGRESQL,TRADITIONAL", "--wait-timeout=28800"]
networks:
- infrastructure_default
postgres:
hostname: postgres
image: postgres
restart: always
# set shared memory limit when using docker-compose
shm_size: 128mb
# or set shared memory limit when deploy via swarm stack
#volumes:
# - type: tmpfs
# target: /dev/shm
# tmpfs:
# size: 134217728 # 128*2^20 bytes = 128Mb
environment:
POSTGRES_PASSWORD: i4966cWBtP3xJ7BLsbsgo93C8Q5262
networks:
- infrastructure_default
networks:
infrastructure_default:
external: true

View File

@ -3,6 +3,8 @@ services:
nextjs-app: # https://sofia.mwhitnessing.com/
hostname: jwpw-app # jwpw-nextjs-app-1
image: docker.d-popov.com/jwpw:latest
deploy:
replicas: 2
#ports:
# - "3000:3000"
volumes:
@ -30,7 +32,7 @@ services:
volumes:
- /mnt/docker_volumes/pw/data/mysql:/var/lib/mysql
environment:
MARIADB_ROOT_PASSWORD: dwxhns9p9vp248V39xJyRthUsZ2gR9
# MARIADB_ROOT_PASSWORD: dwxhns9p9vp248V39xJyRthUsZ2gR9
MYSQL_ROOT_PASSWORD: i4966cWBtP3xJ7BLsbsgo93C8Q5262
MYSQL_DATABASE: jwpwsofia
MYSQL_USER: jwpwsofia
@ -38,7 +40,6 @@ services:
networks:
- default
- infrastructure_default
mariadb_backup:
image: alpine:latest
volumes:
@ -51,7 +52,6 @@ services:
MYSQL_HOST: mariadb
# GOOGLE_DRIVE_FOLDER_ID: your_google_drive_folder_id
entrypoint: /bin/sh -c
networks:
- infrastructure_default
command: |

View File

@ -15,7 +15,7 @@ services:
stdin_open: true
mariadb:
hostname: mariadb
image: mariadb #bitnami/mariadb:latest #mariadb:10.4
image: mariadb #bitnami/mariadb:latest #mariadb:10.4
environment:
MARIADB_ROOT_PASSWORD: Pw62L$3332JH
MYSQL_ROOT_PASSWORD: Pw62L$3332JH
@ -24,4 +24,20 @@ services:
MYSQL_PASSWORD: o74x642Rc8
networks:
- default
- mysql_default
- mysql_default
postgres:
deploy:
replicas: 0
hostname: postgres
image: postgres
restart: always
# set shared memory limit when using docker-compose
shm_size: 128mb
# or set shared memory limit when deploy via swarm stack
#volumes:
# - type: tmpfs
# target: /dev/shm
# tmpfs:
# size: 134217728 # 128*2^20 bytes = 128Mb
environment:
POSTGRES_PASSWORD: i4966cWBtP3xJ7BLsbsgo93C8Q5262

View File

@ -164,8 +164,15 @@ SET PASSWORD FOR 'root'@'localhost' = PASSWORD('i4966cWBtP3xJ7BLsbsgo93C8Q5262')
GRANT ALL PRIVILEGES ON jwpwsofia.* TO 'jwpwsofia'@'%' IDENTIFIED BY 'dwxhns9p9vp248V39xJyRthUsZ2gR9' WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON jwpwsofia.* TO 'jwpwsofia'@'172.22.0.3' IDENTIFIED BY 'dwxhns9p9vp248V39xJyRthUsZ2gR9' WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON jwpwsofia.* TO 'jwpwsofia'@'172.22.0.%' IDENTIFIED BY 'dwxhns9p9vp248V39xJyRthUsZ2gR9' WITH GRANT OPTION;
FLUSH PRIVILEGES;
exit;
ALTER USER 'jwpwsofia'@'172.22.0.%' IDENTIFIED BY 'dwxhns9p9vp248V39xJyRthUsZ2gR9';
--if error (does not exist)
CREATE USER 'jwpwsofia'@'172.22.0.%' IDENTIFIED BY 'dwxhns9p9vp248V39xJyRthUsZ2gR9';
GRANT ALL PRIVILEGES ON jwpwsofia.* TO 'jwpwsofia'@'172.22.0.%' WITH GRANT OPTION;
#Install depcheck:

View File

@ -2,6 +2,8 @@ import React, { useState, useEffect } from 'react';
import axiosInstance from '../../src/axiosSecure';
import PublisherSearchBox from '../publisher/PublisherSearchBox'; // Update the path
import LocalShippingIcon from '@mui/icons-material/LocalShipping';
const common = require('src/helpers/common');
@ -52,10 +54,11 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a
const [useFilterDate, setUseFilterDate] = useState(true);
const [selectedPublisher, setSelectedPublisher] = useState(null);
const [showCopyHint, setShowCopyHint] = useState(false);
const [transportProvided, setTransportProvided] = useState(false);
// Update assignments when shift changes
useEffect(() => {
setAssignments(shift.assignments);
setTransportProvided(!shift.requiresTransport || shift.assignments.some(ass => ass.isWithTransport));
}, [shift.assignments]);
const handleShiftClick = (shiftId) => {
@ -106,7 +109,7 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a
publisher: { connect: { id: publisher.id } },
shift: { connect: { id: shiftId } },
//isactive: true,
isConfirmed: true
isConfirmed: true,
};
const { data } = await axiosInstance.post("/api/data/assignments", newAssignment);
// Update the 'publisher' property of the returned data with the full publisher object
@ -124,9 +127,16 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a
setTimeout(() => setShowCopyHint(false), 1500);
};
async function toggleTransport(assignment): Promise<void> {
try {
assignment.isWithTransport = !assignment.isWithTransport;
const { data } = await axiosInstance.put("/api/data/assignments/" + assignment.id,
{ isWithTransport: assignment.isWithTransport })
.then(() => {
setTransportProvided(assignments.some(ass => ass.isWithTransport))
});
} catch (error) { }
}
return (
<div className={`flow w-full p-4 py-2 border-2 border-gray-300 rounded-md my-1 ${isSelected ? 'bg-gray-200' : ''}`}
@ -135,6 +145,7 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a
<div className="flex justify-between items-center mb-2 border-b pb-1">
<span className="text-lg font-semibold">
{`${common.getTimeRange(new Date(shift.startTime), new Date(shift.endTime))}`}
{/* {shift.requiresTransport && (<LocalShippingIcon />)} */}
</span>
{/* Copy All Names Button */}
@ -149,13 +160,13 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a
)}
</div>
{/* Assignments */}
{assignments.map((ass, index) => {
const publisherInfo = allPublishersInfo.find(info => info?.id === ass.publisher.id) || ass.publisher;
// Determine border styles
let borderStyles = '';
let canTransport = false;
if (selectedPublisher && selectedPublisher.id === ass.publisher.id) {
borderStyles += 'border-2 border-blue-300'; // Bottom border for selected publishers
}
@ -172,10 +183,12 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a
else {
// checkig if the publisher is available for this assignment
if (publisherInfo.availabilities?.some(av =>
av.startTime <= shift.startTime &&
av.endTime >= shift.endTime)) {
const av = publisherInfo.availabilities?.find(av =>
av.startTime <= shift.startTime && av.endTime >= shift.endTime
);
if (av) {
borderStyles += 'border-l-2 border-blue-500 '; // Left border for specific availability conditions
ass.canTransport = av.isWithTransportIn || av.isWithTransportOut;
}
if (publisherInfo.hasUpToDateAvailabilities) {
@ -194,17 +207,29 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a
}
}
return (
<div key={index}
className={`flow space-x-2 rounded-md px-2 py-1 my-1 ${ass.isConfirmed ? 'bg-yellow-100' : 'bg-gray-100'} ${borderStyles}`}
className={`flow space-x-2 rounded-md px-2 py-1 my-1 ${ass.isConfirmed ? 'bg-green-100' : 'bg-gray-100'} ${borderStyles}`}
>
<div className="flex justify-between items-center" onClick={() => handlePublisherClick(ass.publisher)}>
<span className="text-gray-700">{publisherInfo.firstName} {publisherInfo.lastName}</span>
<button onClick={() => removeAssignment(ass.id)}
className="text-white bg-red-500 hover:bg-red-600 px-3 py-1 ml-2 rounded-md"
>
махни
</button>
<div className="flex items-left" >
{/* //if shift.isWithTransport, add trnsport button toggle, which sets ass.isWithTransportIn */}
{shift.requiresTransport && (
<span
onClick={ass.canTransport ? () => toggleTransport(ass) : undefined}
className={`material-icons ${ass.isWithTransport ? 'text-green-500 font-bold' : (transportProvided ? 'text-gray-400 ' : 'text-orange-400 font-bold')} ${ass.canTransport ? ' cursor-pointer' : 'cursor-not-allowed'} px-3 py-1 ml-2 rounded-md`}
>
{ass.isWithTransport ? "транспорт" : ass.canTransport ? "може транспорт" : "без транспорт"} <LocalShippingIcon />
</span>
)}
<button onClick={() => removeAssignment(ass.id)} className="text-white bg-red-500 hover:bg-red-600 px-3 py-1 ml-2 rounded-md" >
махни
</button>
</div>
</div>
</div>
);
@ -243,7 +268,7 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a
showList={false}
/>
</Modal>
</div>
</div >
);
}

View File

@ -178,7 +178,8 @@ async function GenerateSchedule(axios: Axios, date: string, copyFromPreviousMont
shiftNr++;
const __shiftName = String(shiftStart.getHours()).padStart(2, "0") + ":" + String(shiftStart.getMinutes()).padStart(2, "0") + " - " + String(shiftEnd.getHours()).padStart(2, "0") + ":" + String(shiftEnd.getMinutes()).padStart(2, "0");
shiftAssignments = [];
console.log("[shift " + shiftNr + "] " + __shiftName);
let isTransportRequired = shiftNr == 1 || shiftEnd.getTime() == endTime.getTime();
console.log("[shift " + shiftNr + "] " + __shiftName + ", transport: " + (isTransportRequired ? "yes" : "no") + ", " + shiftStart.toLocaleTimeString() + " - " + shiftEnd.toLocaleTimeString() + " (end time: " + endTime.toLocaleTimeString() + ", " + event.shiftDuration + " min)");
if (autoFill || copyFromPreviousMonth) {
// ###########################################
@ -395,6 +396,7 @@ async function GenerateSchedule(axios: Axios, date: string, copyFromPreviousMont
startTime: shiftStart,
endTime: shiftEnd,
name: event.dayofweek + " " + shiftStart.toLocaleTimeString() + " - " + shiftEnd.toLocaleTimeString(),
requiresTransport: isTransportRequired,
cartEvent: {
connect: {
id: event.id,

View File

@ -14,6 +14,7 @@ const common = require('src/helpers/common');
import { toast } from 'react-toastify';
import ProtectedRoute from '../../../components/protectedRoute';
import ConfirmationModal from '../../../components/ConfirmationModal';
import LocalShippingIcon from '@mui/icons-material/LocalShipping';
// import { FaPlus, FaCogs, FaTrashAlt, FaSpinner } from 'react-icons/fa'; // Import FontAwesome icons
@ -108,6 +109,12 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
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`);
availablePubsForDate.forEach(pub => {
pub.canTransport = pub.availabilities.some(av =>
av.isWithTransportIn || av.isWithTransportOut
);
});
//remove availabilities that are isFromPreviousAssignment or from previous month for each publisher
// availablePubsForDate = availablePubsForDate.map(pub => {
// pub.availabilities = pub.availabilities.filter(avail => avail.isFromPreviousAssignment == false);
@ -134,22 +141,31 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
const handleShiftSelection = (selectedShift) => {
setSelectedShiftId(selectedShift.id);
const updatedPubs = availablePubs.map(pub => {
const isAvailableForShift = pub.availabilities.some(avail =>
const av = pub.availabilities?.find(avail =>
avail.startTime <= selectedShift.startTime
&& avail.endTime >= selectedShift.endTime
&& avail.isFromPreviousAssignment == false
);
if (av) {
pub.isAvailableForShift = true;
pub.canTransport = av.isWithTransportIn || av.isWithTransportOut;
}
// const isAvailableForShift = pub.availabilities.some(avail =>
// avail.startTime <= selectedShift.startTime
// && avail.endTime >= selectedShift.endTime
// && avail.isFromPreviousAssignment == false
// );
const isAvailableForShiftWithPrevious = pub.availabilities.some(avail =>
avail.startTime <= selectedShift.startTime
&& avail.endTime >= selectedShift.endTime
);
//! console.log(`Publisher ${pub.firstName} ${pub.lastName} is available for shift ${selectedShift.id}: ${isAvailableForShift}`);
//// console.log(`Publisher ${pub.firstName} ${pub.lastName} has ${pub.availabilities.length} availabilities :` + pub.availabilities.map(avail => avail.startTime + " - " + avail.endTime));
//// console.log(`Publisher ${pub.firstName} ${pub.lastName} has ${pub.availabilities.length} availabilities :` + stringify.join(', 'pub.availabilities.map(avail => avail.id)));
// //! console.log(`Publisher ${pub.firstName} ${pub.lastName} is available for shift ${selectedShift.id}: ${isAvailableForShift}`);
// //// console.log(`Publisher ${pub.firstName} ${pub.lastName} has ${pub.availabilities.length} availabilities :` + pub.availabilities.map(avail => avail.startTime + " - " + avail.endTime));
// //// console.log(`Publisher ${pub.firstName} ${pub.lastName} has ${pub.availabilities.length} availabilities :` + stringify.join(', 'pub.availabilities.map(avail => avail.id)));
const availabilitiesIds = pub.availabilities.map(avail => avail.id).join(', ');
//! console.log(`Publisher ${pub.firstName} ${pub.lastName} has ${pub.availabilities.length} availabilities with IDs: ${availabilitiesIds}`);
return { ...pub, isAvailableForShift, isAvailableForShiftWithPrevious, isSelected: pub.id === selectedShift.selectedPublisher?.id };
// const availabilitiesIds = pub.availabilities.map(avail => avail.id).join(', ');
// //! console.log(`Publisher ${pub.firstName} ${pub.lastName} has ${pub.availabilities.length} availabilities with IDs: ${availabilitiesIds}`);
return { ...pub, isAvailableForShiftWithPrevious, isSelected: pub.id === selectedShift.selectedPublisher?.id };
});
// Sort publishers based on their availability state. use currentDayAssignments, currentWeekAssignments,
@ -664,6 +680,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
>
<span className={`text-gray-700 ${pub.isAvailableForShift ? 'font-bold' : 'font-medium'} `}>
{pub.firstName} {pub.lastName}
{pub.canTransport && (<LocalShippingIcon className="mx-2 text-gray-500" />)}
</span>
<div className="flex space-x-1 overflow-hidden">
<span title="Възможност: часове | дни" className={`badge py-1 px-2 rounded-md text-xs ${pub.currentMonthAvailabilityHoursCount || pub.currentMonthAvailabilityDaysCount ? 'bg-teal-500 text-white' : 'bg-teal-200 text-gray-300'} hover:underline`} >

View File

@ -95,6 +95,9 @@ export const getServerSideProps = async (context) => {
if (availability.startTime) {
availability.startTime = availability.startTime.toISOString();
availability.endTime = availability.endTime.toISOString();
if (availability.dateOfEntry) {
availability.dateOfEntry = availability.dateOfEntry.toISOString();
}
}
});

View File

@ -404,20 +404,21 @@ exports.processEvents = async function (events, year, monthNumber, progressCallb
s.cartEventId === cartEvent.id &&
new Date(s.startTime).getTime() === new Date(start).getTime()
);
// get only hh:mm from the date
let isTransportRequired = event.shiftNr == 1 || end.toLocaleTimeString().substring(0, 5) == cartEvent.endTime.toLocaleTimeString().substring(0, 5);
if (!shift) {
//if shiftnr = 1, notes = "Докарва" + event.transport
//if shiftnr = 8, notes = "Взема" + event.transport
let note = event.shiftNr === 1 ? "Докарва количка от Люлин - " + event.transport :
event.shiftNr === 6 ? "Прибира количка в Люлин - " + event.transport : "";
let note = isTransportRequired ? event.transport : "";
// "Докарва количка от Люлин/Прибира количка в Люлин"
const shiftEntity = await prisma.shift.create({
data: {
name: event.dayOfWeek + " " + event.dayOfMonth + ", " + start.toLocaleTimeString() + " - " + end.toLocaleTimeString(),
startTime: start,
endTime: end,
notes: note,
requiresTransport: isTransportRequired,
cartEvent: {
connect: {
id: cartEvent.id,
@ -506,6 +507,13 @@ exports.processEvents = async function (events, year, monthNumber, progressCallb
}
if (location != null && publisher != null && shift != null) {
let isWithTransport = false;
if (isTransportRequired) {
const pubInitials = publisher.firstName[0] + publisher.lastName[0];
// get cotent after last - or long dash-`-` and remove spaces, trim dots and make lowercase
let transportInitials = event.transport.split("-").pop().replace(/[\s.]/g, "").toUpperCase();
isWithTransport = transportInitials.includes(pubInitials);
}
const assignment = await prisma.assignment.create({
data: {
//publisherId: publisher.id,
@ -520,6 +528,7 @@ exports.processEvents = async function (events, year, monthNumber, progressCallb
id: shift.id,
},
},
isWithTransport: isWithTransport,
},
});
//ToDo: fix findPublisherAvailability and creation of availabilities