From 81f53a4ec7f883aa97f2093751dac93a87c169b4 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 5 Mar 2024 22:35:49 +0200 Subject: [PATCH 1/7] deployment scripts changes. staging is now demo, production has two instances - one for staging --- _deploy/deoloy.azure.demo.yml | 39 +++++++++++++ _deploy/deoloy.azure.prod.stage.yml | 57 ------------------- ...e.prod.yml => deoloy.azure.production.yml} | 6 +- ...tion.yml => homelab.deploy.production.yml} | 20 ++++++- _doc/notes.mb | 7 +++ 5 files changed, 67 insertions(+), 62 deletions(-) create mode 100644 _deploy/deoloy.azure.demo.yml delete mode 100644 _deploy/deoloy.azure.prod.stage.yml rename _deploy/{deoloy.azure.prod.yml => deoloy.azure.production.yml} (96%) rename _deploy/{deploy.homelab.production.yml => homelab.deploy.production.yml} (57%) diff --git a/_deploy/deoloy.azure.demo.yml b/_deploy/deoloy.azure.demo.yml new file mode 100644 index 0000000..4aab094 --- /dev/null +++ b/_deploy/deoloy.azure.demo.yml @@ -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=prod_staging + - 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 diff --git a/_deploy/deoloy.azure.prod.stage.yml b/_deploy/deoloy.azure.prod.stage.yml deleted file mode 100644 index 9590d67..0000000 --- a/_deploy/deoloy.azure.prod.stage.yml +++ /dev/null @@ -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 diff --git a/_deploy/deoloy.azure.prod.yml b/_deploy/deoloy.azure.production.yml similarity index 96% rename from _deploy/deoloy.azure.prod.yml rename to _deploy/deoloy.azure.production.yml index 0cb1e8b..87372a8 100644 --- a/_deploy/deoloy.azure.prod.yml +++ b/_deploy/deoloy.azure.production.yml @@ -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: | diff --git a/_deploy/deploy.homelab.production.yml b/_deploy/homelab.deploy.production.yml similarity index 57% rename from _deploy/deploy.homelab.production.yml rename to _deploy/homelab.deploy.production.yml index cf14df8..402af4d 100644 --- a/_deploy/deploy.homelab.production.yml +++ b/_deploy/homelab.deploy.production.yml @@ -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 \ No newline at end of file + - 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 diff --git a/_doc/notes.mb b/_doc/notes.mb index 4862741..bd38d8e 100644 --- a/_doc/notes.mb +++ b/_doc/notes.mb @@ -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: From 1dfd30afa2d78528e344824cc594f222e18c5cd3 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 5 Mar 2024 22:42:07 +0200 Subject: [PATCH 2/7] env config renames --- .env.demo | 40 ++++++----------------------------- .env.homelab | 37 ++++++++++++++++++++++++++++++++ .env.prod_staging | 9 -------- _deploy/deoloy.azure.demo.yml | 2 +- 4 files changed, 44 insertions(+), 44 deletions(-) create mode 100644 .env.homelab delete mode 100644 .env.prod_staging diff --git a/.env.demo b/.env.demo index 2a2aa9a..17f98ce 100644 --- a/.env.demo +++ b/.env.demo @@ -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 \ No newline at end of file diff --git a/.env.homelab b/.env.homelab new file mode 100644 index 0000000..2a2aa9a --- /dev/null +++ b/.env.homelab @@ -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 diff --git a/.env.prod_staging b/.env.prod_staging deleted file mode 100644 index 4542e30..0000000 --- a/.env.prod_staging +++ /dev/null @@ -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 \ No newline at end of file diff --git a/_deploy/deoloy.azure.demo.yml b/_deploy/deoloy.azure.demo.yml index 4aab094..924858a 100644 --- a/_deploy/deoloy.azure.demo.yml +++ b/_deploy/deoloy.azure.demo.yml @@ -6,7 +6,7 @@ services: volumes: - /mnt/docker_volumes/pw-demo/app/public/content/uploads/:/app/public/content/uploads environment: - - NODE_ENV=prod_staging + - 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 From cf17cc74a2de7ccaa145419228bc02268a11e658 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 5 Mar 2024 23:49:23 +0200 Subject: [PATCH 3/7] import/parse and generate respects withTransport and requiresTransport properties. parsing rransport initials --- .env.development | 4 ++-- components/calendar/ShiftComponent.tsx | 26 ++++++++++++++++++++------ pages/api/shiftgenerate.ts | 4 +++- pages/cart/publishers/stats.tsx | 3 +++ src/helpers/excel.js | 17 +++++++++++++---- 5 files changed, 41 insertions(+), 13 deletions(-) diff --git a/.env.development b/.env.development index afec269..e623f71 100644 --- a/.env.development +++ b/.env.development @@ -11,5 +11,5 @@ 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://root:Zelen0ku4e@192.168.0.10:3306/cart_dev +DATABASE_URL=mysql://cart:cartpw@localhost:3306/cart diff --git a/components/calendar/ShiftComponent.tsx b/components/calendar/ShiftComponent.tsx index f78f498..488e9a6 100644 --- a/components/calendar/ShiftComponent.tsx +++ b/components/calendar/ShiftComponent.tsx @@ -194,17 +194,31 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a } } + function toggleTransport(id: any): void { + throw new Error('Function not implemented.'); + } + return (
handlePublisherClick(ass.publisher)}> {publisherInfo.firstName} {publisherInfo.lastName} - +
+ {/* //if shift.isWithTransport, add trnsport button toggle, which sets ass.isWithTransportIn */} + {shift.requiresTransport && + ( + + ) + } + + +
+
); diff --git a/pages/api/shiftgenerate.ts b/pages/api/shiftgenerate.ts index ba61fb8..c1bc139 100644 --- a/pages/api/shiftgenerate.ts +++ b/pages/api/shiftgenerate.ts @@ -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, diff --git a/pages/cart/publishers/stats.tsx b/pages/cart/publishers/stats.tsx index 6945583..e69f47f 100644 --- a/pages/cart/publishers/stats.tsx +++ b/pages/cart/publishers/stats.tsx @@ -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(); + } } }); diff --git a/src/helpers/excel.js b/src/helpers/excel.js index 49a62f3..40f2f1c 100644 --- a/src/helpers/excel.js +++ b/src/helpers/excel.js @@ -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 From 07e4b1b80f07ffa8c9163db5115226912cb1c96f Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Wed, 6 Mar 2024 00:57:32 +0200 Subject: [PATCH 4/7] transport toggle on calendar working --- .env.development | 4 +-- components/calendar/ShiftComponent.tsx | 46 +++++++++++++++++--------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/.env.development b/.env.development index e623f71..afec269 100644 --- a/.env.development +++ b/.env.development @@ -11,5 +11,5 @@ 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://root:Zelen0ku4e@192.168.0.10:3306/cart_dev +# DATABASE_URL=mysql://cart:cartpw@localhost:3306/cart diff --git a/components/calendar/ShiftComponent.tsx b/components/calendar/ShiftComponent.tsx index 488e9a6..16fab95 100644 --- a/components/calendar/ShiftComponent.tsx +++ b/components/calendar/ShiftComponent.tsx @@ -2,6 +2,8 @@ import React, { useState, useEffect } from 'react'; import axiosInstance from '../../src/axiosSecure'; import PublisherSearchBox from '../publisher/PublisherSearchBox'; // Update the path +import { DirectionsBus } from '@mui/material'; // Import MUI CircularProgress for loading indicator + 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,6 +127,16 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a setTimeout(() => setShowCopyHint(false), 1500); }; + async function toggleTransport(assignment): Promise { + 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) { } + } @@ -156,6 +169,7 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a // 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 +186,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,9 +210,6 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a } } - function toggleTransport(id: any): void { - throw new Error('Function not implemented.'); - } return (
{publisherInfo.firstName} {publisherInfo.lastName}
{/* //if shift.isWithTransport, add trnsport button toggle, which sets ass.isWithTransportIn */} - {shift.requiresTransport && - ( - - ) - } + {shift.requiresTransport && ( + toggleTransport(ass) : undefined} + className={`material-icons ${ass.isWithTransport || ass.canTransport ? '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 ? "може транспорт" : "без транспорт"} + + )} @@ -257,7 +271,7 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a showList={false} /> -
+
); } From cd59566d1cff93446de68b43b42ac307b15090f6 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Wed, 6 Mar 2024 01:26:12 +0200 Subject: [PATCH 5/7] use material icon for transport; transport icon on all available pubs for transport --- components/calendar/ShiftComponent.tsx | 11 +-- pages/cart/calendar/index.tsx | 107 +++++++------------------ 2 files changed, 32 insertions(+), 86 deletions(-) diff --git a/components/calendar/ShiftComponent.tsx b/components/calendar/ShiftComponent.tsx index 16fab95..c6c5ec2 100644 --- a/components/calendar/ShiftComponent.tsx +++ b/components/calendar/ShiftComponent.tsx @@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react'; import axiosInstance from '../../src/axiosSecure'; import PublisherSearchBox from '../publisher/PublisherSearchBox'; // Update the path -import { DirectionsBus } from '@mui/material'; // Import MUI CircularProgress for loading indicator +import LocalShippingIcon from '@mui/icons-material/LocalShipping'; const common = require('src/helpers/common'); @@ -138,9 +138,6 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a } catch (error) { } } - - - return (
@@ -148,6 +145,7 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a
{`${common.getTimeRange(new Date(shift.startTime), new Date(shift.endTime))}`} + {/* {shift.requiresTransport && ()} */} {/* Copy All Names Button */} @@ -162,7 +160,6 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a )}
- {/* Assignments */} {assignments.map((ass, index) => { const publisherInfo = allPublishersInfo.find(info => info?.id === ass.publisher.id) || ass.publisher; @@ -222,9 +219,9 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a {shift.requiresTransport && ( toggleTransport(ass) : undefined} - className={`material-icons ${ass.isWithTransport || ass.canTransport ? '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`} + 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 ? "може транспорт" : "без транспорт"} + {ass.isWithTransport ? "транспорт" : ass.canTransport ? "може транспорт" : "без транспорт"} )}
- -
- {/* */} -
{isModalOpen && setIsModalOpen(false)} />} @@ -844,69 +859,3 @@ export default function CalendarPage({ initialEvents, initialShifts }) { } } } - -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 NEXTAUTH_URL: ' + process.env.NEXTAUTH_URL); - console.log('Runtime Axios Base URL:', axios.defaults.baseURL); - - const currentDate = new Date(); - const firstDayOfMonth = new Date(currentDate.getFullYear(), currentDate.getMonth() - 3, 1); - const lastDayOfMonth = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0); // 0th day of the next month gives the last day of the current month - - 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 } }); - // 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: shifts } = await axios.get(url); - - // get all shifts for the month, including assigments - let shifts = await prismaClient.shift.findMany({ - where: { - isactive: true, - startTime: { - gte: firstDayOfMonth, - //lt: lastDayOfMonth - } - }, - include: { - assignments: { - include: { - publisher: { - select: { - id: true, - } - } - } - } - } - }); - - //calculate assCount for each shift - shifts = shifts.map(shift => ({ - ...shift, - assignedCount: shift.assignments.length, - startTime: shift.startTime.toISOString(), - endTime: shift.endTime.toISOString(), - })); - - - return { - props: { - initialEvents: events, - initialShifts: shifts, - }, - }; - -} \ No newline at end of file From c27dba5860360a341242cf2a91d668fa2a2913ed Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Wed, 6 Mar 2024 01:44:05 +0200 Subject: [PATCH 6/7] restore deleted by accident source --- pages/cart/calendar/index.tsx | 86 ++++++++++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 12 deletions(-) diff --git a/pages/cart/calendar/index.tsx b/pages/cart/calendar/index.tsx index 77a02a4..e853d4b 100644 --- a/pages/cart/calendar/index.tsx +++ b/pages/cart/calendar/index.tsx @@ -14,12 +14,9 @@ const common = require('src/helpers/common'); import { toast } from 'react-toastify'; import ProtectedRoute from '../../../components/protectedRoute'; import ConfirmationModal from '../../../components/ConfirmationModal'; -import axiosServer from '../../../src/axiosServer'; - - -// import { FaPlus, FaCogs, FaTrashAlt, FaSpinner } from 'react-icons/fa'; // Import FontAwesome icons import LocalShippingIcon from '@mui/icons-material/LocalShipping'; +// import { FaPlus, FaCogs, FaTrashAlt, FaSpinner } from 'react-icons/fa'; // Import FontAwesome icons @@ -112,12 +109,6 @@ 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); @@ -150,6 +141,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) { ); if (av) { pub.isAvailableForShift = true; + pub.canTransport = av.isWithTransportIn || av.isWithTransportOut; } // const isAvailableForShift = pub.availabilities.some(avail => @@ -335,7 +327,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) { var classname = ""; if (events == null) { - return
{" - "}
; + return
{" "}
; } const event = events.find((event) => { @@ -682,7 +674,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) { > {pub.firstName} {pub.lastName} - {pub.canTransport && ()} + {pub.canTransport && ()}
@@ -713,6 +705,10 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
+ +
+ {/* */} +
{isModalOpen && setIsModalOpen(false)} />} @@ -859,3 +855,69 @@ export default function CalendarPage({ initialEvents, initialShifts }) { } } } + +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 NEXTAUTH_URL: ' + process.env.NEXTAUTH_URL); + console.log('Runtime Axios Base URL:', axios.defaults.baseURL); + + const currentDate = new Date(); + const firstDayOfMonth = new Date(currentDate.getFullYear(), currentDate.getMonth() - 3, 1); + const lastDayOfMonth = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0); // 0th day of the next month gives the last day of the current month + + 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 } }); + // 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: shifts } = await axios.get(url); + + // get all shifts for the month, including assigments + let shifts = await prismaClient.shift.findMany({ + where: { + isactive: true, + startTime: { + gte: firstDayOfMonth, + //lt: lastDayOfMonth + } + }, + include: { + assignments: { + include: { + publisher: { + select: { + id: true, + } + } + } + } + } + }); + + //calculate assCount for each shift + shifts = shifts.map(shift => ({ + ...shift, + assignedCount: shift.assignments.length, + startTime: shift.startTime.toISOString(), + endTime: shift.endTime.toISOString(), + })); + + + return { + props: { + initialEvents: events, + initialShifts: shifts, + }, + }; + +} \ No newline at end of file From 9f91c289aea2fd97e76062f8b04f1312c36a4662 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Wed, 6 Mar 2024 01:44:57 +0200 Subject: [PATCH 7/7] redo lost change --- pages/cart/calendar/index.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pages/cart/calendar/index.tsx b/pages/cart/calendar/index.tsx index e853d4b..a3f5746 100644 --- a/pages/cart/calendar/index.tsx +++ b/pages/cart/calendar/index.tsx @@ -109,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);