Merge commit '5901c11761634ad71e53f9bc01a1b3262c3767b2' into production
This commit is contained in:
10
.env
10
.env
@ -1,11 +1,7 @@
|
||||
|
||||
#NODE_TLS_REJECT_UNAUTHORIZED='0'
|
||||
SSL_ENABLED=false
|
||||
NEXT_PUBLIC_PROTOCOL=https
|
||||
NEXT_PUBLIC_HOST=localhost
|
||||
NEXT_PUBLIC_PORT=3003
|
||||
NEXTAUTH_URL=https://localhost:3003
|
||||
# NEXTAUTH_URL_INTERNAL=http://127.0.0.1:3003
|
||||
# HOST=localhost
|
||||
# PORT=3003
|
||||
# NEXT_PUBLIC_PUBLIC_URL=http://localhost:3003
|
||||
|
||||
# Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32
|
||||
NEXTAUTH_SECRET=ed8a9681efc414df89dfd03cd188ed58
|
||||
|
@ -1,9 +0,0 @@
|
||||
NEXT_PUBLIC_PROTOCOL=https
|
||||
NEXT_PUBLIC_PORT=
|
||||
NEXT_PUBLIC_HOST=staging.mwhitnessing.com
|
||||
NEXTAUTH_URL= https://staging.mwhitnessing.com
|
||||
|
||||
# Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32
|
||||
NEXTAUTH_SECRET=1dd8a5457970d1dda50600be28e935ecc4513ff27c49c431849e6746f158d638
|
||||
# ? do we need to duplicate this? already defined in the deoployment yml file
|
||||
DATABASE_URL=mysql://jwpwsofia_demo:dwxhns9p9vp248@mariadb:3306/jwpwsofia_demo
|
@ -1,15 +1,12 @@
|
||||
NODE_TLS_REJECT_UNAUTHORIZED=0
|
||||
# NODE_EXTRA_CA_CERTS=C:\\Users\\popov\\AppData\\Local\\mkcert
|
||||
PROTOCOL=https
|
||||
PORT=3003
|
||||
HOST=localhost
|
||||
NEXT_PUBLIC_PUBLIC_URL=https://localhost:3003
|
||||
|
||||
NEXT_PUBLIC_PROTOCOL=https
|
||||
NEXT_PUBLIC_HOST=localhost
|
||||
NEXT_PUBLIC_PORT=3003
|
||||
NEXTAUTH_URL=https://localhost:3003
|
||||
|
||||
SSL_ENABLED=true
|
||||
TELEGRAM_BOT=true
|
||||
SSL_KEY=./certificates/localhost-key.pem
|
||||
SSL_CERT=./certificates/localhost.pem
|
||||
|
||||
DATABASE_URL=mysql://root:Zelen0ku4e@192.168.0.10:3306/cart_dev
|
||||
# DATABASE_URL=mysql://cart:cartpw@localhost:3306/cart
|
||||
# DATABASE_URL=mysql://cart:cartpw@localhost:3306/cart
|
37
.env.homelab
37
.env.homelab
@ -1,37 +0,0 @@
|
||||
NODE_TLS_REJECT_UNAUTHORIZED='0'
|
||||
# DATABASE_URL="file:./src/data/dev.db"
|
||||
# DATABASE_URL="mysql://root:Zelen0ku4e@192.168.0.10:3306/cart"
|
||||
|
||||
NEXT_PUBLIC_PORT=
|
||||
# NEXT_PUBLIC_NEXTAUTH_URL=https://cart.d-popov.com
|
||||
NEXT_PUBLIC_PROTOCOL=https
|
||||
NEXT_PUBLIC_HOST=cart.d-popov.com
|
||||
NEXTAUTH_URL=https://cart.d-popov.com
|
||||
# NEXTAUTH_URL= https://demo.mwhitnessing.com
|
||||
|
||||
# Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32
|
||||
NEXTAUTH_SECRET=ed8a9681efc414df89dfd03cd188ed58
|
||||
DATABASE_URL=mysql://cart:cart2023@192.168.0.10:3306/cart_demo
|
||||
|
||||
APPLE_ID=
|
||||
APPLE_TEAM_ID=
|
||||
APPLE_PRIVATE_KEY=
|
||||
APPLE_KEY_ID=
|
||||
|
||||
AUTH0_ID=Aa9f3HJowauUrmBVY4iQzQJ7fYsaZDbK
|
||||
AUTH0_SECRET=_c0O9GkyRXkoWMQW7jNExnl6UoXN6O4oD3mg7NZ_uHVeAinCUtcTAkeQmcKXpZ4x
|
||||
AUTH0_ISSUER=https://dev-wkzi658ckibr1amv.us.auth0.com
|
||||
|
||||
FACEBOOK_ID=
|
||||
FACEBOOK_SECRET=
|
||||
|
||||
GITHUB_ID=
|
||||
GITHUB_SECRET=
|
||||
# GOOGLE_ID=926212607479-d3m8hm8f8esp3rf1639prskn445sa01v.apps.googleusercontent.com
|
||||
# GOOGLE_SECRET=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
|
||||
|
||||
TWITTER_ID=
|
||||
TWITTER_SECRET=
|
||||
|
||||
EMAIL_SERVER=smtp://8ec69527ff2104:c7bc05f171c96c@smtp.mailtrap.io:2525
|
||||
EMAIL_FROM=noreply@example.com
|
@ -1,7 +1,7 @@
|
||||
NEXT_PUBLIC_PROTOCOL=https
|
||||
NEXT_PUBLIC_PORT=
|
||||
NEXT_PUBLIC_HOST=sofia.mwhitnessing.com
|
||||
NEXTAUTH_URL= https://sofia.mwhitnessing.com
|
||||
PORT=
|
||||
HOST=sofia.mwhitnessing.com
|
||||
PROTOCOL=http # we're behind a reverse proxy. SSL is handled by the proxy
|
||||
NEXT_PUBLIC_PUBLIC_URL= https://sofia.mwhitnessing.com
|
||||
|
||||
# Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32
|
||||
NEXTAUTH_SECRET=1dd8a5457970d1dda50600be28e935ecc4513ff27c49c431849e6746f158d638
|
||||
|
22
.env.test
22
.env.test
@ -1,13 +1,12 @@
|
||||
NODE_TLS_REJECT_UNAUTHORIZED='0'
|
||||
|
||||
NEXT_PUBLIC_PORT=5001
|
||||
NEXT_PUBLIC_PROTOCOL=https
|
||||
NEXT_PUBLIC_HOST=cart.d-popov.com
|
||||
NEXTAUTH_URL=https://cart.d-popov.com
|
||||
PROTOCOL=http
|
||||
HOST=staging.mwhitnessing.com
|
||||
PORT=
|
||||
NEXT_PUBLIC_PUBLIC_URL=https://staging.mwhitnessing.com
|
||||
|
||||
# Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32
|
||||
NEXTAUTH_SECRET=ed8a9681efc414df89dfd03cd188ed58
|
||||
DATABASE_URL=mysql://cart:cartpw@192.168.0.10:3306/cart_dev
|
||||
NEXTAUTH_SECRET=1dd8a5457970d1dda50600be28e935ecc4513ff27c49c431849e6746f158d638
|
||||
# ? do we need to duplicate this? already defined in the deoployment yml file
|
||||
DATABASE_URL=mysql://jwpwsofia_demo:dwxhns9p9vp248@mariadb:3306/jwpwsofia_demo
|
||||
|
||||
APPLE_ID=
|
||||
APPLE_TEAM_ID=
|
||||
@ -23,14 +22,11 @@ FACEBOOK_SECRET=
|
||||
|
||||
GITHUB_ID=
|
||||
GITHUB_SECRET=
|
||||
GOOGLE_ID=926212607479-d3m8hm8f8esp3rf1639prskn445sa01v.apps.googleusercontent.com
|
||||
GOOGLE_SECRET=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
|
||||
# GOOGLE_ID=926212607479-d3m8hm8f8esp3rf1639prskn445sa01v.apps.googleusercontent.com
|
||||
# GOOGLE_SECRET=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
|
||||
|
||||
TWITTER_ID=
|
||||
TWITTER_SECRET=
|
||||
|
||||
EMAIL_SERVER=smtp://8ec69527ff2104:c7bc05f171c96c@smtp.mailtrap.io:2525
|
||||
EMAIL_FROM=noreply@example.com
|
||||
|
||||
GMAIL_EMAIL_USERNAME=
|
||||
GMAIL_EMAIL_APP_PASS=
|
||||
|
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@ -6,7 +6,7 @@
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Run npm nodemon (DEV)",
|
||||
"command": "npm run debug-env",
|
||||
"command": "npm run debug",
|
||||
"request": "launch",
|
||||
"type": "node-terminal",
|
||||
"preLaunchTask": "killInspector",
|
||||
@ -35,7 +35,7 @@
|
||||
"request": "launch",
|
||||
"type": "node-terminal",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"command": "conda activate node && npm run debug-env",
|
||||
"command": "conda activate node && npm run debug",
|
||||
},
|
||||
{
|
||||
"name": "Run conda npm TEST",
|
||||
|
69
_deploy/setupAppleId.mjs
Normal file
69
_deploy/setupAppleId.mjs
Normal file
@ -0,0 +1,69 @@
|
||||
#!/bin/node
|
||||
|
||||
import { SignJWT } from "jose"
|
||||
import { createPrivateKey } from "crypto"
|
||||
|
||||
if (process.argv.includes("--help") || process.argv.includes("-h")) {
|
||||
console.log(`
|
||||
Creates a JWT from the components found at Apple.
|
||||
By default, the JWT has a 6 months expiry date.
|
||||
Read more: https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens#3262048
|
||||
|
||||
Usage:
|
||||
node apple.mjs [--kid] [--iss] [--private_key] [--sub] [--expires_in] [--exp]
|
||||
|
||||
node setupAppleId.mjs --kid YOUR_KEY_ID --iss YOUR_TEAM_ID --private_key "$(cat key.p8)" --sub YOUR_CLIENT_ID --expires_in 15778800
|
||||
|
||||
|
||||
Options:
|
||||
--help Print this help message
|
||||
--kid, --key_id The key id of the private key
|
||||
--iss, --team_id The Apple team ID
|
||||
--private_key The private key to use to sign the JWT. (Starts with -----BEGIN PRIVATE KEY-----)
|
||||
--sub, --client_id The client id to use in the JWT.
|
||||
--expires_in Number of seconds from now when the JWT should expire. Defaults to 6 months.
|
||||
--exp Future date in seconds when the JWT expires
|
||||
`)
|
||||
} else {
|
||||
const args = process.argv.slice(2).reduce((acc, arg, i) => {
|
||||
if (arg.match(/^--\w/)) {
|
||||
const key = arg.replace(/^--/, "").toLowerCase()
|
||||
acc[key] = process.argv[i + 3]
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
const {
|
||||
team_id,
|
||||
iss = team_id,
|
||||
|
||||
private_key,
|
||||
|
||||
client_id,
|
||||
sub = client_id,
|
||||
|
||||
key_id,
|
||||
kid = key_id,
|
||||
|
||||
expires_in = 86400 * 180,
|
||||
exp = Math.ceil(Date.now() / 1000) + expires_in,
|
||||
} = args
|
||||
|
||||
/**
|
||||
* How long is the secret valid in seconds.
|
||||
* @default 15780000
|
||||
*/
|
||||
const expiresAt = Math.ceil(Date.now() / 1000) + expires_in
|
||||
const expirationTime = exp ?? expiresAt
|
||||
console.log(`
|
||||
Apple client secret generated. Valid until: ${new Date(expirationTime * 1000)}
|
||||
|
||||
${await new SignJWT({})
|
||||
.setAudience("https://appleid.apple.com")
|
||||
.setIssuer(iss)
|
||||
.setIssuedAt()
|
||||
.setExpirationTime(expirationTime)
|
||||
.setSubject(sub)
|
||||
.setProtectedHeader({ alg: "ES256", kid })
|
||||
.sign(createPrivateKey(private_key.replace(/\\n/g, "\n")))}`)
|
||||
}
|
@ -187,3 +187,12 @@ fix availability repeat checks
|
||||
sometimes delete from mycalendar fails
|
||||
saturday shifts start at 12:00 / dymamic
|
||||
|
||||
-------------------------------
|
||||
Add availability type UNAVAILABLE/ AWAY (like Estelle, Rick, Me)
|
||||
|
||||
why "Александра Чернъшова" seems available every shift thursdays?
|
||||
fix Time ZONE (currently Z, but it leads to shift when the DST changes ( winter entries are shifter in summer))
|
||||
защо Марсел Клайнер е червен четв 11 април? - има предпочитания и е в номата
|
||||
fix repeating availabilities - Tanq kolcjanova only blue first thursday
|
||||
add assignment in calendar planner
|
||||
fix database
|
||||
|
@ -1,5 +1,5 @@
|
||||
import axiosInstance from '../../src/axiosSecure';
|
||||
import { useEffect, useState, useCallback } from "react";
|
||||
import { useEffect, useState, useCallback, use } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { useRouter } from "next/router";
|
||||
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
|
||||
@ -26,9 +26,6 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o
|
||||
const [editMode, setEditMode] = useState(existingItems.length > 0);
|
||||
const [publisher, setPublisher] = useState({ id: publisherId });
|
||||
const [day, setDay] = useState(new Date(date));
|
||||
const [doRepeat, setDoRepeat] = useState(false);
|
||||
const [repeatFrequency, setRepeatFrequency] = useState(1);
|
||||
const [repeatUntil, setRepeatUntil] = useState(null);
|
||||
const [canUpdate, setCanUpdate] = useState(true);
|
||||
|
||||
const [timeSlots, setTimeSlots] = useState([]);
|
||||
@ -46,6 +43,10 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o
|
||||
isLast: false,
|
||||
}]);
|
||||
|
||||
const [doRepeat, setDoRepeat] = useState(existingItems && existingItems.length > 0 ? existingItems[0].repeatWeekly : false);
|
||||
const [repeatFrequency, setRepeatFrequency] = useState(1);
|
||||
const [repeatUntil, setRepeatUntil] = useState(null);
|
||||
|
||||
const [isInline, setInline] = useState(inline || false);
|
||||
const [config, setConfig] = useState(null);
|
||||
useEffect(() => {
|
||||
@ -69,6 +70,7 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o
|
||||
const response = await axiosInstance.get(`/api/data/availabilities/${id}`);
|
||||
setAvailabilities([response.data]);
|
||||
setEditMode(true);
|
||||
setDoRepeat(response.data.repeatWeekly);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
toast.error("Error fetching availability data.");
|
||||
@ -202,10 +204,24 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o
|
||||
availability.isWithTransportIn = group[0].isFirst && timeSlots[0].isWithTransport;
|
||||
availability.isWithTransportOut = group[group.length - 1].isLast && timeSlots[timeSlots.length - 1].isWithTransport;
|
||||
|
||||
availability.repeatWeekly = doRepeat;
|
||||
availability.dayOfMonth = doRepeat ? null : availability.startTime.getDate();
|
||||
availability.endDate = doRepeat ? repeatUntil : null;
|
||||
delete availability.weekOfMonth;
|
||||
if (doRepeat) {
|
||||
availability.repeatWeekly = true;
|
||||
availability.dayOfMonth = null;
|
||||
availability.weekOfMonth = 0;
|
||||
availability.endDate = repeatUntil;
|
||||
} else {
|
||||
availability.repeatWeekly = false;
|
||||
availability.dayOfMonth = availability.startTime.getDate();
|
||||
availability.endDate = null;
|
||||
}
|
||||
|
||||
availability.dateOfEntry = new Date();
|
||||
if (availability.parentAvailabilityId) {
|
||||
availability.parentAvailability = { connect: { id: parentAvailabilityId } };
|
||||
}
|
||||
delete availability.parentAvailabilityId;
|
||||
|
||||
return availability;
|
||||
}
|
||||
|
||||
@ -288,8 +304,7 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o
|
||||
|
||||
|
||||
const TimeSlotCheckboxes = ({ slots, setSlots, items: [] }) => {
|
||||
const [allDay, setAllDay] = useState(false);
|
||||
|
||||
const [allDay, setAllDay] = useState(slots.every(slot => slot.isChecked));
|
||||
const handleAllDayChange = (e) => {
|
||||
const updatedSlots = slots.map(slot => ({
|
||||
...slot,
|
||||
@ -297,7 +312,9 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o
|
||||
}));
|
||||
setSlots(updatedSlots);
|
||||
setAllDay(e.target.checked)
|
||||
setCanUpdate(true);
|
||||
// setCanUpdate(slots.some(slot => slot.isChecked));
|
||||
const anyChecked = updatedSlots.some(slot => slot.isChecked);
|
||||
setCanUpdate(anyChecked);
|
||||
console.log("handleAllDayChange: allDay: " + allDay + ", updatedSlots: " + JSON.stringify(updatedSlots));
|
||||
};
|
||||
useEffect(() => {
|
||||
@ -352,9 +369,9 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o
|
||||
|
||||
return (
|
||||
<div key={index} className="mb-1 flex justify-between items-center">
|
||||
<label className={`checkbox-container flex items-center mb-2 ${allDay ? 'opacity-50' : ''}`}>
|
||||
<label className={`checkbox-container flex items-center mb-2 `}>
|
||||
<input type="checkbox" checked={slot.isChecked || allDay} onChange={() => handleSlotCheckedChange(slot)}
|
||||
disabled={allDay}
|
||||
|
||||
className="form-checkbox h-5 w-5 text-gray-600 mx-2" />
|
||||
{slotLabel}
|
||||
<span className="checkmark"></span>
|
||||
@ -362,11 +379,11 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o
|
||||
|
||||
{/* Conditionally render transport checkbox based on slot being first or last */}
|
||||
{slot.transportNeeded && (
|
||||
<label className={`checkbox-container flex items-center ${(!slot.isChecked || allDay) ? 'opacity-50' : ''}`}>
|
||||
<label className={`checkbox-container flex items-center ${(!slot.isChecked) ? 'opacity-50' : ''}`}>
|
||||
<input type="checkbox"
|
||||
className="form-checkbox h-5 w-5 text-gray-600 mx-2"
|
||||
checked={slot.isWithTransport}
|
||||
disabled={!slot.isChecked || allDay}
|
||||
disabled={!slot.isChecked}
|
||||
onChange={() => handleTransportChange(slot)} />
|
||||
{slot.isFirst ? 'Вземане' : 'Връщане'}
|
||||
<span className="checkmark"></span>
|
||||
@ -395,12 +412,6 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o
|
||||
<div className="mb-2">
|
||||
<DatePicker label="Изберете дата" value={day} onChange={(value) => setDay({ value })} />
|
||||
</div>
|
||||
<div>
|
||||
<div className="mb-1">
|
||||
{/* Time slot checkboxes */}
|
||||
<TimeSlotCheckboxes slots={timeSlots} setSlots={setTimeSlots} items={availabilities} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-2">
|
||||
<label className="checkbox-container">
|
||||
@ -445,6 +456,13 @@ export default function AvailabilityForm({ publisherId, existingItems, inline, o
|
||||
<DatePicker label="До" value={repeatUntil} onChange={(value) => setRepeatUntil({ value })} />
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<div className="mb-1">
|
||||
{/* Time slot checkboxes */}
|
||||
<TimeSlotCheckboxes slots={timeSlots} setSlots={setTimeSlots} items={availabilities} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</LocalizationProvider>
|
||||
|
||||
<div className="flex justify-between items-center flex-nowrap w-full p-1">
|
||||
|
@ -165,7 +165,6 @@ export default function AvailabilityForm({ publisherId, existingItem, inline, on
|
||||
e.preventDefault();
|
||||
try {
|
||||
|
||||
|
||||
if (!availability.name) {
|
||||
// availability.name = "От календара";
|
||||
availability.name = common.getTimeFomatted(availability.startTime) + "-" + common.getTimeFomatted(availability.endTime);
|
||||
@ -174,12 +173,13 @@ export default function AvailabilityForm({ publisherId, existingItem, inline, on
|
||||
availability.dayofweek = common.getDayOfWeekNameEnEnum(availability.startTime);
|
||||
if (availability.repeatWeekly) {
|
||||
availability.dayOfMonth = null;
|
||||
availability.weekOfMonth = 0; //weekly recurrance - no need for week of month. special value 0
|
||||
} else {
|
||||
availability.endDate = null;
|
||||
availability.dayOfMonth = availability.startTime.getDate();
|
||||
}
|
||||
|
||||
delete availability.date; //remove date from availability as it is not part of the db model
|
||||
delete availability.date; //remove date from availability as it is not part of the db model. we store the info in startDate and endDate
|
||||
// ---------------------- CB UI --------------
|
||||
if (config.checkboxUI.enabled) {
|
||||
const selectedSlots = timeSlots.filter(slot => slot.isChecked);
|
||||
|
@ -12,7 +12,7 @@ module.exports = {
|
||||
pageExtensions: ['ts', 'tsx', 'md', 'mdx'], // Replace `jsx?` with `tsx?`
|
||||
env: {
|
||||
env: process.env.NODE_ENV,
|
||||
server: 'http://' + process.env.NEXT_PUBLIC_HOST + ':' + process.env.NEXT_PUBLIC_PORT + '',
|
||||
server: process.env.NEXT_PUBLIC_PUBLIC_URL
|
||||
},
|
||||
webpack(config, { isServer }) {
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
"homepage": "https://git.d-popov.com/popov/next-cart-app",
|
||||
"scripts": {
|
||||
"debug": "nodemon --inspect server.js",
|
||||
"debug-env": "cross-env NODE_ENV=development dotenv -e .env.development -- nodemon --inspect server.js",
|
||||
"debug-env-dev": "dotenv -e .env.development -- nodemon --inspect server.js",
|
||||
"build": "next build",
|
||||
"buildWin": "npm run build",
|
||||
"start": "next start",
|
||||
@ -109,4 +109,4 @@
|
||||
"depcheck": "^1.4.7",
|
||||
"prisma": "^5.11.0"
|
||||
}
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@ import { isLoggedIn, setAuthTokens, clearAuthTokens, getAccessToken, getRefreshT
|
||||
export const authOptions: NextAuthOptions = {
|
||||
// https://next-auth.js.org/configuration/providers/oauth
|
||||
|
||||
site: process.env.NEXTAUTH_URL,
|
||||
site: process.env.PUBLIC_URL,
|
||||
secret: process.env.NEXTAUTH_SECRET, // Ensure you have this set in your .env file
|
||||
//adapter: PrismaAdapter(prisma),
|
||||
providers: [
|
||||
|
@ -266,13 +266,19 @@ export default async function handler(req, res) {
|
||||
dayOfMonth: null,
|
||||
dayofweek: avail.dayofweek || common.getDayOfWeekNameEnEnum(avail.startTime),
|
||||
weekOfMonth: avail.weekofMonth || common.getWeekOfMonth(avail.startTime),
|
||||
dateOfEntry: new Date(), //avail.dateOfEntry || avail.startTime,
|
||||
// null for auto generated availabilities
|
||||
//dateOfEntry: new Date(), //avail.dateOfEntry || avail.startTime,
|
||||
startTime: newStart,
|
||||
endTime: newEnd,
|
||||
type: AvailabilityType.Monthly,
|
||||
isFromPreviousMonth: true,
|
||||
name: avail.name || "старо предпочитание",
|
||||
parentAvailabilityId: avail.id
|
||||
// parentAvailabilityId: avail.id
|
||||
parentAvailability: {
|
||||
connect: {
|
||||
id: avail.id
|
||||
}
|
||||
}
|
||||
}
|
||||
await prisma.availability.create({ data: data });
|
||||
|
||||
@ -587,7 +593,7 @@ export async function filterPublishers(selectFields, searchText, filterDate, fet
|
||||
// Check if dayOfMonth is null and match by day of week using the enum (Assigments every week)
|
||||
// This includes availabilities from previous assignments but not with preference
|
||||
{
|
||||
dayOfMonth: null,
|
||||
dayOfMonth: null, // includes monthly and weekly repeats
|
||||
dayofweek: dayOfWeekEnum,
|
||||
// ToDo: and weekOfMonth
|
||||
//startTime: { gte: currentMonthStart },
|
||||
@ -611,7 +617,6 @@ export async function filterPublishers(selectFields, searchText, filterDate, fet
|
||||
dayOfMonth: null,
|
||||
dayofweek: dayOfWeekEnum,
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -732,6 +737,11 @@ export async function filterPublishers(selectFields, searchText, filterDate, fet
|
||||
return avail.dayOfMonth != null && avail.startTime >= currentMonthStart; // && avail.startTime <= currentMonthEnd;
|
||||
});
|
||||
|
||||
//if pub has availabilities for the current day
|
||||
pub.hasAvailabilityForCurrentDay = pub.availabilities?.some(avail => {
|
||||
return avail.startTime >= filterDate && avail.startTime <= filterDateEnd;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
if (filterDate && useDateFilter) {
|
||||
|
@ -444,7 +444,7 @@ async function GenerateSchedule(axios: Axios, date: string, copyFromPreviousMont
|
||||
}
|
||||
|
||||
//create shifts using API
|
||||
// const { data: createdShifts } = await axios.post(`${process.env.NEXTAUTH_URL}/api/data/shifts`, shiftsToCreate);
|
||||
// const { data: createdShifts } = await axios.post(`${process.env.PUBLIC_URL}/api/data/shifts`, shiftsToCreate);
|
||||
//const { data: allshifts } = await axios.get(`/api/data/shifts`);
|
||||
return {}; //allshifts;
|
||||
|
||||
|
@ -133,7 +133,7 @@ export const getServerSideProps = async (context) => {
|
||||
|
||||
const role = session?.user.role;
|
||||
console.log("server role: " + role);
|
||||
var queryUrl = process.env.NEXTAUTH_URL + "/api/data/availabilities?select=id,name,isActive,dayofweek,dayOfMonth,startTime,endTime,publisher.firstName,publisher.lastName,publisher.id";
|
||||
var queryUrl = process.env.PUBLIC_URL + "/api/data/availabilities?select=id,name,isActive,dayofweek,dayOfMonth,startTime,endTime,publisher.firstName,publisher.lastName,publisher.id";
|
||||
if (role === UserRole.USER || context.query.my) {
|
||||
queryUrl += `&where={"publisherId":"${session?.user.id}"}`;
|
||||
} else if (role == UserRole.ADMIN) {
|
||||
@ -145,7 +145,7 @@ export const getServerSideProps = async (context) => {
|
||||
}
|
||||
var resp = await axios.get(
|
||||
queryUrl
|
||||
// process.env.NEXTAUTH_URL + "/api/data/availabilities?include=publisher",
|
||||
// process.env.PUBLIC_URL + "/api/data/availabilities?include=publisher",
|
||||
, { decompress: true });
|
||||
var items = resp.data;
|
||||
console.log("got " + items.length + " availabilities");
|
||||
|
@ -31,7 +31,7 @@ export const getServerSideProps = async (context) => {
|
||||
};
|
||||
}
|
||||
const { data: item } = await axios.get(
|
||||
process.env.NEXTAUTH_URL + "/api/data/availabilities/" + context.params.id
|
||||
process.env.PUBLIC_URL + "/api/data/availabilities/" + context.params.id
|
||||
);
|
||||
|
||||
return {
|
||||
|
@ -893,7 +893,7 @@ export const getServerSideProps = async (context) => {
|
||||
const axios = await axiosServer(context);
|
||||
const baseUrl = common.getBaseUrl();
|
||||
console.log('runtime BaseUrl: ' + baseUrl);
|
||||
console.log('runtime NEXTAUTH_URL: ' + process.env.NEXTAUTH_URL);
|
||||
console.log('runtime PUBLIC_URL: ' + process.env.PUBLIC_URL);
|
||||
console.log('Runtime Axios Base URL:', axios.defaults.baseURL);
|
||||
|
||||
const currentDate = new Date();
|
||||
|
@ -7,9 +7,9 @@ export const getServerSideProps = async (context) => {
|
||||
console.log("edit page getServerSideProps");
|
||||
const axios = await axiosServer(context);
|
||||
const { id } = context.query;
|
||||
const { data } = await axios.get(`${process.env.NEXTAUTH_URL}/api/data/cartevents/` + id);
|
||||
const { data } = await axios.get(`${process.env.PUBLIC_URL}/api/data/cartevents/` + id);
|
||||
const locations = await axios
|
||||
.get(`${process.env.NEXTAUTH_URL}/api/data/locations?select=id,name`)
|
||||
.get(`${process.env.PUBLIC_URL}/api/data/locations?select=id,name`)
|
||||
.then((res) => {
|
||||
console.log("locations: " + JSON.stringify(res.data));
|
||||
return res.data;
|
||||
|
@ -26,7 +26,7 @@ export const getServerSideProps = async (context) => {
|
||||
|
||||
const axios = await axiosServer(context);
|
||||
const locations = await axios
|
||||
.get(`${process.env.NEXTAUTH_URL}/api/data/locations?select=id,name`)
|
||||
.get(`${process.env.PUBLIC_URL}/api/data/locations?select=id,name`)
|
||||
.then((res) => {
|
||||
console.log("locations: " + JSON.stringify(res.data));
|
||||
return res.data;
|
||||
@ -41,7 +41,7 @@ export const getServerSideProps = async (context) => {
|
||||
|
||||
const { id } = context.query.id;
|
||||
const { data: item } = await axiosInstance.get(
|
||||
process.env.NEXTAUTH_URL + "/api/data/cartevents/" + context.params.id
|
||||
process.env.PUBLIC_URL + "/api/data/cartevents/" + context.params.id
|
||||
);
|
||||
|
||||
return {
|
||||
|
@ -99,11 +99,11 @@ export const getServerSideProps: GetServerSideProps = async (context) => {
|
||||
const axios = await axiosServer(context);
|
||||
|
||||
const { data: location } = await axios.get(
|
||||
`${process.env.NEXTAUTH_URL}/api/data/locations/${context.params.id}`
|
||||
`${process.env.PUBLIC_URL}/api/data/locations/${context.params.id}`
|
||||
);
|
||||
if (location.backupLocationId !== null) {
|
||||
const { data: backupLocation } = await axios.get(
|
||||
process.env.NEXTAUTH_URL + "/api/data/locations/" + location.backupLocationId
|
||||
process.env.PUBLIC_URL + "/api/data/locations/" + location.backupLocationId
|
||||
);
|
||||
location.backupLocationName = backupLocation.name;
|
||||
location.backupLocationContent = backupLocation ? backupLocation.content : "";
|
||||
|
@ -29,7 +29,7 @@ export const getServerSideProps = async (context) => {
|
||||
};
|
||||
}
|
||||
const { data: item } = await axios.get(
|
||||
process.env.NEXTAUTH_URL + "/api/data/locations/" + context.params.id
|
||||
process.env.PUBLIC_URL + "/api/data/locations/" + context.params.id
|
||||
);
|
||||
console.log(item) //this is the location object
|
||||
context.res.setHeader("Cache-Control", "s-maxage=1, stale-while-revalidate");
|
||||
|
@ -32,7 +32,7 @@ export const getServerSideProps = async (context) => {
|
||||
}
|
||||
|
||||
const { data: loc } = await axios.get(
|
||||
`${process.env.NEXTAUTH_URL}api/data/locations/` + context.params.id
|
||||
`${process.env.PUBLIC_URL}api/data/locations/` + context.params.id
|
||||
);
|
||||
console.log(location) //this is the location object
|
||||
context.res.setHeader("Cache-Control", "s-maxage=1, stale-while-revalidate");
|
||||
|
@ -44,7 +44,7 @@ export const getServerSideProps = async (context) => {
|
||||
props: {}
|
||||
};
|
||||
}
|
||||
var url = process.env.NEXTAUTH_URL + "/api/data/publishers/" + context.query.id + "?include=availabilities,assignments,assignments.shift";
|
||||
var url = process.env.PUBLIC_URL + "/api/data/publishers/" + context.query.id + "?include=availabilities,assignments,assignments.shift";
|
||||
console.log("GET PUBLISHER FROM:" + url)
|
||||
const { data: item } = await axios.get(url);
|
||||
|
||||
|
@ -47,7 +47,7 @@ export const getServerSideProps = async (context) => {
|
||||
props: {}
|
||||
};
|
||||
}
|
||||
var url = process.env.NEXTAUTH_URL + "/api/data/publishers/" + context.query.id + "?include=availabilities,shifts";
|
||||
var url = process.env.PUBLIC_URL + "/api/data/publishers/" + context.query.id + "?include=availabilities,shifts";
|
||||
console.log("GET PUBLISHER FROM:" + url)
|
||||
const { data } = await axios.get(url);
|
||||
|
||||
|
@ -32,7 +32,7 @@ export const getServerSideProps = async (context) => {
|
||||
// };
|
||||
// }
|
||||
// const { data: loc } = await axiosInstance.get(
|
||||
// `${process.env.NEXTAUTH_URL}api/data/locations/` + context.params.id
|
||||
// `${process.env.PUBLIC_URL}api/data/locations/` + context.params.id
|
||||
// );
|
||||
|
||||
// console.log(location) //this is the location object
|
||||
|
@ -33,7 +33,7 @@ export const getServerSideProps = async (context) => {
|
||||
// }
|
||||
|
||||
// const { data: loc } = await axiosInstance.get(
|
||||
// `${process.env.NEXTAUTH_URL}api/data/locations/` + context.params.id
|
||||
// `${process.env.PUBLIC_URL}api/data/locations/` + context.params.id
|
||||
// );
|
||||
// console.log(location) //this is the location object
|
||||
// context.res.setHeader("Cache-Control", "s-maxage=1, stale-while-revalidate");
|
||||
|
2
process.d.ts
vendored
2
process.d.ts
vendored
@ -1,6 +1,6 @@
|
||||
declare namespace NodeJS {
|
||||
export interface ProcessEnv {
|
||||
NEXTAUTH_URL: string
|
||||
PUBLIC_URL: string
|
||||
NEXTAUTH_SECRET: string
|
||||
GITHUB_ID: string
|
||||
GITHUB_SECRET: string
|
||||
|
67
server.js
67
server.js
@ -28,22 +28,23 @@ let baseUrlGlobal;
|
||||
// require('dotenv').config();
|
||||
// }
|
||||
|
||||
console.log("initial process.env.NODE_ENV = ", process.env.NODE_ENV);
|
||||
console.log("initial process.env.NODE_ENV = ", process.env.NODE_ENV); //NODE_ENV can be passed as docker param
|
||||
require('dotenv').config({
|
||||
path: `.env.${process.env.NODE_ENV}`
|
||||
});
|
||||
|
||||
console.log("process.env.NODE_ENV = ", process.env.NODE_ENV);
|
||||
|
||||
const PORT = process.env.NEXT_PUBLIC_PORT || 3000;
|
||||
const HOST = process.env.NEXT_PUBLIC_HOST;
|
||||
const PROTOCOL = process.env.PROTOCOL;
|
||||
const PORT = process.env.PORT || 3000;
|
||||
const HOST = process.env.HOST;
|
||||
|
||||
const dev = process.env.NODE_ENV !== "production";
|
||||
const PROTOCOL = process.env.NEXT_PUBLIC_PROTOCOL;
|
||||
const nextApp = next({ dev });
|
||||
const nextHandler = nextApp.getRequestHandler();
|
||||
console.log("process.env.SSL_ENABLED = ", process.env.SSL_ENABLED);
|
||||
console.log("process.env.NEXTAUTH_URL = ", process.env.NEXTAUTH_URL);
|
||||
console.log("process.env.NEXT_PUBLIC_PORT = ", process.env.NEXT_PUBLIC_PORT);
|
||||
console.log("process.env.PROTOCOL = ", process.env.PROTOCOL);
|
||||
console.log("process.env.PUBLIC_URL = ", process.env.NEXT_PUBLIC_PUBLIC_URL);
|
||||
console.log("process.env.PORT = ", process.env.PORT);
|
||||
console.log("process.env.TELEGRAM_BOT = ", process.env.TELEGRAM_BOT);
|
||||
|
||||
//require('module-alias/register');
|
||||
@ -62,12 +63,37 @@ const uploadTmp = multer({ storage: storageMem });
|
||||
|
||||
|
||||
const prisma = common.getPrismaClient();
|
||||
const server = express();
|
||||
|
||||
//check if ssl is enabled
|
||||
if (process.env.PROTOCOL === 'https') {
|
||||
console.log("SSL_ENABLED = true");
|
||||
// Redirect from http to https
|
||||
// server.use((req, res, next) => {
|
||||
// if (req.headers['x-forwarded-proto'] !== 'https') {
|
||||
// return res.redirect(`https://${req.headers.host}${req.url}`);
|
||||
// }
|
||||
// next();
|
||||
// });
|
||||
if (process.env.SSL_KEY && process.env.SSL_CERT) {
|
||||
const options = {
|
||||
key: fs.readFileSync(process.env.SSL_KEY),
|
||||
cert: fs.readFileSync(process.env.SSL_CERT),
|
||||
secureProtocol: 'TLSv1_2_method', // Example: Force TLS 1.2
|
||||
};
|
||||
https.createServer(options, server).listen(PORT);
|
||||
}
|
||||
}
|
||||
else {
|
||||
server.listen(PORT, (err) => {
|
||||
if (err) throw err;
|
||||
console.log(`> Ready on ${PROTOCOL}://${HOST}:${PORT}`);
|
||||
});
|
||||
}
|
||||
// handlers
|
||||
nextApp
|
||||
.prepare()
|
||||
.then(() => {
|
||||
const server = express();
|
||||
|
||||
// Add the middleware to set 'x-forwarded-host' header
|
||||
server.use((req, res, next) => {
|
||||
@ -558,31 +584,6 @@ nextApp
|
||||
return nextHandler(req, res);
|
||||
});
|
||||
|
||||
//check if ssl is enabled
|
||||
if (process.env.SSL_ENABLED === "true") {
|
||||
console.log("SSL_ENABLED = true");
|
||||
// Redirect from http to https
|
||||
// server.use((req, res, next) => {
|
||||
// if (req.headers['x-forwarded-proto'] !== 'https') {
|
||||
// return res.redirect(`https://${req.headers.host}${req.url}`);
|
||||
// }
|
||||
// next();
|
||||
// });
|
||||
if (process.env.SSL_KEY && process.env.SSL_CERT) {
|
||||
const options = {
|
||||
key: fs.readFileSync(process.env.SSL_KEY),
|
||||
cert: fs.readFileSync(process.env.SSL_CERT),
|
||||
secureProtocol: 'TLSv1_2_method', // Example: Force TLS 1.2
|
||||
};
|
||||
https.createServer(options, server).listen(PORT);
|
||||
}
|
||||
}
|
||||
else {
|
||||
server.listen(PORT, (err) => {
|
||||
if (err) throw err;
|
||||
console.log(`> Ready on ${PROTOCOL}://${HOST}:${PORT}`);
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((ex) => {
|
||||
console.warn(`Error starting server on ${HOST}:${PORT}`)
|
||||
|
@ -76,39 +76,7 @@ exports.setBaseUrl = function (req) {
|
||||
};
|
||||
|
||||
exports.getBaseUrl = function (relative = "", req = null) {
|
||||
if (typeof window === 'undefined') {
|
||||
// Server-side logic
|
||||
// Read the base URL from env (NEXTAUTH_URL):
|
||||
return process.env.NEXTAUTH_URL + relative;
|
||||
|
||||
// const filePath = path.join(__dirname, 'baseUrl.txt');
|
||||
|
||||
// try {
|
||||
// if (fs.existsSync(filePath)) {
|
||||
// const baseUrl = fs.readFileSync(filePath, 'utf8').trim();
|
||||
// const fullUrl = relative ? new URL(relative, baseUrl).toString() : baseUrl;
|
||||
// return fullUrl;
|
||||
// } else {
|
||||
// if (req) {
|
||||
// // Assuming setBaseUrl is defined somewhere in this file
|
||||
// const baseUrl = exports.setBaseUrl(req);
|
||||
// return `${baseUrl}/${relative.replace(/^\/|\/$/g, '')}`;
|
||||
// }
|
||||
// console.log('Base URL file does not exist.');
|
||||
// return null;
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error('Error reading the base URL file:', error);
|
||||
// return null;
|
||||
// }
|
||||
} else {
|
||||
// Client-side logic
|
||||
// Fetch the base URL from the server endpoint you've set up
|
||||
const baseUrl = window.location.origin;
|
||||
const fullUrl = relative ? `${baseUrl}/${relative.replace(/^\/|\/$/g, '')}` : baseUrl;
|
||||
//console.log("getBaseUrl()=", fullUrl);
|
||||
return fullUrl.toString();
|
||||
}
|
||||
return process.env.NEXT_PUBLIC_PUBLIC_URL + relative;
|
||||
};
|
||||
|
||||
|
||||
@ -122,6 +90,8 @@ exports.getPrismaClient = function getPrismaClient() {
|
||||
datasources: { db: { url: process.env.DATABASE_URL } },
|
||||
});
|
||||
}
|
||||
logger.debug("getPrismaClient: process.env.DATABASE_URL = ", process.env.DATABASE_URL);
|
||||
|
||||
return prisma;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user