Merge branch 'main' of https://git.d-popov.com/popov/mwhitnessing
This commit is contained in:
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -144,5 +144,8 @@
|
||||
"components/x-date-pickers/locales"
|
||||
],
|
||||
"i18n-ally.keystyle": "nested",
|
||||
"i18n-ally.sourceLanguage": "bg"
|
||||
"i18n-ally.sourceLanguage": "bg",
|
||||
"[shellscript]": {
|
||||
"editor.defaultFormatter": "foxundermoon.shell-format"
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ services:
|
||||
# - "3000:3000"
|
||||
volumes:
|
||||
- /mnt/docker_volumes/pw/app/public/content/uploads/:/app/public/content/uploads
|
||||
- /mnt/docker_volumes/pw/app/logs:/app/logs
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- TZ=Europe/Sofia
|
||||
@ -19,7 +20,7 @@ services:
|
||||
- GIT_USERNAME=deploy
|
||||
- GIT_PASSWORD=L3Kr2R438u4F7
|
||||
- ADMIN_PASSWORD=changeme
|
||||
command: sh -c " cd /app && npm install && npm run prod; tail -f /dev/null"
|
||||
command: sh -c " cd /app && npm install && npx next build && npm run prod; tail -f /dev/null"
|
||||
#command: sh -c " cd /app && tail -f /dev/null"
|
||||
tty: true
|
||||
stdin_open: true
|
||||
@ -56,15 +57,15 @@ services:
|
||||
networks:
|
||||
- infrastructure_default
|
||||
command: |
|
||||
apk update && \
|
||||
"apk update && \
|
||||
apk add --no-cache mariadb-client mariadb-connector-c && \
|
||||
echo '0 2 * * * mysqldump -h $$MYSQL_HOST -P 3306 -u$$MYSQL_USER -p$$MYSQL_PASSWORD $$MYSQL_DATABASE > /backup/$$(date +\\%Y-\\%m-\\%d-\\%H\\%M\\%S)-$$MYSQL_DATABASE.sql' > /etc/crontabs/root && \
|
||||
echo '0 7 * * * rclone sync /backup nextcloud:/mwitnessing' >> /etc/crontabs/root && \
|
||||
crond -f -d 8
|
||||
crond -f -d 8"
|
||||
# wget -q https://github.com/prasmussen/gdrive/releases/download/2.1.0/gdrive-linux-x64 -O /usr/bin/gdrive && \
|
||||
# chmod +x /usr/bin/gdrive && \
|
||||
# gdrive about --service-account /root/.gdrive_service_account.json && \
|
||||
# echo '0 * * * * /usr/bin/mysqldump -h $$MYSQL_HOST -u$$MYSQL_USER -p$$MYSQL_PASSWORD $$MYSQL_DATABASE | gzip > /backup/$$(date +\\%Y-\\%m-\\%d-\\%H\\%M\\%S)-$$MYSQL_DATABASE.sql.gz && gdrive upload --parent $$GOOGLE_DRIVE_FOLDER_ID --service-account /root/.gdrive_service_account.json /backup/$$(date +\\%Y-\\%m-\\%d-\\%H\\%M\\%S)-$$MYSQL_DATABASE.sql.gz' > /etc/crontabs/root && crond -f -d 8"
|
||||
# echo '0 * * * * /usr/bin/mysqldump -h $$MYSQL_HOST -u$$MYSQL_USER -p$$MYSQL_PASSWORD $$MYSQL_DATABASE | gzip > /backup/$$(date +\\%Y-\\%m-\\%d-\\%H\\%M\\%S)-$$MYSQL_DATABASE.sql.gz && gdrive upload --parent $$GOOGLE_DRIVE_FOLDER_ID --service-account /root/.gdrive_service_account.json /backup/$$(date +\\%Y-\\%m-\\%d-\\%H\\%M\\%S)-$$MYSQL_DATABASE.sql.gz' > /etc/crontabs/root && crond -f -d 8 \
|
||||
# echo '0 7 * * * rclone sync /backup nextcloud:/mwitnessing --delete-excluded ' >> /etc/crontabs/root && \"
|
||||
networks:
|
||||
infrastructure_default:
|
||||
external: true
|
||||
|
@ -3,18 +3,72 @@
|
||||
if [ "$UPDATE_CODE_FROM_GIT" = "true" ]; then
|
||||
# Install necessary packages
|
||||
apk add git nano rsync
|
||||
echo "Updating code from git.d-popov.com...(as '$GIT_USERNAME')"
|
||||
echo "Updating code from git.d-popov.com...(as '$GIT_USERNAME')" > /app/logs/deploy.txt
|
||||
|
||||
# Create a temporary directory for the new clone
|
||||
rm -rf /tmp/clone
|
||||
mkdir /tmp/clone
|
||||
mkdir -p /app/logs
|
||||
|
||||
# Clear previous log
|
||||
echo "Starting sync process at $(date)" > /app/logs/deploy.txt
|
||||
# Clone the repository
|
||||
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
|
||||
echo "\r\n\r\n Cloning repository..." | tee -a logs/deploy.txt
|
||||
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"
|
||||
# Synchronize all files except package.json, package-lock.json, and the contents of /public/content
|
||||
# rsync -av --filter='P /public/content/' --exclude 'package.json' --exclude 'package-lock.json' /tmp/clone/ /app/ || echo "Rsync failed: Issue synchronizing files"
|
||||
echo "\r\n\r\n Synchronizing files..."
|
||||
rsync -av /tmp/clone/_deploy/entrypoint.sh /app/entrypoint.sh || echo "Rsync failed: Issue copying entrypoint.sh"
|
||||
|
||||
|
||||
|
||||
# rsync -av --update --exclude '/public/content' --exclude 'package.json' --exclude 'package-lock.json' /tmp/clone/ /app/ || echo "Rsync failed: Issue synchronizing files" | tee -a /app/logs/deploy.txt
|
||||
|
||||
|
||||
########################################################################################
|
||||
if [ -d "/app/public/content/permits" ]; then
|
||||
mv /app/public/content/permits /tmp/content/permits
|
||||
echo "Permits folder backed up successfully." | tee -a /app/logs/deploy.txt
|
||||
else
|
||||
echo "Permits folder not found, skipping backup." | tee -a /app/logs/deploy.txt
|
||||
fi
|
||||
|
||||
# Run rsync with verbose output and itemize-changes
|
||||
echo "Running rsync..." | tee -a /app/logs/deploy.txt
|
||||
rsync -av --itemize-changes \
|
||||
--exclude='package.json' \
|
||||
--exclude='package-lock.json' \
|
||||
/tmp/clone/ /app/ >> /app/logs/deploy.txt 2>&1
|
||||
|
||||
# Check rsync exit status
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Rsync failed: Issue synchronizing files" | tee -a /app/logs/deploy.txt
|
||||
cat /app/logs/deploy.txt # Display the log contents
|
||||
else
|
||||
echo "Rsync completed successfully" | tee -a /app/logs/deploy.txt
|
||||
echo "Last few lines of rsync log:" | tee -a /app/logs/deploy.txt
|
||||
tail -n 20 /app/logs/deploy.txt # Display the last 20 lines of the log
|
||||
fi
|
||||
|
||||
# Restore permits folder
|
||||
echo "Restoring permits folder..." | tee -a /app/logs/deploy.txt
|
||||
if [ -d "/tmp/content/permits" ]; then
|
||||
# Ensure the destination directory exists
|
||||
mkdir -p /app/public/content
|
||||
mv /tmp/content/permits /app/public/content/permits
|
||||
echo "Permits folder restored successfully." | tee -a /app/logs/deploy.txt
|
||||
else
|
||||
echo "No permits folder to restore." | tee -a /app/logs/deploy.txt
|
||||
fi
|
||||
|
||||
# Check contents after restoration
|
||||
echo "Contents of /app/public/content after restoration:" >> /app/logs/deploy.txt
|
||||
ls -la /app/public/content >> /app/logs/deploy.txt 2>&1
|
||||
########################################################################################
|
||||
|
||||
|
||||
echo "\r\n\r\n Checking for changes in package files..."
|
||||
# Determine if package.json or package-lock.json has changed
|
||||
PACKAGE_CHANGE=0
|
||||
if ! cmp -s /tmp/clone/package.json /app/package.json || ! cmp -s /tmp/clone/package-lock.json /app/package-lock.json; then
|
||||
@ -37,7 +91,7 @@ if [ "$UPDATE_CODE_FROM_GIT" = "true" ]; then
|
||||
npx next build
|
||||
|
||||
# Clean up
|
||||
rm -rf /tmp/clone
|
||||
# rm -rf /tmp/clone
|
||||
echo "Update process completed."
|
||||
fi
|
||||
|
||||
|
43
_deploy/entrypoint.staging.sh
Normal file
43
_deploy/entrypoint.staging.sh
Normal file
@ -0,0 +1,43 @@
|
||||
# Check if the environment variable to update code from git is set to true
|
||||
if [ "$UPDATE_CODE_FROM_GIT" = "true" ]; then
|
||||
# Install necessary packages
|
||||
apk add git nano rsync
|
||||
echo "Updating code from git.d-popov.com...(as '$GIT_USERNAME')"
|
||||
|
||||
# Remove the previous clone directory to ensure a fresh start
|
||||
rm -rf /tmp/clone
|
||||
mkdir /tmp/clone
|
||||
|
||||
# Clone the specific branch of the new repository
|
||||
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
|
||||
# Fetch the latest commit ID and message from the cloned repository
|
||||
GIT_COMMIT_ID=$(git -C /tmp/clone rev-parse HEAD)
|
||||
LAST_COMMIT_MESSAGE=$(git -C /tmp/clone log -1 --pretty=%B)
|
||||
echo "Current Git Commit: $LAST_COMMIT_MESSAGE: $GIT_COMMIT_ID"
|
||||
export GIT_COMMIT_ID
|
||||
|
||||
# Use rsync to synchronize the files to /app, including deletion of files not in the source
|
||||
rsync -av --delete --exclude '/public/content' /tmp/clone/ /app/ || echo "Rsync failed: Issue synchronizing files"
|
||||
# Copy .env files
|
||||
rsync -av /tmp/clone/.env* /app/ || echo "Rsync failed: Issue copying .env files"
|
||||
# Copy the entrypoint.sh if exists in the new structure
|
||||
[ -f /tmp/clone/entrypoint.sh ] && rsync -av /tmp/clone/entrypoint.sh /app/entrypoint.sh || echo "Rsync failed: Issue copying entrypoint.sh"
|
||||
chmod +x /app/entrypoint.sh
|
||||
|
||||
# Clean up the temporary clone directory
|
||||
rm -rf /tmp/clone
|
||||
|
||||
cd /app
|
||||
echo "Installing packages in /app"
|
||||
npm install --no-audit --no-fund --no-optional --omit=optional
|
||||
yes | npx prisma generate
|
||||
# Uncomment the next line if database migrations are necessary
|
||||
# npx prisma migrate deploy
|
||||
echo "Done cloning. Current Git Commit ID: $GIT_COMMIT_ID"
|
||||
# Uncomment the following lines for production deployment
|
||||
# npx next build
|
||||
# npx next start
|
||||
fi
|
||||
|
||||
echo "Running the main process"
|
||||
exec "$@"
|
19
_deploy/new-lite/Dockerfile
Normal file
19
_deploy/new-lite/Dockerfile
Normal file
@ -0,0 +1,19 @@
|
||||
FROM node:current-alpine
|
||||
|
||||
# Install git and curl
|
||||
RUN apk add --no-cache git curl
|
||||
|
||||
# Set environment variables for repo and branch
|
||||
# These will be overridden by docker-compose.yml
|
||||
ENV REPO=""
|
||||
ENV BRANCH=""
|
||||
|
||||
# Create a directory for the app
|
||||
WORKDIR /app
|
||||
|
||||
# Download the entrypoint script
|
||||
CMD git clone --depth 1 --branch $BRANCH $REPO /tmp/repo && \
|
||||
cp /tmp/repo/_deploy/entrypoint.sh /app/entrypoint.sh && \
|
||||
chmod +x /app/entrypoint.sh && \
|
||||
rm -rf /tmp/repo && \
|
||||
/app/entrypoint.sh
|
10
_doc/ToDo.md
10
_doc/ToDo.md
@ -262,4 +262,12 @@ in schedule admin - if a publisher is always pair & family is not in the shift -
|
||||
[] allow blocking of inputs (different from publishing) TODO: fix to keep previous occurances when repeating evert week
|
||||
[] user - add createdAt field
|
||||
|
||||
[] FIX insecure logins
|
||||
[x] FIX insecure logins
|
||||
|
||||
[] nove push to form, - reorganize pWAManager to have session, role, subscriptions, etc...
|
||||
[] add shift name in calendar/ show in schedule if no assignments.
|
||||
[] show unpublished schedule if admin
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -25,8 +25,8 @@ apt install nodejs -y
|
||||
|
||||
##### ----------------- compose/deploy ----------------- ###
|
||||
# install docker if inside docker (vscode-server)# apt-get update && apt-get install -y docker.io
|
||||
# .10 > /mnt/apps/DEV/SSS/next-cart-app/next-cart-app/
|
||||
#.11 > cd /mnt/storage/DEV/workspace/repos/git.d-popov.com/next-cart-app/next-cart-app
|
||||
# !!! .10 > /mnt/apps/DEV/SSS/next-cart-app/next-cart-app/
|
||||
# !!! .11 > cd /mnt/storage/DEV/workspace/repos/git.d-popov.com/next-cart-app/next-cart-app
|
||||
|
||||
# using dockerfile and image:
|
||||
docker build -t jwpw:latest -f _deploy/prod.Dockerfile .
|
||||
@ -46,9 +46,9 @@ docker push docker.d-popov.com/jwpw:test
|
||||
--LATEST/
|
||||
cd /mnt/storage/DEV/workspace/repos/git.d-popov.com/mwhitnessing
|
||||
docker build -t docker.d-popov.com/jwpw:latest -f _deploy/prod.Dockerfile .
|
||||
docker tag docker.d-popov.com/jwpw:latest docker.d-popov.com/jwpw:0.9.95
|
||||
docker tag docker.d-popov.com/jwpw:latest docker.d-popov.com/jwpw:1.3.5
|
||||
docker push docker.d-popov.com/jwpw:latest
|
||||
docker push docker.d-popov.com/jwpw:0.9.95
|
||||
docker push docker.d-popov.com/jwpw:1.3.5
|
||||
|
||||
#---
|
||||
|
||||
@ -221,7 +221,8 @@ curl https://gist.githubusercontent.com/balazsorban44/09613175e7b37ec03f676dcefb
|
||||
################### sync folders
|
||||
# nc: WebDAV
|
||||
apk add rclone
|
||||
rclone config
|
||||
rclone config
|
||||
/52 https://cloud.d-popov.com sync syncsyncsyncsyncsyncsyncsync
|
||||
rclone sync /path/to/local/folder yourRemoteName:target-folder
|
||||
# nc
|
||||
sudo add-apt-repository ppa:nextcloud-devs/client
|
||||
@ -236,9 +237,11 @@ rclone config
|
||||
rclone lsd nextcloud: # {nc=remotename}
|
||||
rclone sync /path/to/local/folder gdrive:target-folder
|
||||
rclone sync /backup nextcloud:/mwitnessing [--dry-run] [--progress]
|
||||
rclone sync /backup nextcloud:/mwitnessing --dry-run --progress
|
||||
# pw-mariadb_backup-1
|
||||
rclone sync /backup nextcloud:/mwitnessing --dry-run --progress --delete-excluded
|
||||
rclone sync /mnt/docker_volumes/pw/data/backup nc:/mwitnessing --dry-run --progress
|
||||
crontab -e
|
||||
0 7 * * * rclone sync /backup nextcloud:/mwitnessing
|
||||
0 7 * * * rclone sync /backup nextcloud:/mwitnessing --delete-excluded
|
||||
|
||||
|
||||
|
||||
|
@ -27,7 +27,7 @@ class ErrorBoundary extends React.Component {
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
// Render any custom fallback UI
|
||||
return <h1>Нещо се обърка при изтриването. Моля, опитай отново и се свържете с нас ако проблема продължи. </h1>;
|
||||
return <h1>Нещо се обърка. Моля, опитай отново и се свържете с нас ако проблема продължи. </h1>;
|
||||
}
|
||||
|
||||
return this.props.children;
|
||||
|
@ -6,7 +6,7 @@ import e from 'express';
|
||||
import ProtectedRoute from './protectedRoute';
|
||||
import { UserRole } from '@prisma/client';
|
||||
|
||||
function PwaManager({ subs }) {
|
||||
function PwaManager({ userId, subs }) {
|
||||
//ToDo: for iOS, try to use apn? https://github.com/node-apn/node-apn/blob/master/doc/apn.markdown
|
||||
const isSupported = () =>
|
||||
'Notification' in window &&
|
||||
@ -271,6 +271,37 @@ function PwaManager({ subs }) {
|
||||
{ action: 'close', title: 'Затвори', icon: '❌' }]
|
||||
})
|
||||
});
|
||||
|
||||
/*
|
||||
await fetch('/api/notify', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
id: pub.id,
|
||||
message: "Тестово съобщение",
|
||||
title: "Това е тестово съобщение от https://sofia.mwitnessing.com",
|
||||
actions: [
|
||||
{ action: 'OK', title: 'OK', icon: '✅' },
|
||||
{ action: 'close', title: 'Затвори', icon: '❌' }
|
||||
]
|
||||
// actions: [
|
||||
// {
|
||||
// title: 'Open URL',
|
||||
// action: 'open_url',
|
||||
// icon: '/images/open-url.png'
|
||||
// },
|
||||
// {
|
||||
// title: 'Dismiss',
|
||||
// action: 'dismiss',
|
||||
// icon: '/images/dismiss.png'
|
||||
// }
|
||||
// ]
|
||||
})
|
||||
})
|
||||
*/
|
||||
|
||||
};
|
||||
|
||||
// async function sendTestReminder(event: MouseEvent<HTMLButtonElement, MouseEvent>): Promise<void> {
|
||||
@ -382,7 +413,7 @@ function PwaManager({ subs }) {
|
||||
>
|
||||
Тестово уведомление
|
||||
</button>
|
||||
</div>
|
||||
</div >
|
||||
{isAdmin &&
|
||||
<div>
|
||||
{/* <button
|
||||
@ -403,28 +434,31 @@ function PwaManager({ subs }) {
|
||||
</button> */}
|
||||
</div>
|
||||
}
|
||||
{notificationPermission !== "granted" && (
|
||||
<button
|
||||
onClick={togglePushNotifications}
|
||||
className={`text-xs py-1 px-2 rounded-full focus:outline-none transition duration-150 ease-in-out ${notificationPermission === "denied" ? 'bg-red-500 hover:bg-red-700 text-white' : 'bg-green-500 hover:bg-green-700 text-white'
|
||||
}`}
|
||||
>
|
||||
{notificationPermission === "denied" ? 'Notifications Denied!' : 'Enable Notifications'}
|
||||
</button>
|
||||
)}
|
||||
{
|
||||
notificationPermission !== "granted" && (
|
||||
<button
|
||||
onClick={togglePushNotifications}
|
||||
className={`text-xs py-1 px-2 rounded-full focus:outline-none transition duration-150 ease-in-out ${notificationPermission === "denied" ? 'bg-red-500 hover:bg-red-700 text-white' : 'bg-green-500 hover:bg-green-700 text-white'
|
||||
}`}
|
||||
>
|
||||
{notificationPermission === "denied" ? 'Notifications Denied!' : 'Enable Notifications'}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
{isAdmin && <div>
|
||||
<div>
|
||||
<a href="https://t.me/mwhitnessing_bot" className="inline-flex items-center ml-4" target="_blank">
|
||||
<img src="/content/icons/telegram-svgrepo-com.svg" alt="Телеграм" width="32" height="32" className="align-middle" />
|
||||
<span className="align-middle">Телеграм</span>
|
||||
</a>
|
||||
{
|
||||
isAdmin && <div>
|
||||
<div>
|
||||
<a href="https://t.me/mwhitnessing_bot" className="inline-flex items-center ml-4" target="_blank">
|
||||
<img src="/content/icons/telegram-svgrepo-com.svg" alt="Телеграм" width="32" height="32" className="align-middle" />
|
||||
<span className="align-middle">Телеграм</span>
|
||||
</a>
|
||||
|
||||
<a href="/api/auth/apple-signin" className="inline-flex items-center ml-4 bg-gray-100 button" target="_blank">
|
||||
<span className="align-middle">Apple sign-in</span>
|
||||
</a>
|
||||
<a href="/api/auth/apple-signin" className="inline-flex items-center ml-4 bg-gray-100 button" target="_blank">
|
||||
<span className="align-middle">Apple sign-in</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</>
|
||||
);
|
||||
|
@ -22,7 +22,7 @@ const fetchConfig = async () => {
|
||||
return config.default;
|
||||
};
|
||||
|
||||
export default function AvailabilityForm({ publisherId, existingItems, inline, onDone, date, cartEvent, datePicker = false }) {
|
||||
export default function AvailabilityForm({ publisherId, existingItems, inline, onDone, date, cartEvent, datePicker = false, lockedBeforeDate }) {
|
||||
|
||||
const router = useRouter();
|
||||
const urls = {
|
||||
@ -31,14 +31,15 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o
|
||||
};
|
||||
|
||||
const id = parseInt(router.query.id);
|
||||
//coalsce existingItems to empty array
|
||||
existingItems = existingItems || [];
|
||||
|
||||
const originalAvailabilities = existingItems || [];
|
||||
|
||||
const [editMode, setEditMode] = useState(existingItems.length > 0);
|
||||
const [publisher, setPublisher] = useState({ id: publisherId });
|
||||
const [day, setDay] = useState(new Date(date));
|
||||
const [canUpdate, setCanUpdate] = useState(true);
|
||||
|
||||
|
||||
const [timeSlots, setTimeSlots] = useState([]);
|
||||
const [availabilities, setAvailabilities] = useState(existingItems && existingItems.length > 0 ? existingItems : [{
|
||||
publisherId: publisher.id,
|
||||
@ -143,6 +144,35 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o
|
||||
setAvailabilities(avs);
|
||||
}
|
||||
|
||||
|
||||
// Handle repetition logic
|
||||
// const parentAvailabilityId = avs[0].id;
|
||||
// originalAvailabilities.forEach(async av => {
|
||||
// if (av.repeatWeekly && av.startTime < lockedBeforeDate) {
|
||||
// const newDate = av.startTime;
|
||||
// while (newDate < lockedBeforeDate) {
|
||||
// const newAvailability = {
|
||||
// ...av,
|
||||
// startTime: newDate,
|
||||
// parentAvailability: { connect: { id: parentAvailabilityId } },
|
||||
// publisher: { connect: { id: publisher.id } },
|
||||
// dateOfEntry: new Date(),
|
||||
// type: "OneTime"
|
||||
// };
|
||||
|
||||
// delete newAvailability.id;
|
||||
// delete newAvailability.title;
|
||||
// delete newAvailability.date;
|
||||
// delete newAvailability.publisherId
|
||||
|
||||
// await axiosInstance.post(urls.apiUrl, newAvailability);
|
||||
// newDate.setDate(newDate.getDate() + 7); // Repeat weekly
|
||||
// }
|
||||
// }
|
||||
// console.log("Updated availability: ", av)
|
||||
// }
|
||||
// );
|
||||
|
||||
handleCompletion({ updated: true });
|
||||
} catch (error) {
|
||||
alert("Нещо се обърка. Моля, опитайте отново по-късно.");
|
||||
@ -220,9 +250,9 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o
|
||||
availability.dateOfEntry = new Date();
|
||||
}
|
||||
|
||||
function createAvailabilityFromGroup(group) {
|
||||
function createAvailabilityFromGroup(group, publisherId) {
|
||||
let availability = {
|
||||
publisherId: publisher.id,
|
||||
publisherId: publisherId,
|
||||
dayofweek: common.getDayOfWeekNameEnEnumForDate(day),
|
||||
};
|
||||
|
||||
|
@ -62,6 +62,28 @@ const AvCalendar = ({ publisherId, events, selectedDate, cartEvents, lastPublish
|
||||
}, []);
|
||||
//const isAdmin = ProtectedRoute.IsInRole(UserRole.ADMIN);
|
||||
|
||||
//block dates between 1 and 18 august 2024
|
||||
const blockedDates = [
|
||||
new Date(2024, 7, 1),
|
||||
new Date(2024, 7, 2),
|
||||
new Date(2024, 7, 3),
|
||||
new Date(2024, 7, 4),
|
||||
new Date(2024, 7, 5),
|
||||
new Date(2024, 7, 6),
|
||||
new Date(2024, 7, 7),
|
||||
new Date(2024, 7, 8),
|
||||
new Date(2024, 7, 9),
|
||||
new Date(2024, 7, 10),
|
||||
new Date(2024, 7, 11),
|
||||
new Date(2024, 7, 12),
|
||||
new Date(2024, 7, 13),
|
||||
new Date(2024, 7, 14),
|
||||
new Date(2024, 7, 15),
|
||||
new Date(2024, 7, 16),
|
||||
new Date(2024, 7, 17),
|
||||
new Date(2024, 7, 18),
|
||||
];
|
||||
|
||||
const [date, setDate] = useState(new Date());
|
||||
//ToDo: see if we can optimize this
|
||||
const [evts, setEvents] = useState(events); // Existing events
|
||||
@ -243,6 +265,11 @@ const AvCalendar = ({ publisherId, events, selectedDate, cartEvents, lastPublish
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if (blockedDates[0] <= startdate && startdate <= blockedDates[blockedDates.length - 1]) {
|
||||
toast.error(`Не можете да въвеждате предпочитания за ${common.getDateFormattedShort(startdate)}`, { autoClose: 5000 });
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Check if start and end are on the same day
|
||||
if (startdate.toDateString() !== enddate.toDateString()) {
|
||||
@ -539,6 +566,27 @@ const AvCalendar = ({ publisherId, events, selectedDate, cartEvents, lastPublish
|
||||
},
|
||||
// ... other custom components
|
||||
}}
|
||||
dayPropGetter={(date) => {
|
||||
// Highlight the current day
|
||||
// if (date.toDateString() === new Date().toDateString()) {
|
||||
// return {
|
||||
// style: {
|
||||
// // white-500 from Tailwind CSS
|
||||
// backgroundColor: '#f9fafb',
|
||||
// color: 'white'
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
if (blockedDates[0] <= date && date <= blockedDates[blockedDates.length - 1]) {
|
||||
return {
|
||||
style: {
|
||||
// red-100 from Tailwind CSS
|
||||
backgroundColor: '#fee2e2',
|
||||
color: 'white'
|
||||
}
|
||||
};
|
||||
}
|
||||
}}
|
||||
eventPropGetter={(eventStyleGetter)}
|
||||
date={date}
|
||||
showAllEvents={true}
|
||||
@ -556,6 +604,7 @@ const AvCalendar = ({ publisherId, events, selectedDate, cartEvents, lastPublish
|
||||
onDone={handleDialogClose}
|
||||
inline={true}
|
||||
cartEvent={cartEvent}
|
||||
lockedBeforeDate={editLockedBefore}
|
||||
// Pass other props as needed
|
||||
/>
|
||||
</div>
|
||||
|
@ -303,7 +303,8 @@ export default function PublisherForm({ item, me }) {
|
||||
{/* In-App notifications group */}
|
||||
<div className="mb-4">
|
||||
<h3 className="text-md font-semibold mb-2">Известия в приложението</h3>
|
||||
<PwaManager />
|
||||
<PwaManager userId={publisher.userId || session.user.id} />
|
||||
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
189
components/publisher/PublisherShiftsModal.js
Normal file
189
components/publisher/PublisherShiftsModal.js
Normal file
@ -0,0 +1,189 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import Link from 'next/link';
|
||||
import common from 'src/helpers/common';
|
||||
import axiosInstance from 'src/axiosSecure';
|
||||
|
||||
const PublisherShiftsModal = ({ publisher, _shifts, onClose, date, onAssignmentChange }) => {
|
||||
|
||||
const [shifts, setShifts] = React.useState([..._shifts]);
|
||||
//Refactor ToDo: show the whole month instead of just the current week by showing the shift start time in front of the rows, and show all shifts in the month from the first to the last week in the cell where we show one shift now
|
||||
|
||||
const monthInfo = common.getMonthDatesInfo(new Date(date));
|
||||
const monthShifts = shifts.filter(shift => {
|
||||
const shiftDate = new Date(shift.startTime);
|
||||
return shiftDate > monthInfo.firstDay && shiftDate < monthInfo.lastDay;
|
||||
});
|
||||
const weekShifts = monthShifts.filter(shift => {
|
||||
const shiftDate = new Date(shift.startTime);
|
||||
return common.getStartOfWeek(date) <= shiftDate && shiftDate <= common.getEndOfWeek(date);
|
||||
});
|
||||
const dayShifts = weekShifts.map(shift => {
|
||||
const isAvailable = publisher?.availabilities?.some(avail =>
|
||||
avail.startTime <= shift.startTime && avail.endTime >= shift.endTime
|
||||
);
|
||||
let color = isAvailable ? getColorForShift(shift) : 'bg-gray-300';
|
||||
if (shift.isFromPreviousMonth) {
|
||||
color += ' border-l-4 border-orange-500 ';
|
||||
}
|
||||
if (shift.isFromPreviousAssignment) {
|
||||
color += ' border-l-4 border-red-500 ';
|
||||
}
|
||||
return { ...shift, isAvailable, color };
|
||||
}).reduce((acc, shift) => {
|
||||
const dayIndex = new Date(shift.startTime).getDay();
|
||||
acc[dayIndex] = acc[dayIndex] || [];
|
||||
acc[dayIndex].push(shift);
|
||||
return acc;
|
||||
}, {});
|
||||
console.log("dayShifts:", dayShifts);
|
||||
|
||||
const hasAssignment = (shiftId) => {
|
||||
// return publisher.assignments.some(ass => ass.shift.id == shiftId);
|
||||
return publisher.assignments?.some(ass => {
|
||||
//console.log(`Comparing: ${ass.shift.id} to ${shiftId}: ${ass.shift.id === shiftId}`);
|
||||
return ass.shift.id === shiftId;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (event) => {
|
||||
if (event.key === 'Escape') {
|
||||
console.log('ESC: closing modal.');
|
||||
onClose(); // Call the onClose function when ESC key is pressed
|
||||
}
|
||||
};
|
||||
|
||||
// Add event listener
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
|
||||
// Remove event listener on cleanup
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
}, [onClose]); // Include onClose in the dependency array
|
||||
|
||||
return (
|
||||
<div className="fixed top-0 left-0 w-full h-full flex items-center justify-center bg-black bg-opacity-50 z-50">
|
||||
<div className="relative bg-white p-8 rounded-lg shadow-xl max-w-xl w-full h-auto overflow-y-auto">
|
||||
<h2 className="text-xl font-semibold mb-4">График на <span title={publisher.email} className='publisher'>
|
||||
<strong>{publisher.firstName} {publisher.lastName}</strong>
|
||||
<span className="publisher-tooltip" onClick={common.copyToClipboard}>{publisher.email}</span>
|
||||
</span> тази седмица:</h2>
|
||||
|
||||
{/* ... Display shifts in a calendar-like UI ... */}
|
||||
<div className="grid grid-cols-6 gap-4 mb-4">
|
||||
{Object.entries(dayShifts).map(([dayIndex, shiftsForDay]) => (
|
||||
<div key={dayIndex} className="flex flex-col space-y-2 justify-end">
|
||||
{/* Day header */}
|
||||
<div className="text-center font-medium">{new Date(shiftsForDay[0].startTime).getDate()}-ти</div>
|
||||
|
||||
{shiftsForDay.map((shift, index) => {
|
||||
const assignmentExists = hasAssignment(shift.id);
|
||||
const availability = publisher.availabilities.find(avail =>
|
||||
avail.startTime <= shift.startTime && avail.endTime >= shift.endTime
|
||||
);
|
||||
const isFromPrevMonth = availability && availability.isFromPreviousMonth;
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className={`text-sm text-white p-2 rounded-md ${isFromPrevMonth ? 'border-l-6 border-black-500' : ''} ${shift.color} ${assignmentExists ? 'border-2 border-blue-500' : ""} h-24 flex flex-col justify-center`}
|
||||
>
|
||||
{common.getTimeRange(shift.startTime, shift.endTime)} {shift.id}
|
||||
|
||||
{!assignmentExists && shift.isAvailable && (
|
||||
<button onClick={() => { addAssignment(publisher, shift.id); }}
|
||||
className="mt-2 bg-green-500 text-white p-1 rounded hover:bg-green-600 active:bg-green-700 focus:outline-none"
|
||||
>
|
||||
добави
|
||||
</button>
|
||||
)}
|
||||
{assignmentExists && (
|
||||
<button onClick={() => { removeAssignment(publisher, shift.id) }} // Implement the removeAssignment function
|
||||
className="mt-2 bg-red-500 text-white p-1 rounded hover:bg-red-600 active:bg-red-700 focus:outline-none"
|
||||
>
|
||||
махни
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Close button in the top right corner */}
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="absolute top-3 right-2 p-2 px-3 bg-red-500 text-white rounded-full hover:bg-red-600 active:bg-red-700 focus:outline-none"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
|
||||
{/* <Link href={`/cart/publishers/edit/${publisher.id}`}
|
||||
className="mt-2 bg-blue-500 text-white p-1 rounded hover:bg-blue-600 active:bg-blue-700 focus:outline-none">
|
||||
<i className="fas fa-edit" />
|
||||
</Link> */}
|
||||
{/* Edit button in the top right corner, next to the close button */}
|
||||
<Link href={`/cart/publishers/edit/${publisher.id}`} className="absolute top-3 right-12 p-2 bg-blue-500 text-white rounded-full hover:bg-blue-600 active:bg-blue-700 focus:outline-none">
|
||||
<i className="fas fa-edit" />
|
||||
</Link>
|
||||
|
||||
</div>
|
||||
</div >
|
||||
);
|
||||
}
|
||||
|
||||
function getColorForShift(shift) {
|
||||
const assignedCount = shift.assignedCount || 0; // Assuming each shift has an assignedCount property
|
||||
switch (assignedCount) {
|
||||
case 0: return 'bg-blue-300';
|
||||
case 1: return 'bg-green-300';
|
||||
case 2: return 'bg-yellow-300';
|
||||
case 3: return 'bg-orange-300';
|
||||
case 4: return 'bg-red-200';
|
||||
default: return 'bg-gray-300';
|
||||
}
|
||||
}
|
||||
|
||||
//ToDo: DRY - move to common
|
||||
const addAssignment = async (publisher, shiftId) => {
|
||||
try {
|
||||
console.log(`calendar.idx: new assignment for publisher ${publisher.id} - ${publisher.firstName} ${publisher.lastName}`);
|
||||
const newAssignment = {
|
||||
publisher: { connect: { id: publisher.id } },
|
||||
shift: { connect: { id: shiftId } },
|
||||
isConfirmed: true
|
||||
};
|
||||
const { data } = await axiosInstance.post("/api/data/assignments", newAssignment);
|
||||
|
||||
// Update the 'publisher' property of the returned data with the full publisher object
|
||||
data.publisher = publisher;
|
||||
data.shift = shifts.find(shift => shift.id === shiftId);
|
||||
publisher.assignments = [...publisher.assignments, data];
|
||||
// handleAssignmentChange(publisher.id, 'add');
|
||||
if (onAssignmentChange) { onAssignmentChange(publisher.id, 'add'); }
|
||||
} catch (error) {
|
||||
console.error("Error adding assignment:", error);
|
||||
}
|
||||
};
|
||||
const removeAssignment = async (publisher, shiftId) => {
|
||||
try {
|
||||
const assignment = publisher.assignments.find(ass => ass.shift.id === shiftId);
|
||||
console.log(`calendar.idx: remove assignment for shift ${shiftId}`);
|
||||
const { data } = await axiosInstance.delete(`/api/data/assignments/${assignment.id}`);
|
||||
//remove from local assignments:
|
||||
publisher.assignments = publisher.assignments.filter(a => a.id !== assignment.id)
|
||||
//
|
||||
// handleAssignmentChange(publisher.id, 'remove')
|
||||
if (onAssignmentChange) {
|
||||
onAssignmentChange(publisher.id, 'remove')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error removing assignment:", error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default PublisherShiftsModal;
|
@ -158,7 +158,7 @@ export default function ReportForm({ shiftId, existingItem, onDone }) {
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<div className="mb-4">
|
||||
{/* <div className="mb-4">
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
@ -168,7 +168,7 @@ export default function ReportForm({ shiftId, existingItem, onDone }) {
|
||||
/>
|
||||
за целия ден
|
||||
</label>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
|
@ -62,8 +62,8 @@ const SurveyForm: React.FC<SurveyFormProps> = ({ existingItem }) => {
|
||||
...existingItem,
|
||||
content: existingItem?.content || "Нова анкета",
|
||||
answers: existingItem?.answers.split(",") || [],
|
||||
publicFrom: existingItem?.publicFrom ? dayjs(existingItem.publicFrom).toISOString() : new Date().toISOString(),
|
||||
publicUntil: existingItem?.publicUntil ? dayjs(existingItem.publicUntil).toISOString() : new Date().toISOString(),
|
||||
publicFrom: existingItem?.publicFrom ? dayjs(existingItem.publicFrom).toISOString() : '',
|
||||
publicUntil: existingItem?.publicUntil ? dayjs(existingItem.publicUntil).toISOString() : null,
|
||||
});
|
||||
|
||||
|
||||
@ -104,7 +104,7 @@ const SurveyForm: React.FC<SurveyFormProps> = ({ existingItem }) => {
|
||||
}
|
||||
else {
|
||||
//get all publisherIds and create a message for each
|
||||
const messages = pubs.data.map(pub => {
|
||||
const messages = pubs.map(pub => {
|
||||
return {
|
||||
publisherId: pub.id,
|
||||
content: JSON.stringify({ message: item.content, options: item.answers }),
|
||||
@ -211,7 +211,7 @@ const SurveyForm: React.FC<SurveyFormProps> = ({ existingItem }) => {
|
||||
},
|
||||
body: JSON.stringify({
|
||||
id,
|
||||
title: 'Нямаме отговор',
|
||||
title: 'Напомняне',
|
||||
message: `${message}`,
|
||||
})
|
||||
});
|
||||
@ -236,13 +236,16 @@ const SurveyForm: React.FC<SurveyFormProps> = ({ existingItem }) => {
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="date">
|
||||
Видима от
|
||||
</label>
|
||||
<DatePicker className="textbox form-input px-4 py-2 rounded" name="publicFrom" onChange={(newDate) => handleDateChange('publicFrom', newDate)} value={dayjs(item?.publicFrom)} />
|
||||
<DatePicker className="textbox form-input px-4 py-2 rounded" name="publicFrom" onChange={(newDate) => handleDateChange('publicFrom', newDate)}
|
||||
value={item && item.publicFrom ? dayjs(item.publicFrom) : null} />
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="date">
|
||||
Видима до
|
||||
</label>
|
||||
<DatePicker className="textbox form-input px-4 py-2 rounded" name="publicUntil" onChange={(newDate) => handleDateChange('publicUntil', newDate)} value={dayjs(item?.publicUntil)} />
|
||||
<DatePicker className="textbox form-input px-4 py-2 rounded" name="publicUntil" onChange={(newDate) => handleDateChange('publicUntil', newDate)}
|
||||
value={item && item.publicUntil ? dayjs(item.publicUntil) : null}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="content">
|
||||
|
577
package-lock.json
generated
577
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "smws",
|
||||
"version": "1.2.4",
|
||||
"version": "1.3.5",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "smws",
|
||||
"version": "1.2.4",
|
||||
"version": "1.3.5",
|
||||
"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.15.0",
|
||||
"@prisma/client": "^5.19.1",
|
||||
"@react-pdf/renderer": "^3.3.8",
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@types/multer": "^1.4.11",
|
||||
@ -93,14 +93,14 @@
|
||||
"winston-daily-rotate-file": "^5.0.0",
|
||||
"workbox-webpack-plugin": "^7.1.0",
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.19.1/xlsx-0.19.1.tgz",
|
||||
"xlsx-style": "^0.8.13",
|
||||
"xlsx-js-style": "^1.2.0",
|
||||
"xml-js": "^1.6.11",
|
||||
"xml2js": "^0.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "^7.0.3",
|
||||
"depcheck": "^1.4.7",
|
||||
"prisma": "^5.15.0"
|
||||
"prisma": "^5.19.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@alloc/quick-lru": {
|
||||
@ -3239,14 +3239,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/env": {
|
||||
"version": "14.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-14.1.0.tgz",
|
||||
"integrity": "sha512-Py8zIo+02ht82brwwhTg36iogzFqGLPXlRGKQw5s+qP/kMNc4MAyDeEwBKDijk6zTIbegEgu8Qy7C1LboslQAw=="
|
||||
"version": "14.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.10.tgz",
|
||||
"integrity": "sha512-dZIu93Bf5LUtluBXIv4woQw2cZVZ2DJTjax5/5DOs3lzEOeKLy7GxRSr4caK9/SCPdaW6bCgpye6+n4Dh9oJPw=="
|
||||
},
|
||||
"node_modules/@next/swc-darwin-arm64": {
|
||||
"version": "14.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.1.0.tgz",
|
||||
"integrity": "sha512-nUDn7TOGcIeyQni6lZHfzNoo9S0euXnu0jhsbMOmMJUBfgsnESdjN97kM7cBqQxZa8L/bM9om/S5/1dzCrW6wQ==",
|
||||
"version": "14.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.10.tgz",
|
||||
"integrity": "sha512-V3z10NV+cvMAfxQUMhKgfQnPbjw+Ew3cnr64b0lr8MDiBJs3eLnM6RpGC46nhfMZsiXgQngCJKWGTC/yDcgrDQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -3259,9 +3259,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-x64": {
|
||||
"version": "14.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.0.tgz",
|
||||
"integrity": "sha512-1jgudN5haWxiAl3O1ljUS2GfupPmcftu2RYJqZiMJmmbBT5M1XDffjUtRUzP4W3cBHsrvkfOFdQ71hAreNQP6g==",
|
||||
"version": "14.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.10.tgz",
|
||||
"integrity": "sha512-Y0TC+FXbFUQ2MQgimJ/7Ina2mXIKhE7F+GUe1SgnzRmwFY3hX2z8nyVCxE82I2RicspdkZnSWMn4oTjIKz4uzA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -3274,9 +3274,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||
"version": "14.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.0.tgz",
|
||||
"integrity": "sha512-RHo7Tcj+jllXUbK7xk2NyIDod3YcCPDZxj1WLIYxd709BQ7WuRYl3OWUNG+WUfqeQBds6kvZYlc42NJJTNi4tQ==",
|
||||
"version": "14.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.10.tgz",
|
||||
"integrity": "sha512-ZfQ7yOy5zyskSj9rFpa0Yd7gkrBnJTkYVSya95hX3zeBG9E55Z6OTNPn1j2BTFWvOVVj65C3T+qsjOyVI9DQpA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -3289,9 +3289,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-musl": {
|
||||
"version": "14.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.0.tgz",
|
||||
"integrity": "sha512-v6kP8sHYxjO8RwHmWMJSq7VZP2nYCkRVQ0qolh2l6xroe9QjbgV8siTbduED4u0hlk0+tjS6/Tuy4n5XCp+l6g==",
|
||||
"version": "14.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.10.tgz",
|
||||
"integrity": "sha512-n2i5o3y2jpBfXFRxDREr342BGIQCJbdAUi/K4q6Env3aSx8erM9VuKXHw5KNROK9ejFSPf0LhoSkU/ZiNdacpQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -3304,9 +3304,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-gnu": {
|
||||
"version": "14.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.0.tgz",
|
||||
"integrity": "sha512-zJ2pnoFYB1F4vmEVlb/eSe+VH679zT1VdXlZKX+pE66grOgjmKJHKacf82g/sWE4MQ4Rk2FMBCRnX+l6/TVYzQ==",
|
||||
"version": "14.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.10.tgz",
|
||||
"integrity": "sha512-GXvajAWh2woTT0GKEDlkVhFNxhJS/XdDmrVHrPOA83pLzlGPQnixqxD8u3bBB9oATBKB//5e4vpACnx5Vaxdqg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -3319,9 +3319,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-musl": {
|
||||
"version": "14.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.0.tgz",
|
||||
"integrity": "sha512-rbaIYFt2X9YZBSbH/CwGAjbBG2/MrACCVu2X0+kSykHzHnYH5FjHxwXLkcoJ10cX0aWCEynpu+rP76x0914atg==",
|
||||
"version": "14.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.10.tgz",
|
||||
"integrity": "sha512-opFFN5B0SnO+HTz4Wq4HaylXGFV+iHrVxd3YvREUX9K+xfc4ePbRrxqOuPOFjtSuiVouwe6uLeDtabjEIbkmDA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -3334,9 +3334,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||
"version": "14.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.0.tgz",
|
||||
"integrity": "sha512-o1N5TsYc8f/HpGt39OUQpQ9AKIGApd3QLueu7hXk//2xq5Z9OxmV6sQfNp8C7qYmiOlHYODOGqNNa0e9jvchGQ==",
|
||||
"version": "14.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.10.tgz",
|
||||
"integrity": "sha512-9NUzZuR8WiXTvv+EiU/MXdcQ1XUvFixbLIMNQiVHuzs7ZIFrJDLJDaOF1KaqttoTujpcxljM/RNAOmw1GhPPQQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -3349,9 +3349,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-ia32-msvc": {
|
||||
"version": "14.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.0.tgz",
|
||||
"integrity": "sha512-XXIuB1DBRCFwNO6EEzCTMHT5pauwaSj4SWs7CYnME57eaReAKBXCnkUE80p/pAZcewm7hs+vGvNqDPacEXHVkw==",
|
||||
"version": "14.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.10.tgz",
|
||||
"integrity": "sha512-fr3aEbSd1GeW3YUMBkWAu4hcdjZ6g4NBl1uku4gAn661tcxd1bHs1THWYzdsbTRLcCKLjrDZlNp6j2HTfrw+Bg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@ -3364,9 +3364,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-x64-msvc": {
|
||||
"version": "14.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.0.tgz",
|
||||
"integrity": "sha512-9WEbVRRAqJ3YFVqEZIxUqkiO8l1nool1LmNxygr5HWF8AcSYsEpneUDhmjUVJEzO2A04+oPtZdombzzPPkTtgg==",
|
||||
"version": "14.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.10.tgz",
|
||||
"integrity": "sha512-UjeVoRGKNL2zfbcQ6fscmgjBAS/inHBh63mjIlfPg/NG8Yn2ztqylXt5qilYb6hoHIwaU2ogHknHWWmahJjgZQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -3915,9 +3915,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@prisma/client": {
|
||||
"version": "5.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.15.0.tgz",
|
||||
"integrity": "sha512-wPTeTjbd2Q0abOeffN7zCDCbkp9C9cF+e9HPiI64lmpehyq2TepgXE+sY7FXr7Rhbb21prLMnhXX27/E11V09w==",
|
||||
"version": "5.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.19.1.tgz",
|
||||
"integrity": "sha512-x30GFguInsgt+4z5I4WbkZP2CGpotJMUXy+Gl/aaUjHn2o1DnLYNTA+q9XdYmAQZM8fIIkvUiA2NpgosM3fneg==",
|
||||
"hasInstallScript": true,
|
||||
"engines": {
|
||||
"node": ">=16.13"
|
||||
@ -3932,39 +3932,39 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@prisma/debug": {
|
||||
"version": "5.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.15.0.tgz",
|
||||
"integrity": "sha512-QpEAOjieLPc/4sMny/WrWqtpIAmBYsgqwWlWwIctqZO0AbhQ9QcT6x2Ut3ojbDo/pFRCCA1Z1+xm2MUy7fAkZA==",
|
||||
"version": "5.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.19.1.tgz",
|
||||
"integrity": "sha512-lAG6A6QnG2AskAukIEucYJZxxcSqKsMK74ZFVfCTOM/7UiyJQi48v6TQ47d6qKG3LbMslqOvnTX25dj/qvclGg==",
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/@prisma/engines": {
|
||||
"version": "5.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.15.0.tgz",
|
||||
"integrity": "sha512-hXL5Sn9hh/ZpRKWiyPA5GbvF3laqBHKt6Vo70hYqqOhh5e0ZXDzHcdmxNvOefEFeqxra2DMz2hNbFoPvqrVe1w==",
|
||||
"version": "5.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.19.1.tgz",
|
||||
"integrity": "sha512-kR/PoxZDrfUmbbXqqb8SlBBgCjvGaJYMCOe189PEYzq9rKqitQ2fvT/VJ8PDSe8tTNxhc2KzsCfCAL+Iwm/7Cg==",
|
||||
"devOptional": true,
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@prisma/debug": "5.15.0",
|
||||
"@prisma/engines-version": "5.15.0-29.12e25d8d06f6ea5a0252864dd9a03b1bb51f3022",
|
||||
"@prisma/fetch-engine": "5.15.0",
|
||||
"@prisma/get-platform": "5.15.0"
|
||||
"@prisma/debug": "5.19.1",
|
||||
"@prisma/engines-version": "5.19.1-2.69d742ee20b815d88e17e54db4a2a7a3b30324e3",
|
||||
"@prisma/fetch-engine": "5.19.1",
|
||||
"@prisma/get-platform": "5.19.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@prisma/engines-version": {
|
||||
"version": "5.15.0-29.12e25d8d06f6ea5a0252864dd9a03b1bb51f3022",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.15.0-29.12e25d8d06f6ea5a0252864dd9a03b1bb51f3022.tgz",
|
||||
"integrity": "sha512-3BEgZ41Qb4oWHz9kZNofToRvNeS4LZYaT9pienR1gWkjhky6t6K1NyeWNBkqSj2llgraUNbgMOCQPY4f7Qp5wA==",
|
||||
"version": "5.19.1-2.69d742ee20b815d88e17e54db4a2a7a3b30324e3",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.19.1-2.69d742ee20b815d88e17e54db4a2a7a3b30324e3.tgz",
|
||||
"integrity": "sha512-xR6rt+z5LnNqTP5BBc+8+ySgf4WNMimOKXRn6xfNRDSpHvbOEmd7+qAOmzCrddEc4Cp8nFC0txU14dstjH7FXA==",
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/@prisma/fetch-engine": {
|
||||
"version": "5.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.15.0.tgz",
|
||||
"integrity": "sha512-z6AY5yyXxc20Klj7wwnfGP0iIUkVKzybqapT02zLYR/nf9ynaeN8bq73WRmi1TkLYn+DJ5Qy+JGu7hBf1pE78A==",
|
||||
"version": "5.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.19.1.tgz",
|
||||
"integrity": "sha512-pCq74rtlOVJfn4pLmdJj+eI4P7w2dugOnnTXpRilP/6n5b2aZiA4ulJlE0ddCbTPkfHmOL9BfaRgA8o+1rfdHw==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@prisma/debug": "5.15.0",
|
||||
"@prisma/engines-version": "5.15.0-29.12e25d8d06f6ea5a0252864dd9a03b1bb51f3022",
|
||||
"@prisma/get-platform": "5.15.0"
|
||||
"@prisma/debug": "5.19.1",
|
||||
"@prisma/engines-version": "5.19.1-2.69d742ee20b815d88e17e54db4a2a7a3b30324e3",
|
||||
"@prisma/get-platform": "5.19.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@prisma/generator-helper": {
|
||||
@ -3981,12 +3981,12 @@
|
||||
"integrity": "sha512-tZ+MOjWlVvz1kOEhNYMa4QUGURY+kgOUBqLHYIV8jmCsMuvA1tWcn7qtIMLzYWCbDcQT4ZS8xDgK0R2gl6/0wA=="
|
||||
},
|
||||
"node_modules/@prisma/get-platform": {
|
||||
"version": "5.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.15.0.tgz",
|
||||
"integrity": "sha512-1GULDkW4+/VQb73vihxCBSc4Chc2x88MA+O40tcZFjmBzG4/fF44PaXFxUqKSFltxU9L9GIMLhh0Gfkk/pUbtg==",
|
||||
"version": "5.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.19.1.tgz",
|
||||
"integrity": "sha512-sCeoJ+7yt0UjnR+AXZL7vXlg5eNxaFOwC23h0KvW1YIXUoa7+W2ZcAUhoEQBmJTW4GrFqCuZ8YSP0mkDa4k3Zg==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@prisma/debug": "5.15.0"
|
||||
"@prisma/debug": "5.19.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@prisma/internals": {
|
||||
@ -4366,6 +4366,11 @@
|
||||
"sourcemap-codec": "^1.4.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/counter": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
|
||||
"integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.4.36",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.36.tgz",
|
||||
@ -4443,26 +4448,6 @@
|
||||
"@types/ms": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/eslint": {
|
||||
"version": "8.56.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.7.tgz",
|
||||
"integrity": "sha512-SjDvI/x3zsZnOkYZ3lCt9lOZWZLB2jIlNKz+LBgCtDurK0JZcwucxYHn1w2BJkD34dgX9Tjnak0txtq4WTggEA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "*",
|
||||
"@types/json-schema": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/eslint-scope": {
|
||||
"version": "3.7.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
|
||||
"integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/eslint": "*",
|
||||
"@types/estree": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
||||
@ -4939,10 +4924,10 @@
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn-import-assertions": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz",
|
||||
"integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==",
|
||||
"node_modules/acorn-import-attributes": {
|
||||
"version": "1.9.5",
|
||||
"resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz",
|
||||
"integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"acorn": "^8"
|
||||
@ -5396,11 +5381,11 @@
|
||||
"integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg=="
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.6.7",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz",
|
||||
"integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==",
|
||||
"version": "1.7.7",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
|
||||
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.4",
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
@ -5617,20 +5602,20 @@
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.1",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
||||
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
|
||||
"version": "1.20.3",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
|
||||
"integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.4",
|
||||
"content-type": "~1.0.5",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"raw-body": "2.5.1",
|
||||
"qs": "6.13.0",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
@ -5639,20 +5624,6 @@
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser/node_modules/qs": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
||||
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
@ -5663,11 +5634,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/braces": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||
"dependencies": {
|
||||
"fill-range": "^7.0.1"
|
||||
"fill-range": "^7.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
@ -5878,9 +5849,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001588",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001588.tgz",
|
||||
"integrity": "sha512-+hVY9jE44uKLkH0SrUTqxjxqNTOWHsbnQDIKjwkZ3lNTzUUVdBLBGXtj/q5Mp5u98r3droaZAewQuEDzjQdZlQ==",
|
||||
"version": "1.0.30001651",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz",
|
||||
"integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@ -7284,9 +7255,9 @@
|
||||
"integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="
|
||||
},
|
||||
"node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
|
||||
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
@ -7323,9 +7294,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.16.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz",
|
||||
"integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==",
|
||||
"version": "5.17.1",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
|
||||
"integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
@ -7697,6 +7668,14 @@
|
||||
"url": "https://github.com/sindresorhus/execa?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/exit-on-epipe": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz",
|
||||
"integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/expand-tilde": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
|
||||
@ -7710,36 +7689,36 @@
|
||||
}
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "4.18.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
|
||||
"integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
|
||||
"version": "4.21.0",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz",
|
||||
"integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
"body-parser": "1.20.1",
|
||||
"body-parser": "1.20.3",
|
||||
"content-disposition": "0.5.4",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "0.5.0",
|
||||
"cookie": "0.6.0",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"encodeurl": "~1.0.2",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"finalhandler": "1.2.0",
|
||||
"finalhandler": "1.3.1",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "2.0.0",
|
||||
"merge-descriptors": "1.0.1",
|
||||
"merge-descriptors": "1.0.3",
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-to-regexp": "0.1.7",
|
||||
"path-to-regexp": "0.1.10",
|
||||
"proxy-addr": "~2.0.7",
|
||||
"qs": "6.11.0",
|
||||
"qs": "6.13.0",
|
||||
"range-parser": "~1.2.1",
|
||||
"safe-buffer": "5.2.1",
|
||||
"send": "0.18.0",
|
||||
"serve-static": "1.15.0",
|
||||
"send": "0.19.0",
|
||||
"serve-static": "1.16.2",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": "2.0.1",
|
||||
"type-is": "~1.6.18",
|
||||
@ -7768,32 +7747,10 @@
|
||||
"resolved": "https://registry.npmjs.org/express-unless/-/express-unless-2.1.3.tgz",
|
||||
"integrity": "sha512-wj4tLMyCVYuIIKHGt0FhCtIViBcwzWejX0EjNxveAa6dG+0XBCQhMbx+PnkLkFCxLC69qoFrxds4pIyL88inaQ=="
|
||||
},
|
||||
"node_modules/express/node_modules/cookie": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
|
||||
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/path-to-regexp": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
|
||||
},
|
||||
"node_modules/express/node_modules/qs": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
||||
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
"version": "0.1.10",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
|
||||
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w=="
|
||||
},
|
||||
"node_modules/extend": {
|
||||
"version": "3.0.2",
|
||||
@ -7877,6 +7834,11 @@
|
||||
"resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
|
||||
"integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="
|
||||
},
|
||||
"node_modules/fflate": {
|
||||
"version": "0.3.11",
|
||||
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.3.11.tgz",
|
||||
"integrity": "sha512-Rr5QlUeGN1mbOHlaqcSYMKVpPbgLy0AWT/W0EHxA6NGI12yO1jpoui2zBBvU2G824ltM6Ut8BFgfHSBGfkmS0A=="
|
||||
},
|
||||
"node_modules/file-stream-rotator": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/file-stream-rotator/-/file-stream-rotator-0.6.1.tgz",
|
||||
@ -7921,9 +7883,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
@ -7932,12 +7894,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/finalhandler": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
|
||||
"integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
|
||||
"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
"encodeurl": "~1.0.2",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
@ -8006,9 +7968,9 @@
|
||||
"integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.5",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
|
||||
"integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
|
||||
"version": "1.15.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@ -10643,9 +10605,12 @@
|
||||
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
|
||||
},
|
||||
"node_modules/merge-descriptors": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
||||
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
|
||||
"integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/merge-stream": {
|
||||
"version": "2.0.0",
|
||||
@ -10669,11 +10634,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/micromatch": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
|
||||
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||
"dependencies": {
|
||||
"braces": "^3.0.2",
|
||||
"braces": "^3.0.3",
|
||||
"picomatch": "^2.3.1"
|
||||
},
|
||||
"engines": {
|
||||
@ -10945,12 +10910,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/next": {
|
||||
"version": "14.1.0",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-14.1.0.tgz",
|
||||
"integrity": "sha512-wlzrsbfeSU48YQBjZhDzOwhWhGsy+uQycR8bHAOt1LY1bn3zZEcDyHQOEoN3aWzQ8LHCAJ1nqrWCc9XF2+O45Q==",
|
||||
"version": "14.2.10",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-14.2.10.tgz",
|
||||
"integrity": "sha512-sDDExXnh33cY3RkS9JuFEKaS4HmlWmDKP1VJioucCG6z5KuA008DPsDZOzi8UfqEk3Ii+2NCQSJrfbEWtZZfww==",
|
||||
"dependencies": {
|
||||
"@next/env": "14.1.0",
|
||||
"@swc/helpers": "0.5.2",
|
||||
"@next/env": "14.2.10",
|
||||
"@swc/helpers": "0.5.5",
|
||||
"busboy": "1.6.0",
|
||||
"caniuse-lite": "^1.0.30001579",
|
||||
"graceful-fs": "^4.2.11",
|
||||
@ -10964,18 +10929,19 @@
|
||||
"node": ">=18.17.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@next/swc-darwin-arm64": "14.1.0",
|
||||
"@next/swc-darwin-x64": "14.1.0",
|
||||
"@next/swc-linux-arm64-gnu": "14.1.0",
|
||||
"@next/swc-linux-arm64-musl": "14.1.0",
|
||||
"@next/swc-linux-x64-gnu": "14.1.0",
|
||||
"@next/swc-linux-x64-musl": "14.1.0",
|
||||
"@next/swc-win32-arm64-msvc": "14.1.0",
|
||||
"@next/swc-win32-ia32-msvc": "14.1.0",
|
||||
"@next/swc-win32-x64-msvc": "14.1.0"
|
||||
"@next/swc-darwin-arm64": "14.2.10",
|
||||
"@next/swc-darwin-x64": "14.2.10",
|
||||
"@next/swc-linux-arm64-gnu": "14.2.10",
|
||||
"@next/swc-linux-arm64-musl": "14.2.10",
|
||||
"@next/swc-linux-x64-gnu": "14.2.10",
|
||||
"@next/swc-linux-x64-musl": "14.2.10",
|
||||
"@next/swc-win32-arm64-msvc": "14.2.10",
|
||||
"@next/swc-win32-ia32-msvc": "14.2.10",
|
||||
"@next/swc-win32-x64-msvc": "14.2.10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentelemetry/api": "^1.1.0",
|
||||
"@playwright/test": "^1.41.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"sass": "^1.3.0"
|
||||
@ -10984,6 +10950,9 @@
|
||||
"@opentelemetry/api": {
|
||||
"optional": true
|
||||
},
|
||||
"@playwright/test": {
|
||||
"optional": true
|
||||
},
|
||||
"sass": {
|
||||
"optional": true
|
||||
}
|
||||
@ -11025,9 +10994,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/next-auth/node_modules/jose": {
|
||||
"version": "4.15.4",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-4.15.4.tgz",
|
||||
"integrity": "sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==",
|
||||
"version": "4.15.9",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz",
|
||||
"integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/panva"
|
||||
}
|
||||
@ -11431,10 +11400,11 @@
|
||||
"integrity": "sha512-f7h4svPtl+QidoBv4taKXUjJ70G2asaZ8G28nS0OkqaalX8dwwrtWtyxEDPK62AC00ur/+/E0pUwBwY5EPn15Q=="
|
||||
},
|
||||
"node_modules/next/node_modules/@swc/helpers": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz",
|
||||
"integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==",
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz",
|
||||
"integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==",
|
||||
"dependencies": {
|
||||
"@swc/counter": "^0.1.3",
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
@ -14583,9 +14553,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/openid-client/node_modules/jose": {
|
||||
"version": "4.15.4",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-4.15.4.tgz",
|
||||
"integrity": "sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==",
|
||||
"version": "4.15.9",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz",
|
||||
"integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/panva"
|
||||
}
|
||||
@ -15118,20 +15088,34 @@
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz",
|
||||
"integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew=="
|
||||
},
|
||||
"node_modules/printj": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz",
|
||||
"integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==",
|
||||
"bin": {
|
||||
"printj": "bin/printj.njs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/prisma": {
|
||||
"version": "5.15.0",
|
||||
"resolved": "https://registry.npmjs.org/prisma/-/prisma-5.15.0.tgz",
|
||||
"integrity": "sha512-JA81ACQSCi3a7NUOgonOIkdx8PAVkO+HbUOxmd00Yb8DgIIEpr2V9+Qe/j6MLxIgWtE/OtVQ54rVjfYRbZsCfw==",
|
||||
"version": "5.19.1",
|
||||
"resolved": "https://registry.npmjs.org/prisma/-/prisma-5.19.1.tgz",
|
||||
"integrity": "sha512-c5K9MiDaa+VAAyh1OiYk76PXOme9s3E992D7kvvIOhCrNsBQfy2mP2QAQtX0WNj140IgG++12kwZpYB9iIydNQ==",
|
||||
"devOptional": true,
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@prisma/engines": "5.15.0"
|
||||
"@prisma/engines": "5.19.1"
|
||||
},
|
||||
"bin": {
|
||||
"prisma": "build/index.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.13"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "2.3.3"
|
||||
}
|
||||
},
|
||||
"node_modules/prisma-json-schema-generator": {
|
||||
@ -15248,11 +15232,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.11.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz",
|
||||
"integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==",
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
||||
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.0.4"
|
||||
"side-channel": "^1.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
@ -15367,9 +15351,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/raw-body": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
||||
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
|
||||
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"http-errors": "2.0.0",
|
||||
@ -16318,9 +16302,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/send": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
|
||||
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
|
||||
"version": "0.19.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
|
||||
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
@ -16340,6 +16324,14 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/send/node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/send/node_modules/mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
@ -16365,14 +16357,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/serve-static": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
|
||||
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
|
||||
"version": "1.16.2",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
|
||||
"integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
|
||||
"dependencies": {
|
||||
"encodeurl": "~1.0.2",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"parseurl": "~1.3.3",
|
||||
"send": "0.18.0"
|
||||
"send": "0.19.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
@ -18386,21 +18378,20 @@
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.91.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz",
|
||||
"integrity": "sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==",
|
||||
"version": "5.94.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz",
|
||||
"integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
"@types/estree": "^1.0.5",
|
||||
"@webassemblyjs/ast": "^1.12.1",
|
||||
"@webassemblyjs/wasm-edit": "^1.12.1",
|
||||
"@webassemblyjs/wasm-parser": "^1.12.1",
|
||||
"acorn": "^8.7.1",
|
||||
"acorn-import-assertions": "^1.9.0",
|
||||
"acorn-import-attributes": "^1.9.5",
|
||||
"browserslist": "^4.21.10",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^5.16.0",
|
||||
"enhanced-resolve": "^5.17.1",
|
||||
"es-module-lexer": "^1.2.1",
|
||||
"eslint-scope": "5.1.1",
|
||||
"events": "^3.2.0",
|
||||
@ -18474,26 +18465,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-bundle-analyzer/node_modules/ws": {
|
||||
"version": "7.5.9",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
|
||||
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
|
||||
"engines": {
|
||||
"node": ">=8.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": "^5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-sources": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
|
||||
@ -18644,6 +18615,22 @@
|
||||
"node": ">= 12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wmf": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz",
|
||||
"integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/word": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz",
|
||||
"integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/wordwrap": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
|
||||
@ -19092,6 +19079,26 @@
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "7.5.10",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
|
||||
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
|
||||
"engines": {
|
||||
"node": ">=8.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": "^5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/x-is-array": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/x-is-array/-/x-is-array-0.1.0.tgz",
|
||||
@ -19114,6 +19121,88 @@
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/xlsx-js-style": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/xlsx-js-style/-/xlsx-js-style-1.2.0.tgz",
|
||||
"integrity": "sha512-DDT4FXFSWfT4DXMSok/m3TvmP1gvO3dn0Eu/c+eXHW5Kzmp7IczNkxg/iEPnImbG9X0Vb8QhROda5eatSR/97Q==",
|
||||
"dependencies": {
|
||||
"adler-32": "~1.2.0",
|
||||
"cfb": "^1.1.4",
|
||||
"codepage": "~1.14.0",
|
||||
"commander": "~2.17.1",
|
||||
"crc-32": "~1.2.0",
|
||||
"exit-on-epipe": "~1.0.1",
|
||||
"fflate": "^0.3.8",
|
||||
"ssf": "~0.11.2",
|
||||
"wmf": "~1.0.1",
|
||||
"word": "~0.3.0"
|
||||
},
|
||||
"bin": {
|
||||
"xlsx": "bin/xlsx.njs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/xlsx-js-style/node_modules/adler-32": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz",
|
||||
"integrity": "sha512-/vUqU/UY4MVeFsg+SsK6c+/05RZXIHZMGJA+PX5JyWI0ZRcBpupnRuPLU/NXXoFwMYCPCoxIfElM2eS+DUXCqQ==",
|
||||
"dependencies": {
|
||||
"exit-on-epipe": "~1.0.1",
|
||||
"printj": "~1.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"adler32": "bin/adler32.njs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/xlsx-js-style/node_modules/codepage": {
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/codepage/-/codepage-1.14.0.tgz",
|
||||
"integrity": "sha512-iz3zJLhlrg37/gYRWgEPkaFTtzmnEv1h+r7NgZum2lFElYQPi0/5bnmuDfODHxfp0INEfnRqyfyeIJDbb7ahRw==",
|
||||
"dependencies": {
|
||||
"commander": "~2.14.1",
|
||||
"exit-on-epipe": "~1.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"codepage": "bin/codepage.njs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/xlsx-js-style/node_modules/codepage/node_modules/commander": {
|
||||
"version": "2.14.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz",
|
||||
"integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw=="
|
||||
},
|
||||
"node_modules/xlsx-js-style/node_modules/commander": {
|
||||
"version": "2.17.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
|
||||
"integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg=="
|
||||
},
|
||||
"node_modules/xlsx-js-style/node_modules/frac": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
|
||||
"integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/xlsx-js-style/node_modules/ssf": {
|
||||
"version": "0.11.2",
|
||||
"resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz",
|
||||
"integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
|
||||
"dependencies": {
|
||||
"frac": "~1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/xlsx-style": {
|
||||
"version": "0.8.13",
|
||||
"resolved": "https://registry.npmjs.org/xlsx-style/-/xlsx-style-0.8.13.tgz",
|
||||
|
10
package.json
10
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "smws",
|
||||
"version": "1.3.0",
|
||||
"version": "1.3.5",
|
||||
"private": true,
|
||||
"description": "SMWS | ССОМ | Специално Свидетелстване София",
|
||||
"repository": "http://git.d-popov.com/popov/next-cart-app.git",
|
||||
@ -34,7 +34,7 @@
|
||||
"@mui/material": "^5.15.10",
|
||||
"@mui/x-date-pickers": "^6.19.4",
|
||||
"@premieroctet/next-crud": "^3.0.0",
|
||||
"@prisma/client": "^5.15.0",
|
||||
"@prisma/client": "^5.19.1",
|
||||
"@react-pdf/renderer": "^3.3.8",
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@types/multer": "^1.4.11",
|
||||
@ -111,13 +111,13 @@
|
||||
"winston-daily-rotate-file": "^5.0.0",
|
||||
"workbox-webpack-plugin": "^7.1.0",
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.19.1/xlsx-0.19.1.tgz",
|
||||
"xlsx-style": "^0.8.13",
|
||||
"xlsx-js-style": "^1.2.0",
|
||||
"xml-js": "^1.6.11",
|
||||
"xml2js": "^0.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "^7.0.3",
|
||||
"depcheck": "^1.4.7",
|
||||
"prisma": "^5.15.0"
|
||||
"prisma": "^5.19.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,6 +77,10 @@ export const authOptions: NextAuthOptions = {
|
||||
{ id: "1", name: "admin", email: "admin@example.com", password: process.env.ADMIN_PASSWORD, role: "ADMIN", static: true }
|
||||
];
|
||||
|
||||
if (process.env.ADMIN_PASSWORD !== credentials.password) {
|
||||
throw new Error('невалидна парола');
|
||||
}
|
||||
|
||||
const user = users.find(user =>
|
||||
user.name === credentials.username && user.password === credentials.password
|
||||
);
|
||||
|
@ -12,6 +12,7 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { all } from "axios";
|
||||
import { logger } from "src/helpers/common";
|
||||
import { excel } from "src/helpers/excel";
|
||||
|
||||
/**
|
||||
*
|
||||
@ -432,7 +433,13 @@ export default async function handler(req, res) {
|
||||
case "getAllPublishersWithStatistics":
|
||||
let noEndDate = common.parseBool(req.query.noEndDate);
|
||||
res.status(200).json(await dataHelper.getAllPublishersWithStatisticsMonth(day, noEndDate));
|
||||
|
||||
case "exportPublishersExcel":
|
||||
try {
|
||||
await excel.ExportPublishersToExcel(req, res);
|
||||
} catch (error) {
|
||||
console.error(JSON.stringify(error));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
res.status(200).json({
|
||||
"message": "no action '" + action + "' found"
|
||||
|
@ -94,6 +94,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
where: {
|
||||
isActive: true,
|
||||
isPublished: true,
|
||||
// OR: [
|
||||
// { isPublished: true },
|
||||
// { user: { role: 'admin' } } // Todo: example. fix this
|
||||
// ],
|
||||
startTime: {
|
||||
gte: fromDate,
|
||||
//lt: toDate,
|
||||
@ -152,15 +156,17 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
//bold the text after - in the notes
|
||||
notes: notes,
|
||||
notes_bold: notes_bold,
|
||||
names: shift.assignments
|
||||
.map((assignment) => {
|
||||
return (
|
||||
assignment.publisher.firstName +
|
||||
" " +
|
||||
assignment.publisher.lastName
|
||||
);
|
||||
})
|
||||
.join(", "),
|
||||
names: shift.assignments.length > 0
|
||||
? shift.assignments
|
||||
.map((assignment) => {
|
||||
return (
|
||||
assignment.publisher.firstName +
|
||||
" " +
|
||||
assignment.publisher.lastName
|
||||
);
|
||||
})
|
||||
.join(", ")
|
||||
: shift.name,
|
||||
};
|
||||
|
||||
if (shiftSchedule.names.length > 0) {
|
||||
@ -246,6 +252,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
);
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error);
|
||||
res.status(500).json({ error: "Internal Server Error" });
|
||||
}
|
||||
} else {
|
||||
|
@ -9,6 +9,7 @@ import Shift from '../../../components/calendar/ShiftComponent';
|
||||
import { DayOfWeek, UserRole } from '@prisma/client';
|
||||
import { env } from 'process'
|
||||
import ShiftComponent from '../../../components/calendar/ShiftComponent';
|
||||
import PublisherShiftsModal from '../../../components/publisher/PublisherShiftsModal';
|
||||
//import { set } from 'date-fns';
|
||||
const common = require('src/helpers/common');
|
||||
import { toast } from 'react-toastify';
|
||||
@ -66,6 +67,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
|
||||
const [shifts, setShifts] = React.useState([]);
|
||||
const [error, setError] = React.useState(null);
|
||||
const [availablePubs, setAvailablePubs] = React.useState([]);
|
||||
const [selectedPublisher, setSelectedPublisher] = React.useState(null);
|
||||
|
||||
const [selectedShiftId, setSelectedShiftId] = useState(null);
|
||||
|
||||
@ -214,8 +216,8 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
|
||||
};
|
||||
|
||||
const handleSelectedPublisher = (publisher) => {
|
||||
// Do something with the selected publisher
|
||||
console.log("handle pub clicked:", publisher);
|
||||
setSelectedPublisher(publisher);
|
||||
}
|
||||
const handlePublisherModalOpen = async (publisher) => {
|
||||
// Do something with the selected publisher
|
||||
@ -355,7 +357,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
|
||||
}
|
||||
return <div>{" "}</div>;
|
||||
};
|
||||
|
||||
//ToDo: DRY - move to common
|
||||
const addAssignment = async (publisher, shiftId) => {
|
||||
try {
|
||||
console.log(`calendar.idx: new assignment for publisher ${publisher.id} - ${publisher.firstName} ${publisher.lastName}`);
|
||||
@ -365,6 +367,10 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
|
||||
isConfirmed: true
|
||||
};
|
||||
const { data } = await axiosInstance.post("/api/data/assignments", newAssignment);
|
||||
if (selectedShiftId == shiftId) {
|
||||
handleShiftSelection(shifts.find(shift => shift.id === shiftId));
|
||||
}
|
||||
|
||||
// Update the 'publisher' property of the returned data with the full publisher object
|
||||
data.publisher = publisher;
|
||||
data.shift = shifts.find(shift => shift.id === shiftId);
|
||||
@ -779,7 +785,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
|
||||
<input type="checkbox" className="toggle-checkbox" id="filterIncludeOldAvailabilities" onChange={handleCheckboxChange} />
|
||||
<span className="toggle-slider m-1">със стари предпочитания</span>
|
||||
</label>
|
||||
<ul className="w-full max-w-md">
|
||||
<ul className="w-full max-w-md" id="availablePubsList" name="availablePubsList">
|
||||
{Array.isArray(availablePubs) && availablePubs?.map((pub, index) => {
|
||||
// Determine background and border classes based on conditions
|
||||
let bgAndBorderColorClass;
|
||||
@ -814,8 +820,8 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
|
||||
<li key={index}
|
||||
className={`flex justify-between items-center p-4 sm:py-2 rounded-lg shadow-sm mb-2
|
||||
${bgAndBorderColorClass} ${selectedBorderClass} ${activeOpacityClass}
|
||||
${pub.currentMonthAssignments >= pub.desiredShiftsPerMonth ? 'text-gray-400' : 'text-gray-800'}`}
|
||||
onDoubleClick={(handlePublisherModalOpen.bind(this, pub))}
|
||||
${pub.currentMonthAssignments === pub.desiredShiftsPerMonth ? 'text-gray-400' : pub.currentMonthAssignments > pub.desiredShiftsPerMonth ? 'text-orange-300' : 'text-gray-800'}`}
|
||||
onDoubleClick={() => handlePublisherModalOpen(pub)}
|
||||
>
|
||||
<span className={`${pub.isAvailableForShift ? 'font-bold' : 'font-medium'} `}>
|
||||
{pub.firstName} {pub.lastName}
|
||||
@ -831,36 +837,10 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
|
||||
<button tooltip="желани участия на месец" title="желани участия" className={`badge py-1 px-2 rounded-md text-xs ${pub.desiredShiftsPerMonth ? 'bg-purple-500 text-white' : 'bg-purple-200 text-gray-400'}`}>{pub.desiredShiftsPerMonth || 0}</button>
|
||||
<button tooltip="push" title="push" className={`badge py-1 px-2 rounded-md text-xs bg-red-100`}
|
||||
onClick={async () => {
|
||||
await fetch('/api/notify', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
id: pub.id,
|
||||
message: "Тестово съобщение",
|
||||
title: "Това е тестово съобщение от https://sofia.mwitnessing.com",
|
||||
actions: [
|
||||
{ action: 'OK', title: 'OK', icon: '✅' },
|
||||
{ action: 'close', title: 'Затвори', icon: '❌' }
|
||||
]
|
||||
// actions: [
|
||||
// {
|
||||
// title: 'Open URL',
|
||||
// action: 'open_url',
|
||||
// icon: '/images/open-url.png'
|
||||
// },
|
||||
// {
|
||||
// title: 'Dismiss',
|
||||
// action: 'dismiss',
|
||||
// icon: '/images/dismiss.png'
|
||||
// }
|
||||
// ]
|
||||
})
|
||||
})
|
||||
handleSelectedPublisher(pub);
|
||||
addAssignment(pub, selectedShiftId);
|
||||
}}
|
||||
>+</button>
|
||||
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
@ -899,151 +879,22 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
|
||||
<div>
|
||||
{/* <CustomCalendar date={value} shifts={shifts} /> */}
|
||||
</div>
|
||||
{isModalOpen && <PublisherShiftsModal publisher={modalPub} shifts={allShifts} onClose={() => setIsModalOpen(false)} />}
|
||||
{isModalOpen && (
|
||||
<PublisherShiftsModal
|
||||
publisher={modalPub}
|
||||
_shifts={allShifts}
|
||||
onClose={() => setIsModalOpen(false)}
|
||||
date={value}
|
||||
onAssignmentChange={handleAssignmentChange}
|
||||
/>
|
||||
)}
|
||||
</ProtectedRoute >
|
||||
</Layout >
|
||||
</>
|
||||
);
|
||||
|
||||
function PublisherShiftsModal({ publisher, shifts, onClose }) {
|
||||
const monthInfo = common.getMonthDatesInfo(new Date(value));
|
||||
const monthShifts = shifts.filter(shift => {
|
||||
const shiftDate = new Date(shift.startTime);
|
||||
return shiftDate > monthInfo.firstDay && shiftDate < monthInfo.lastDay;
|
||||
});
|
||||
const weekShifts = monthShifts.filter(shift => {
|
||||
const shiftDate = new Date(shift.startTime);
|
||||
return common.getStartOfWeek(value) <= shiftDate && shiftDate <= common.getEndOfWeek(value);
|
||||
});
|
||||
const dayShifts = weekShifts.map(shift => {
|
||||
const isAvailable = publisher.availabilities?.some(avail =>
|
||||
avail.startTime <= shift.startTime && avail.endTime >= shift.endTime
|
||||
);
|
||||
let color = isAvailable ? getColorForShift(shift) : 'bg-gray-300';
|
||||
if (shift.isFromPreviousMonth) {
|
||||
color += ' border-l-4 border-orange-500 ';
|
||||
}
|
||||
if (shift.isFromPreviousAssignment) {
|
||||
color += ' border-l-4 border-red-500 ';
|
||||
}
|
||||
return { ...shift, isAvailable, color };
|
||||
}).reduce((acc, shift) => {
|
||||
const dayIndex = new Date(shift.startTime).getDay();
|
||||
acc[dayIndex] = acc[dayIndex] || [];
|
||||
acc[dayIndex].push(shift);
|
||||
return acc;
|
||||
}, {});
|
||||
console.log("dayShifts:", dayShifts);
|
||||
|
||||
const hasAssignment = (shiftId) => {
|
||||
// return publisher.assignments.some(ass => ass.shift.id == shiftId);
|
||||
return publisher.assignments?.some(ass => {
|
||||
//console.log(`Comparing: ${ass.shift.id} to ${shiftId}: ${ass.shift.id === shiftId}`);
|
||||
return ass.shift.id === shiftId;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (event) => {
|
||||
if (event.key === 'Escape') {
|
||||
console.log('ESC: closing modal.');
|
||||
onClose(); // Call the onClose function when ESC key is pressed
|
||||
}
|
||||
};
|
||||
|
||||
// Add event listener
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
|
||||
// Remove event listener on cleanup
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
}, [onClose]); // Include onClose in the dependency array
|
||||
|
||||
return (
|
||||
<div className="fixed top-0 left-0 w-full h-full flex items-center justify-center bg-black bg-opacity-50 z-50">
|
||||
<div className="relative bg-white p-8 rounded-lg shadow-xl max-w-xl w-full h-auto overflow-y-auto">
|
||||
<h2 className="text-xl font-semibold mb-4">График на <span title={publisher.email} className='publisher'>
|
||||
<strong>{publisher.firstName} {publisher.lastName}</strong>
|
||||
<span className="publisher-tooltip" onClick={common.copyToClipboard}>{publisher.email}</span>
|
||||
</span> тази седмица:</h2>
|
||||
|
||||
{/* ... Display shifts in a calendar-like UI ... */}
|
||||
<div className="grid grid-cols-6 gap-4 mb-4">
|
||||
{Object.entries(dayShifts).map(([dayIndex, shiftsForDay]) => (
|
||||
<div key={dayIndex} className="flex flex-col space-y-2 justify-end">
|
||||
{/* Day header */}
|
||||
<div className="text-center font-medium">{new Date(shiftsForDay[0].startTime).getDate()}-ти</div>
|
||||
|
||||
{shiftsForDay.map((shift, index) => {
|
||||
const assignmentExists = hasAssignment(shift.id);
|
||||
const availability = publisher.availabilities.find(avail =>
|
||||
avail.startTime <= shift.startTime && avail.endTime >= shift.endTime
|
||||
);
|
||||
const isFromPrevMonth = availability && availability.isFromPreviousMonth;
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className={`text-sm text-white p-2 rounded-md ${isFromPrevMonth ? 'border-l-6 border-black-500' : ''} ${shift.color} ${assignmentExists ? 'border-2 border-blue-500' : ""} h-24 flex flex-col justify-center`}
|
||||
>
|
||||
{common.getTimeRange(shift.startTime, shift.endTime)} {shift.id}
|
||||
|
||||
{!assignmentExists && shift.isAvailable && (
|
||||
<button onClick={() => { addAssignment(publisher, shift.id); }}
|
||||
className="mt-2 bg-green-500 text-white p-1 rounded hover:bg-green-600 active:bg-green-700 focus:outline-none"
|
||||
>
|
||||
добави
|
||||
</button>
|
||||
)}
|
||||
{assignmentExists && (
|
||||
<button onClick={() => { removeAssignment(publisher, shift.id) }} // Implement the removeAssignment function
|
||||
className="mt-2 bg-red-500 text-white p-1 rounded hover:bg-red-600 active:bg-red-700 focus:outline-none"
|
||||
>
|
||||
махни
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Close button in the top right corner */}
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="absolute top-3 right-2 p-2 px-3 bg-red-500 text-white rounded-full hover:bg-red-600 active:bg-red-700 focus:outline-none"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
|
||||
{/* <Link href={`/cart/publishers/edit/${modalPub.id}`}
|
||||
className="mt-2 bg-blue-500 text-white p-1 rounded hover:bg-blue-600 active:bg-blue-700 focus:outline-none">
|
||||
<i className="fas fa-edit" />
|
||||
</Link> */}
|
||||
{/* Edit button in the top right corner, next to the close button */}
|
||||
<Link href={`/cart/publishers/edit/${modalPub.id}`} className="absolute top-3 right-12 p-2 bg-blue-500 text-white rounded-full hover:bg-blue-600 active:bg-blue-700 focus:outline-none">
|
||||
<i className="fas fa-edit" />
|
||||
</Link>
|
||||
|
||||
</div>
|
||||
</div >
|
||||
);
|
||||
}
|
||||
|
||||
function getColorForShift(shift) {
|
||||
const assignedCount = shift.assignedCount || 0; // Assuming each shift has an assignedCount property
|
||||
switch (assignedCount) {
|
||||
case 0: return 'bg-blue-300';
|
||||
case 1: return 'bg-green-300';
|
||||
case 2: return 'bg-yellow-300';
|
||||
case 3: return 'bg-orange-300';
|
||||
case 4: return 'bg-red-200';
|
||||
default: return 'bg-gray-300';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
import axiosServer from '../../../src/axiosServer';
|
||||
|
@ -15,8 +15,7 @@ import { levenshteinEditDistance } from "levenshtein-edit-distance";
|
||||
import ProtectedRoute from '../../../components/protectedRoute';
|
||||
import ConfirmationModal from '../../../components/ConfirmationModal';
|
||||
import { relative } from "path";
|
||||
|
||||
|
||||
import { set } from "lodash";
|
||||
|
||||
interface IProps {
|
||||
initialItems: Publisher[];
|
||||
@ -24,14 +23,31 @@ interface IProps {
|
||||
|
||||
function PublishersPage({ publishers = [] }: IProps) {
|
||||
const [shownPubs, setShownPubs] = useState(publishers);
|
||||
|
||||
const [filter, setFilter] = useState("");
|
||||
const [showZeroShiftsOnly, setShowZeroShiftsOnly] = useState(false);
|
||||
const [filterIsImported, setFilterIsImported] = useState({
|
||||
checked: false,
|
||||
indeterminate: true,
|
||||
});
|
||||
const [showZeroShiftsOnly, setShowZeroShiftsOnly] = useState(false);
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
|
||||
// const cbRefFilterTraining = useRef<HTMLInputElement>(null);
|
||||
|
||||
// const getCheckboxState = (currentState: boolean | null) => {
|
||||
// if (currentState === true) return 'unchecked';
|
||||
// if (currentState === false) return 'checked';
|
||||
// return 'indeterminate';
|
||||
// };
|
||||
// const cbRefFilterTraining = useRef<HTMLInputElement>(null);
|
||||
// const [cbFilterTrainingState, setcbFilterTrainingState] = useState<boolean | null>(null);
|
||||
// useEffect(() => {
|
||||
// if (cbRefFilterTraining.current) {
|
||||
// cbRefFilterTraining.current.indeterminate = cbFilterTrainingState === null;
|
||||
// }
|
||||
// }, [cbFilterTrainingState]);
|
||||
const [flterNoTraining, setFilterNoTraining] = useState(false);
|
||||
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
const [isModalOpenDeleteAllVisible, setIsModalOpenDeleteAllVisible] = useState(false);
|
||||
const [isModalOpenDeleteAllAvaillabilities, setIsModalOpenDeleteAllAvaillabilities] = useState(false);
|
||||
|
||||
@ -102,10 +118,15 @@ function PublishersPage({ publishers = [] }: IProps) {
|
||||
? filteredPublishers.filter(p => p.assignments.length === 0)
|
||||
: filteredPublishers;
|
||||
|
||||
setShownPubs(filteredPublishers);
|
||||
}, [filter, showZeroShiftsOnly]);
|
||||
// trained filter
|
||||
if (flterNoTraining) {
|
||||
filteredPublishers = filteredPublishers.filter(p => p.isTrained === false);
|
||||
}
|
||||
|
||||
setShownPubs(filteredPublishers);
|
||||
}, [filter, showZeroShiftsOnly, flterNoTraining]);
|
||||
|
||||
|
||||
const checkboxRef = useRef();
|
||||
|
||||
const renderPublishers = () => {
|
||||
if (shownPubs.length === 0) {
|
||||
@ -138,31 +159,33 @@ function PublishersPage({ publishers = [] }: IProps) {
|
||||
if (type === 'text') {
|
||||
setFilter(value);
|
||||
} else if (type === 'checkbox') {
|
||||
// setFilterIsImported({ ...checkboxFilter, [name]: checked });
|
||||
const { checked, indeterminate } = checkboxRef.current;
|
||||
if (!checked && !indeterminate) {
|
||||
// Checkbox was unchecked, set it to indeterminate state
|
||||
checkboxRef.current.indeterminate = true;
|
||||
setFilterIsImported({ checked: false, indeterminate: true });
|
||||
} else if (!checked && indeterminate) {
|
||||
// Checkbox was indeterminate, set it to checked state
|
||||
checkboxRef.current.checked = true;
|
||||
checkboxRef.current.indeterminate = false;
|
||||
setFilterIsImported({ checked: true, indeterminate: false });
|
||||
} else if (checked && !indeterminate) {
|
||||
// Checkbox was checked, set it to unchecked state
|
||||
checkboxRef.current.checked = false;
|
||||
checkboxRef.current.indeterminate = false;
|
||||
setFilterIsImported({ checked: false, indeterminate: false });
|
||||
} else {
|
||||
// Checkbox was checked and indeterminate (should not happen), set it to unchecked state
|
||||
checkboxRef.current.checked = false;
|
||||
checkboxRef.current.indeterminate = false;
|
||||
setFilterIsImported({ checked: false, indeterminate: false });
|
||||
if (name === 'filterIsImported') {
|
||||
setFilterIsImported({ checked, indeterminate: false });
|
||||
}
|
||||
if (name === 'filterTrained') {
|
||||
// const nextState = cbFilterTrainingState === false ? null : cbFilterTrainingState === null ? true : false;
|
||||
// setcbFilterTrainingState(nextState);
|
||||
setFilterNoTraining(checked);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const exportPublishers = async () => {
|
||||
try {
|
||||
const response = await axiosInstance.get('/api/?action=exportPublishersExcel');
|
||||
const blob = new Blob([response.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = 'publishers.xlsx';
|
||||
a.click();
|
||||
} catch (error) {
|
||||
console.error(JSON.stringify(error)); // Log the error
|
||||
toast.error("Грешка при експорт на данни");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<ProtectedRoute allowedRoles={[UserRole.ADMIN, UserRole.POWERUSER]}>
|
||||
@ -195,8 +218,13 @@ function PublishersPage({ publishers = [] }: IProps) {
|
||||
<div className="flex justify-center m-4">
|
||||
<a href="/cart/publishers/import" className="btn">Import publishers</a>
|
||||
</div>
|
||||
{/* export by calling excel helper .ExportPublishersToExcel() */}
|
||||
<div className="flex justify-center m-4">
|
||||
<button className="btn" onClick={exportPublishers}>Export to Excel</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="z-60 sticky top-0" style={{ zIndex: 60, position: relative }}>
|
||||
<div name="filters" className="flex items-center justify-center space-x-4 m-4 bg-gray-100 p-2" >
|
||||
<label htmlFor="filter">Filter:</label>
|
||||
@ -212,7 +240,17 @@ function PublishersPage({ publishers = [] }: IProps) {
|
||||
<span className="ml-2">само без смени</span>
|
||||
</label>
|
||||
|
||||
<span id="filter-info" className="ml-4">{publishers.length} от {publishers.length} вестителя</span>
|
||||
<label htmlFor="filterTrained" className="ml-4 inline-flex items-center">
|
||||
<input type="checkbox" id="filterTrained" name="filterTrained"
|
||||
// support intermediate state if checkboxState is null
|
||||
checked={flterNoTraining}
|
||||
onChange={handleFilterChange}
|
||||
className="form-checkbox text-indigo-600"
|
||||
/>
|
||||
<span className="ml-2">без обучение</span>
|
||||
</label>
|
||||
|
||||
<span id="filter-info" className="ml-4">{shownPubs.length} от {publishers.length} вестителя</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid gap-4 grid-cols-1 md:grid-cols-4 z-0">
|
||||
@ -226,12 +264,12 @@ function PublishersPage({ publishers = [] }: IProps) {
|
||||
|
||||
export default PublishersPage;
|
||||
|
||||
//import { set } from "date-fns";
|
||||
//import {set} from "date-fns";
|
||||
|
||||
export const getServerSideProps = async (context) => {
|
||||
// const axios = await axiosServer(context);
|
||||
// //ToDo: refactor all axios calls to use axiosInstance and this URL
|
||||
// const { data: publishers } = await axios.get('/api/data/publishers?select=id,firstName,lastName,email,isActive,isTrained,isImported,assignments.shift.startTime,availabilities.startTime&dev=fromuseefect');
|
||||
// const {data: publishers } = await axios.get('/api/data/publishers?select=id,firstName,lastName,email,isActive,isTrained,isImported,assignments.shift.startTime,availabilities.startTime&dev=fromuseefect');
|
||||
//use prisma instead of axios
|
||||
const prisma = common.getPrismaClient();
|
||||
let publishers = await prisma.publisher.findMany({
|
||||
|
@ -9,7 +9,7 @@ import ProtectedRoute from '../../../components/protectedRoute';
|
||||
function NewPage(loc: Location) {
|
||||
return (
|
||||
<Layout>
|
||||
<ProtectedRoute allowedRoles={[UserRole.POWERUSER, UserRole.ADMIN]}>
|
||||
<ProtectedRoute allowedRoles={[UserRole.USER, UserRole.POWERUSER, UserRole.ADMIN]}>
|
||||
<div className="h-5/6 grid place-items-center">
|
||||
<ExperienceForm />
|
||||
</div></ProtectedRoute>
|
||||
|
@ -105,7 +105,12 @@ export default PDFViewerPage;
|
||||
|
||||
|
||||
export const getServerSideProps = async (context) => {
|
||||
const permitsFolder = '/public/content/permits/';
|
||||
const permitsFolder = path.join('public', 'content', 'permits');
|
||||
|
||||
// Create folders if they do not exist
|
||||
if (!fs.existsSync(permitsFolder)) {
|
||||
fs.mkdirSync(permitsFolder, { recursive: true });
|
||||
}
|
||||
//get all the files in the permits folder order them by date desc and display them
|
||||
const pdfFiles = fs.readdirSync(path.join(process.cwd(), permitsFolder)).map(file => {
|
||||
return {
|
||||
|
5
prisma/migrations/20240621124135_/migration.sql
Normal file
5
prisma/migrations/20240621124135_/migration.sql
Normal file
@ -0,0 +1,5 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE `Message` MODIFY `content` TEXT NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `Survey` MODIFY `content` TEXT NOT NULL;
|
@ -0,0 +1,6 @@
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `Message` DROP FOREIGN KEY `Message_publisherId_fkey`;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `Message`
|
||||
ADD CONSTRAINT `Message_publisherId_fkey` FOREIGN KEY (`publisherId`) REFERENCES `Publisher` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
@ -266,7 +266,7 @@ enum MessageType {
|
||||
|
||||
model Survey {
|
||||
id Int @id @default(autoincrement())
|
||||
content String
|
||||
content String @db.Text
|
||||
answers Json?
|
||||
messages Message[]
|
||||
publicFrom DateTime?
|
||||
@ -275,10 +275,10 @@ model Survey {
|
||||
|
||||
model Message {
|
||||
id Int @id @default(autoincrement())
|
||||
publisher Publisher @relation(fields: [publisherId], references: [id])
|
||||
publisher Publisher @relation(fields: [publisherId], references: [id], onDelete: Cascade)
|
||||
publisherId String
|
||||
date DateTime
|
||||
content String
|
||||
content String @db.Text
|
||||
isRead Boolean @default(false)
|
||||
isPublic Boolean @default(false)
|
||||
type MessageType @default(Email)
|
||||
@ -305,7 +305,7 @@ model EventLog {
|
||||
id Int @id @default(autoincrement())
|
||||
date DateTime
|
||||
publisherId String?
|
||||
publisher Publisher? @relation(fields: [publisherId], references: [id])
|
||||
publisher Publisher? @relation(fields: [publisherId], references: [id], onDelete: SetNull)
|
||||
shiftId Int?
|
||||
shift Shift? @relation(fields: [shiftId], references: [id])
|
||||
content String @db.VarChar(5000)
|
||||
|
Binary file not shown.
@ -574,7 +574,7 @@ nextApp
|
||||
|
||||
// --------------- EXCEL EXPORT ROUTE ----------------
|
||||
server.get("/generatexcel/:year/:month/:process", async (req, res) => {
|
||||
await excel.GenerateExcel(req, res);
|
||||
await excel.ScheduleGenerateExcel(req, res);
|
||||
});
|
||||
|
||||
|
||||
|
@ -14,8 +14,12 @@ const data = require("./data");
|
||||
|
||||
// for nodejs
|
||||
//const api = require("./pages/api/index");
|
||||
// import dynamic from 'next/dynamic';
|
||||
|
||||
exports.GenerateExcel = async function (req, res) {
|
||||
// const XLSX = dynamic(() => import('xlsx-style'), { ssr: false });
|
||||
|
||||
|
||||
exports.ScheduleGenerateExcel = async function (req, res) {
|
||||
|
||||
const prisma = common.getPrismaClient();
|
||||
const year = req.params.year;
|
||||
@ -162,7 +166,7 @@ exports.GenerateExcel = async function (req, res) {
|
||||
const ws = XLSX.utils.aoa_to_sheet(ws_data);
|
||||
wb.Sheets["График КОЛИЧКИ"] = ws;
|
||||
|
||||
const xlsxstyle = require("xlsx-style");
|
||||
const xlsxstyle = require("xlsx-js-style");
|
||||
try {
|
||||
const workbook = xlsxstyle.readFile(filePath);
|
||||
const sheetNames = workbook.SheetNames;
|
||||
@ -611,6 +615,55 @@ exports.ReadDocxFileForMonth = async function (filePath, buffer, month, year, pr
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
exports.ExportPublishersToExcel = async function (req, res) {
|
||||
const prisma = common.getPrismaClient();
|
||||
const publishers = await prisma.publisher.findMany({
|
||||
// where: { isActive: true, },
|
||||
include: {
|
||||
// availabilities: { where: { isActive: true, }, },
|
||||
// assignments: { include: { shift: true, }, },
|
||||
congregation: true,
|
||||
|
||||
},
|
||||
});
|
||||
const ExcelJS = require("exceljs");
|
||||
const xjswb = new ExcelJS.Workbook();
|
||||
const sheet = xjswb.addWorksheet("Publishers");
|
||||
sheet.columns = [
|
||||
{ header: "Name", key: "name", width: 32 },
|
||||
{ header: "Trained", key: "trained", width: 10 },
|
||||
{ header: "Email", key: "email", width: 32 },
|
||||
{ header: "Phone", key: "phone", width: 32 },
|
||||
{ header: "Role", key: "role", width: 32 },
|
||||
{ header: "Congregation", key: "congregationName", width: 32 },
|
||||
{ header: "Last Login", key: "lastLogin", width: 32 },
|
||||
{ header: "Type", key: "PublisherTypeText", width: 32 },
|
||||
{ header: "Active", key: "isActive", width: 10 },
|
||||
{ header: "Created At", key: "createdAt", width: 32 },
|
||||
{ header: "Updated At", key: "updatedAt", width: 32 },
|
||||
];
|
||||
publishers.forEach((publisher) => {
|
||||
sheet.addRow({
|
||||
name: publisher.firstName + " " + publisher.lastName,
|
||||
trained: publisher.isTrained,
|
||||
email: publisher.email,
|
||||
phone: publisher.phone,
|
||||
role: publisher.role,
|
||||
congregationName: publisher.congregation.name,
|
||||
lastLogin: publisher.lastLogin,
|
||||
PublisherTypeText: publisher.PublisherTypeText,
|
||||
isActive: publisher.isActive,
|
||||
createdAt: publisher.createdAt,
|
||||
updatedAt: publisher.updatedAt,
|
||||
|
||||
});
|
||||
});
|
||||
res.setHeader("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
res.setHeader("Content-Disposition", "attachment; filename=" + encodeURI("Publishers.xlsx"));
|
||||
xjswb.xlsx.write(res);
|
||||
}
|
||||
|
||||
const weekNames = [
|
||||
"Понеделник",
|
||||
"Вторник",
|
||||
|
Reference in New Issue
Block a user