mirror of
https://github.com/jakobkordez/ham-reserve.git
synced 2025-05-31 08:49:06 +00:00
Changes
This commit is contained in:
parent
fb54ba537f
commit
21c63f0333
@ -21,15 +21,17 @@ export class EventsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
findCurrent(): Promise<Event[]> {
|
findCurrent(): Promise<Event[]> {
|
||||||
const now = new Date();
|
const now = Date.now();
|
||||||
|
const from = new Date(now - 1000 * 60 * 60 * 24 * 7);
|
||||||
|
const to = new Date(now + 1000 * 60 * 60 * 24 * 7);
|
||||||
return this.eventModel
|
return this.eventModel
|
||||||
.find({
|
.find({
|
||||||
$and: [
|
$and: [
|
||||||
{
|
{
|
||||||
$or: [{ fromDateTime: [null] }, { fromDateTime: { $lte: now } }],
|
$or: [{ fromDateTime: [null] }, { fromDateTime: { $lte: to } }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
$or: [{ toDateTime: [null] }, { toDateTime: { $gte: now } }],
|
$or: [{ toDateTime: [null] }, { toDateTime: { $gte: from } }],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
$nor: [{ isDeleted: true }, { isPrivate: true }],
|
$nor: [{ isDeleted: true }, { isPrivate: true }],
|
||||||
|
@ -12,7 +12,10 @@ export class UsersService {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
create(createUserDto: CreateUserDto): Promise<User> {
|
create(createUserDto: CreateUserDto): Promise<User> {
|
||||||
const user = new this.userModel(createUserDto);
|
const user = new this.userModel({
|
||||||
|
...createUserDto,
|
||||||
|
passwordResetRequired: true,
|
||||||
|
});
|
||||||
return user.save();
|
return user.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import { PrivateTag } from '@/components/private-tag';
|
|||||||
import { ProgressBar } from '@/components/progress-bar';
|
import { ProgressBar } from '@/components/progress-bar';
|
||||||
import { Event } from '@/interfaces/event.interface';
|
import { Event } from '@/interfaces/event.interface';
|
||||||
import { User } from '@/interfaces/user.interface';
|
import { User } from '@/interfaces/user.interface';
|
||||||
|
import { getUTCString } from '@/util/date.util';
|
||||||
import { faMinus, faPlus } from '@fortawesome/free-solid-svg-icons';
|
import { faMinus, faPlus } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
@ -34,8 +35,8 @@ export function EventComponent({ event }: EventComponentProps) {
|
|||||||
{event.fromDateTime && event.toDateTime && (
|
{event.fromDateTime && event.toDateTime && (
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<div className="mb-2 flex justify-between">
|
<div className="mb-2 flex justify-between">
|
||||||
<div>{event.fromDateTime.toLocaleString()}</div>
|
<div>{getUTCString(event.fromDateTime)}</div>
|
||||||
<div>{event.toDateTime.toLocaleString()}</div>
|
<div>{getUTCString(event.toDateTime)}</div>
|
||||||
</div>
|
</div>
|
||||||
<ProgressBar start={event.fromDateTime} end={event.toDateTime} />
|
<ProgressBar start={event.fromDateTime} end={event.toDateTime} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import { apiFunctions } from '@/api';
|
import { apiFunctions } from '@/api';
|
||||||
import { PrivateTag } from '@/components/private-tag';
|
import { PrivateTag } from '@/components/private-tag';
|
||||||
import { Event } from '@/interfaces/event.interface';
|
import { Event } from '@/interfaces/event.interface';
|
||||||
|
import { getUTCString } from '@/util/date.util';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
@ -33,8 +34,13 @@ export function EventsList() {
|
|||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td className="flex-1 text-sm opacity-80">
|
<td className="flex-1 text-sm opacity-80">
|
||||||
<div>Od: {event.fromDateTime?.toLocaleDateString() ?? '/'}</div>
|
<div>
|
||||||
<div>Do: {event.toDateTime?.toLocaleDateString() ?? '/'}</div>
|
Od:{' '}
|
||||||
|
{event.fromDateTime ? getUTCString(event.fromDateTime) : '/'}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Do: {event.toDateTime ? getUTCString(event.toDateTime) : '/'}
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<th>
|
<th>
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import { redirect } from 'next/navigation';
|
import { redirect } from 'next/navigation';
|
||||||
|
|
||||||
export default function AdminPage() {
|
export default function AdminPage() {
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import { User } from '@/interfaces/user.interface';
|
|
||||||
|
|
||||||
interface DeleteUserDialogProps {
|
|
||||||
user: User | undefined;
|
|
||||||
onCancel: () => void;
|
|
||||||
onConfirm: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function DeleteUserDialog({ user }: DeleteUserDialogProps) {
|
|
||||||
return (
|
|
||||||
<dialog id="delete_user" className="modal">
|
|
||||||
<div className="modal-box">
|
|
||||||
<h3 className="text-lg font-bold">Izbriši uporabnika</h3>
|
|
||||||
<p className="py-4">
|
|
||||||
Are you sure you want to deactivate the account "
|
|
||||||
<strong className="text-black">{user?.username}</strong>
|
|
||||||
"? This action cannot be undone.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<form method="dialog" className="modal-backdrop">
|
|
||||||
<button>close</button>
|
|
||||||
</form>
|
|
||||||
</dialog>
|
|
||||||
);
|
|
||||||
}
|
|
@ -50,10 +50,8 @@ export function UsersList() {
|
|||||||
<tr key={user._id}>
|
<tr key={user._id}>
|
||||||
<td className="my-auto flex-1">
|
<td className="my-auto flex-1">
|
||||||
<div className="text-xl">
|
<div className="text-xl">
|
||||||
<span className="font-callsign">
|
<span className="font-callsign">{user.username}</span> -{' '}
|
||||||
{user.username.toUpperCase()}
|
{user.name}
|
||||||
</span>{' '}
|
|
||||||
- {user.name}
|
|
||||||
</div>{' '}
|
</div>{' '}
|
||||||
<div className="text-xs opacity-80">{user._id}</div>
|
<div className="text-xs opacity-80">{user._id}</div>
|
||||||
</td>
|
</td>
|
||||||
@ -115,6 +113,17 @@ export function UsersList() {
|
|||||||
type="button"
|
type="button"
|
||||||
className="btn btn-error"
|
className="btn btn-error"
|
||||||
// onClick={onConfirm}
|
// onClick={onConfirm}
|
||||||
|
onClick={() => {
|
||||||
|
apiFunctions
|
||||||
|
.deleteUser(deleteUser!._id)
|
||||||
|
.then(() => {
|
||||||
|
getUsers();
|
||||||
|
dialogRef.current?.close();
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
Izbriši
|
Izbriši
|
||||||
</button>
|
</button>
|
||||||
@ -122,7 +131,7 @@ export function UsersList() {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn"
|
className="btn"
|
||||||
// onClick={onCancel}
|
onClick={() => dialogRef.current?.close()}
|
||||||
>
|
>
|
||||||
Prekliči
|
Prekliči
|
||||||
</button>
|
</button>
|
||||||
|
@ -11,6 +11,7 @@ import { User } from '@/interfaces/user.interface';
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useUserState } from '@/state/user-state';
|
import { useUserState } from '@/state/user-state';
|
||||||
|
import { Role } from '@/enums/role.enum';
|
||||||
|
|
||||||
interface EventComponentProps {
|
interface EventComponentProps {
|
||||||
event: Event;
|
event: Event;
|
||||||
@ -27,12 +28,15 @@ export function EventComponent({ event }: EventComponentProps) {
|
|||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-8">
|
<div className="flex flex-col gap-8">
|
||||||
<div>
|
<div>
|
||||||
<div className="flex flex-col items-start gap-2">
|
<div className="flex justify-between">
|
||||||
<h1 className="font-callsign text-4xl font-medium">
|
<div className="flex flex-col items-start gap-2">
|
||||||
{event.callsign}
|
<h1 className="font-callsign text-4xl font-medium">
|
||||||
</h1>
|
{event.callsign}
|
||||||
<p className="opacity-90">{event.description}</p>
|
</h1>
|
||||||
{event.isPrivate && <PrivateTag />}
|
<p className="opacity-90">{event.description}</p>
|
||||||
|
{event.isPrivate && <PrivateTag />}
|
||||||
|
</div>
|
||||||
|
<EditButton id={event._id} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{event.fromDateTime && event.toDateTime && (
|
{event.fromDateTime && event.toDateTime && (
|
||||||
@ -76,3 +80,16 @@ export function EventComponent({ event }: EventComponentProps) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function EditButton({ id }: { id: string }) {
|
||||||
|
const user = useUserState((s) => s.user);
|
||||||
|
console.log(user);
|
||||||
|
|
||||||
|
if (!user || !user.roles.includes(Role.Admin)) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Link href={`/admin/events/${id}`} className="btn btn-warning btn-sm">
|
||||||
|
Uredi
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -2,7 +2,13 @@
|
|||||||
import { apiFunctions } from '@/api';
|
import { apiFunctions } from '@/api';
|
||||||
import { Event } from '@/interfaces/event.interface';
|
import { Event } from '@/interfaces/event.interface';
|
||||||
import { Reservation } from '@/interfaces/reservation.interface';
|
import { Reservation } from '@/interfaces/reservation.interface';
|
||||||
import { dayInMs, dayInWeeks, getNextNDays } from '@/util/date.util';
|
import {
|
||||||
|
dayInMs,
|
||||||
|
dayInWeeks,
|
||||||
|
getNextNDays,
|
||||||
|
getUTCDMString,
|
||||||
|
getUTCDateString,
|
||||||
|
} from '@/util/date.util';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { Band } from '@/enums/band.enum';
|
import { Band } from '@/enums/band.enum';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
@ -22,6 +28,7 @@ export function FreeDatesComponent({ event }: { event: Event }) {
|
|||||||
const end = dates[dates.length - 1]?.toISOString();
|
const end = dates[dates.length - 1]?.toISOString();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
setReservations(undefined);
|
||||||
apiFunctions
|
apiFunctions
|
||||||
.getReservationsForEvent(event._id, {
|
.getReservationsForEvent(event._id, {
|
||||||
start,
|
start,
|
||||||
@ -31,7 +38,9 @@ export function FreeDatesComponent({ event }: { event: Event }) {
|
|||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
}, [event._id, start, end]);
|
}, [event._id, start, end]);
|
||||||
|
|
||||||
const freeTable = bands.map(() => dates.map(() => true));
|
const freeTable = bands.map(() =>
|
||||||
|
dates.map<boolean | null>(() => (reservations == undefined ? null : true)),
|
||||||
|
);
|
||||||
|
|
||||||
for (const reservation of reservations ?? []) {
|
for (const reservation of reservations ?? []) {
|
||||||
const forDateDay = reservation.forDate.valueOf() / dayInMs;
|
const forDateDay = reservation.forDate.valueOf() / dayInMs;
|
||||||
@ -56,8 +65,10 @@ export function FreeDatesComponent({ event }: { event: Event }) {
|
|||||||
</button>
|
</button>
|
||||||
<div className="join-item flex w-full bg-base-200">
|
<div className="join-item flex w-full bg-base-200">
|
||||||
<div className="m-auto">
|
<div className="m-auto">
|
||||||
{dates[0]?.toLocaleDateString('sl')} -{' '}
|
{dates[0] ? getUTCDateString(dates[0]) : ''} -{' '}
|
||||||
{dates[dates.length - 1]?.toLocaleDateString('sl')}
|
{dates[dates.length - 1]
|
||||||
|
? getUTCDateString(dates[dates.length - 1])
|
||||||
|
: ''}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
@ -85,9 +96,7 @@ export function FreeDatesComponent({ event }: { event: Event }) {
|
|||||||
{dates.map((date, i) => (
|
{dates.map((date, i) => (
|
||||||
<th key={i} className="px-3">
|
<th key={i} className="px-3">
|
||||||
<div>{dayInWeeks[date.getUTCDay()]}</div>
|
<div>{dayInWeeks[date.getUTCDay()]}</div>
|
||||||
<div>
|
<div>{getUTCDMString(date)}</div>
|
||||||
{date.getUTCDate()}. {date.getUTCMonth() + 1}.
|
|
||||||
</div>
|
|
||||||
</th>
|
</th>
|
||||||
))}
|
))}
|
||||||
</tr>
|
</tr>
|
||||||
@ -105,7 +114,11 @@ export function FreeDatesComponent({ event }: { event: Event }) {
|
|||||||
className={`m-auto h-3 w-full${
|
className={`m-auto h-3 w-full${
|
||||||
i > 0 ? '' : ' rounded-l-full'
|
i > 0 ? '' : ' rounded-l-full'
|
||||||
}${i == dates.length - 1 ? ' rounded-r-full' : ''} ${
|
}${i == dates.length - 1 ? ' rounded-r-full' : ''} ${
|
||||||
isFree ? 'bg-green-500' : 'bg-red-500'
|
isFree == null
|
||||||
|
? 'bg-base-200'
|
||||||
|
: isFree
|
||||||
|
? 'bg-green-500/90'
|
||||||
|
: 'bg-red-500/90'
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
|
@ -6,7 +6,7 @@ import { Mode } from '@/enums/mode.enum';
|
|||||||
import { Event } from '@/interfaces/event.interface';
|
import { Event } from '@/interfaces/event.interface';
|
||||||
import { User } from '@/interfaces/user.interface';
|
import { User } from '@/interfaces/user.interface';
|
||||||
import { useUserState } from '@/state/user-state';
|
import { useUserState } from '@/state/user-state';
|
||||||
import { getNextNDays } from '@/util/date.util';
|
import { getNextNDays, getUTCDMString } from '@/util/date.util';
|
||||||
import { faTriangleExclamation } from '@fortawesome/free-solid-svg-icons';
|
import { faTriangleExclamation } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
@ -85,7 +85,7 @@ export function ReserveComponent({ event }: ReserveComponentProps) {
|
|||||||
date?.valueOf() === dt?.valueOf() ? 'btn-primary' : ''
|
date?.valueOf() === dt?.valueOf() ? 'btn-primary' : ''
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{dt.getDate()}. {dt.getMonth() + 1}.
|
{getUTCDMString(dt)}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { Header } from '@/components/header';
|
import { Header } from '@/components/header';
|
||||||
import { THEME_DARK, useThemeState } from '@/state/theme-state';
|
import { THEME_LIGHT } from '@/state/theme-state';
|
||||||
import { Allerta, Inter } from 'next/font/google';
|
import { Allerta, Inter } from 'next/font/google';
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
|
|
||||||
const callsignFont = Allerta({
|
const callsignFont = Allerta({
|
||||||
subsets: ['latin'],
|
subsets: ['latin'],
|
||||||
@ -14,15 +13,15 @@ const callsignFont = Allerta({
|
|||||||
const inter = Inter({ subsets: ['latin'] });
|
const inter = Inter({ subsets: ['latin'] });
|
||||||
|
|
||||||
export function LayoutComponent({ children }: { children: React.ReactNode }) {
|
export function LayoutComponent({ children }: { children: React.ReactNode }) {
|
||||||
const [theme, setTheme] = useState<string>(THEME_DARK);
|
// const [theme, setTheme] = useState<string>(THEME_DARK);
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
setTheme(useThemeState.getState().theme);
|
// setTheme(useThemeState.getState().theme);
|
||||||
useThemeState.subscribe((s) => setTheme(s.theme));
|
// useThemeState.subscribe((s) => setTheme(s.theme));
|
||||||
}, []);
|
// }, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang="sl" data-theme={theme}>
|
<html lang="sl" data-theme={THEME_LIGHT}>
|
||||||
<body
|
<body
|
||||||
className={`${inter.className} ${callsignFont.variable} dark:[color-scheme:dark]`}
|
className={`${inter.className} ${callsignFont.variable} dark:[color-scheme:dark]`}
|
||||||
>
|
>
|
||||||
|
@ -4,7 +4,7 @@ import { apiFunctions } from '@/api';
|
|||||||
import { Event } from '@/interfaces/event.interface';
|
import { Event } from '@/interfaces/event.interface';
|
||||||
import { LogSummary } from '@/interfaces/log-summary.interface';
|
import { LogSummary } from '@/interfaces/log-summary.interface';
|
||||||
import { Reservation } from '@/interfaces/reservation.interface';
|
import { Reservation } from '@/interfaces/reservation.interface';
|
||||||
import { getUTCString } from '@/util/date.util';
|
import { getUTCDateString, getUTCString } from '@/util/date.util';
|
||||||
import {
|
import {
|
||||||
faFileCircleCheck,
|
faFileCircleCheck,
|
||||||
faFileCircleExclamation,
|
faFileCircleExclamation,
|
||||||
@ -27,7 +27,7 @@ export function ReservationComponent({
|
|||||||
<h1 className="font-callsign text-3xl">{event.callsign}</h1>
|
<h1 className="font-callsign text-3xl">{event.callsign}</h1>
|
||||||
|
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<div>Datum: {reservation.forDate.toISOString().slice(0, 10)}</div>
|
<div>Datum: {getUTCDateString(reservation.forDate)}</div>
|
||||||
<div>Frekvenčni pasovi: {reservation.bands.join(', ')}</div>
|
<div>Frekvenčni pasovi: {reservation.bands.join(', ')}</div>
|
||||||
<div>Način dela: {reservation.modes.join(', ')}</div>
|
<div>Način dela: {reservation.modes.join(', ')}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Event } from '@/interfaces/event.interface';
|
import { Event } from '@/interfaces/event.interface';
|
||||||
import { ProgressBar } from './progress-bar';
|
import { ProgressBar } from './progress-bar';
|
||||||
|
import { getUTCDateString, getUTCTimeString } from '@/util/date.util';
|
||||||
|
|
||||||
interface EventCardProps {
|
interface EventCardProps {
|
||||||
event: Event;
|
event: Event;
|
||||||
@ -7,7 +8,7 @@ interface EventCardProps {
|
|||||||
|
|
||||||
export function EventCard({ event }: EventCardProps) {
|
export function EventCard({ event }: EventCardProps) {
|
||||||
return (
|
return (
|
||||||
<div className="card bg-base-100 flex h-full flex-col justify-between gap-3 border border-primary shadow-xl">
|
<div className="card flex h-full flex-col justify-between gap-3 border border-neutral-200 shadow-lg dark:border-0 dark:bg-neutral dark:text-neutral-content">
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="font-callsign card-title mb-1 text-2xl">
|
<h1 className="font-callsign card-title mb-1 text-2xl">
|
||||||
@ -19,24 +20,35 @@ export function EventCard({ event }: EventCardProps) {
|
|||||||
) : (
|
) : (
|
||||||
<p className="font-light italic">Brez opisa</p>
|
<p className="font-light italic">Brez opisa</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{event.fromDateTime && event.fromDateTime > new Date() && (
|
||||||
|
<div className="badge badge-primary mt-3 w-full">Začetek kmalu</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{event.toDateTime && event.toDateTime < new Date() && (
|
||||||
|
<div className="badge badge-ghost mt-3 w-full">Zaključeno</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{(event.fromDateTime != undefined) !==
|
{(event.fromDateTime != undefined) !==
|
||||||
(event.toDateTime != undefined) && (
|
(event.toDateTime != undefined) && (
|
||||||
<div>
|
<div className="mt-2 text-sm">
|
||||||
{event.fromDateTime ? 'Od' : 'Do'}:{' '}
|
<span className="font-bold">
|
||||||
{(event.fromDateTime ?? event.toDateTime!).toLocaleDateString()}
|
{event.fromDateTime ? 'Od' : 'Do'}:
|
||||||
|
</span>{' '}
|
||||||
|
{getUTCDateString(event.fromDateTime ?? event.toDateTime!)}{' '}
|
||||||
|
{getUTCTimeString(event.fromDateTime ?? event.toDateTime!)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{event.fromDateTime && event.toDateTime && (
|
{event.fromDateTime && event.toDateTime && (
|
||||||
<div className="mt-2">
|
<div className="mt-2 text-sm">
|
||||||
<div className="flex justify-between text-sm">
|
<div className="flex justify-between">
|
||||||
{event.fromDateTime && (
|
<div>{getUTCDateString(event.fromDateTime)}</div>
|
||||||
<div>{event.fromDateTime.toLocaleDateString()}</div>
|
<div>{getUTCDateString(event.toDateTime)}</div>
|
||||||
)}
|
</div>
|
||||||
{event.toDateTime && (
|
<div className="flex justify-between">
|
||||||
<div>{event.toDateTime.toLocaleDateString()}</div>
|
<div>{getUTCTimeString(event.fromDateTime)}</div>
|
||||||
)}
|
<div>{getUTCTimeString(event.toDateTime)}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ProgressBar start={event.fromDateTime} end={event.toDateTime} />
|
<ProgressBar start={event.fromDateTime} end={event.toDateTime} />
|
||||||
|
@ -2,29 +2,28 @@
|
|||||||
|
|
||||||
import { Role } from '@/enums/role.enum';
|
import { Role } from '@/enums/role.enum';
|
||||||
import { useAuthState } from '@/state/auth-state';
|
import { useAuthState } from '@/state/auth-state';
|
||||||
import { THEME_DARK, useThemeState } from '@/state/theme-state';
|
|
||||||
import { useUserState } from '@/state/user-state';
|
import { useUserState } from '@/state/user-state';
|
||||||
import { faMoon, faSun, faUserCircle } from '@fortawesome/free-solid-svg-icons';
|
import { faUserCircle } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
export function Header() {
|
export function Header() {
|
||||||
const [theme, setTheme] = useState<string>(THEME_DARK);
|
// const [theme, setTheme] = useState<string>(THEME_DARK);
|
||||||
const toggleTheme = useThemeState((s) => s.toggleTheme);
|
// const toggleTheme = useThemeState((s) => s.toggleTheme);
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
setTheme(useThemeState.getState().theme);
|
// setTheme(useThemeState.getState().theme);
|
||||||
useThemeState.subscribe((s) => setTheme(s.theme));
|
// useThemeState.subscribe((s) => setTheme(s.theme));
|
||||||
}, []);
|
// }, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-16 select-none justify-between border-b border-primary">
|
<div className="flex h-16 select-none justify-between bg-primary text-primary-content shadow-md dark:border-b dark:border-primary">
|
||||||
<Link href="/" className="my-auto ml-4 text-2xl font-semibold">
|
<Link href="/" className="my-auto ml-4 text-2xl font-semibold">
|
||||||
Ham Reserve
|
Ham Reserve
|
||||||
</Link>
|
</Link>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<label className="header-button swap swap-rotate">
|
{/* <label className="header-button swap-rotate swap">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={theme === THEME_DARK}
|
checked={theme === THEME_DARK}
|
||||||
@ -42,7 +41,7 @@ export function Header() {
|
|||||||
height={20}
|
height={20}
|
||||||
className="swap-on h-5 w-5"
|
className="swap-on h-5 w-5"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label> */}
|
||||||
<UserHeader />
|
<UserHeader />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -74,11 +73,12 @@ function UserHeader() {
|
|||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={`absolute right-2 top-full z-[1] pt-4 ${
|
className={`absolute right-2 top-full z-[1] pt-1 ${
|
||||||
isOpen ? '' : 'hidden'
|
isOpen ? '' : 'hidden'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<ul className="menu flex w-60 flex-col gap-1 rounded-xl bg-base-100 p-2 text-base-content shadow-md">
|
<div className="fixed inset-0" onClick={() => setIsOpen(false)} />
|
||||||
|
<ul className="menu flex w-60 flex-col gap-1 rounded-xl bg-base-100 p-2 text-base-content shadow-md dark:bg-base-200">
|
||||||
<li>
|
<li>
|
||||||
<Link href="/profile" onClick={() => setIsOpen(false)}>
|
<Link href="/profile" onClick={() => setIsOpen(false)}>
|
||||||
Profil
|
Profil
|
||||||
|
@ -13,5 +13,11 @@ export function ProgressBar({ start, end }: ProgressBarProps) {
|
|||||||
),
|
),
|
||||||
).toFixed(1);
|
).toFixed(1);
|
||||||
|
|
||||||
return <progress className="progress" value={progress} max={100} />;
|
return (
|
||||||
|
<progress
|
||||||
|
className="progress progress-primary"
|
||||||
|
value={progress}
|
||||||
|
max={100}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Reservation } from '@/interfaces/reservation.interface';
|
import { Reservation } from '@/interfaces/reservation.interface';
|
||||||
|
import { getUTCDateString } from '@/util/date.util';
|
||||||
import {
|
import {
|
||||||
faFileCircleCheck,
|
faFileCircleCheck,
|
||||||
faFileCircleExclamation,
|
faFileCircleExclamation,
|
||||||
@ -30,7 +31,7 @@ export function ReservationsTable({ reservations }: ReservationsTableProps) {
|
|||||||
<tbody>
|
<tbody>
|
||||||
{reservations.map((reservation) => (
|
{reservations.map((reservation) => (
|
||||||
<tr key={reservation._id}>
|
<tr key={reservation._id}>
|
||||||
<td>{reservation.forDate.toISOString().slice(0, 10)}</td>
|
<td>{getUTCDateString(reservation.forDate)}</td>
|
||||||
<td>
|
<td>
|
||||||
<div className="flex flex-wrap gap-1">
|
<div className="flex flex-wrap gap-1">
|
||||||
{reservation.bands.join(', ')}
|
{reservation.bands.join(', ')}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { apiFunctions } from '@/api';
|
import { apiFunctions } from '@/api';
|
||||||
import AsyncLock from 'async-lock';
|
import AsyncLock from 'async-lock';
|
||||||
|
import { AxiosError } from 'axios';
|
||||||
import jwtDecode from 'jwt-decode';
|
import jwtDecode from 'jwt-decode';
|
||||||
import secureLocalStorage from 'react-secure-storage';
|
import secureLocalStorage from 'react-secure-storage';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
@ -36,7 +37,6 @@ export const useAuthState = create(
|
|||||||
const { exp } = jwtDecode(accessToken) as { exp: number };
|
const { exp } = jwtDecode(accessToken) as { exp: number };
|
||||||
if (Date.now() < exp * 1000) {
|
if (Date.now() < exp * 1000) {
|
||||||
return true;
|
return true;
|
||||||
return;
|
|
||||||
} else set({ accessToken: null });
|
} else set({ accessToken: null });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,12 +48,12 @@ export const useAuthState = create(
|
|||||||
set(await apiFunctions.refresh(refreshToken));
|
set(await apiFunctions.refresh(refreshToken));
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
set({ refreshToken: null });
|
if (e instanceof AxiosError && e.response?.status === 401)
|
||||||
|
set({ refreshToken: null });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set({ refreshToken: null, accessToken: null });
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -1,16 +1,32 @@
|
|||||||
import { Event } from '@/interfaces/event.interface';
|
import { Event } from '@/interfaces/event.interface';
|
||||||
|
|
||||||
export function getUTCString(dt: Date) {
|
function pad(num: number) {
|
||||||
function pad(num: number) {
|
return num < 10 ? '0' + num : num;
|
||||||
return num < 10 ? '0' + num : num;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
export function getUTCDMString(dt: Date) {
|
||||||
|
const month = pad(dt.getUTCMonth() + 1);
|
||||||
|
const date = pad(dt.getUTCDate());
|
||||||
|
return `${date}. ${month}.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUTCDateString(dt: Date) {
|
||||||
const year = dt.getUTCFullYear();
|
const year = dt.getUTCFullYear();
|
||||||
const month = pad(dt.getUTCMonth() + 1);
|
const month = pad(dt.getUTCMonth() + 1);
|
||||||
const date = pad(dt.getUTCDate());
|
const date = pad(dt.getUTCDate());
|
||||||
|
return `${date}. ${month}. ${year}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUTCTimeString(dt: Date) {
|
||||||
const hour = pad(dt.getUTCHours());
|
const hour = pad(dt.getUTCHours());
|
||||||
const minute = pad(dt.getUTCMinutes());
|
const minute = pad(dt.getUTCMinutes());
|
||||||
return `${year}-${month}-${date} ${hour}:${minute} UTC`;
|
return `${hour}:${minute}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUTCString(dt: Date) {
|
||||||
|
const date = getUTCDateString(dt);
|
||||||
|
const time = getUTCTimeString(dt);
|
||||||
|
return `${date} ${time} UTC`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const dayInMs = 1000 * 60 * 60 * 24;
|
export const dayInMs = 1000 * 60 * 60 * 24;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user