Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import type { ReactNode } from "react";

import { getAuthStateServer } from "@/features/authentication/server";
import { fetchResources } from "@/features/backend";
import type { Resource } from "@/features/resources";
import type { ResourcePageProps } from "@/types/components";

import { HIDDEN_EVENT_QUERY_PARAMS } from "../constants";
import type {
CalendarDataMapper,
ResourceCalendarProps,
Expand All @@ -23,7 +25,14 @@ export async function AbstractResourceCalendar<T extends Resource>({
dataMapper: CalendarDataMapper<T>;
clickable: boolean;
}) {
const resourceData = await fetchResources(resource, true);
const authState = await getAuthStateServer();
const isSolvroAdmin =
authState?.user.roles.some((role) => role.slug === "solvro_admin") ?? false;
const resourceData = await fetchResources(
resource,
true,
isSolvroAdmin ? HIDDEN_EVENT_QUERY_PARAMS : undefined,
);
Comment thread
GTR1701 marked this conversation as resolved.
Comment thread
GTR1701 marked this conversation as resolved.
Comment thread
GTR1701 marked this conversation as resolved.

const mappedData = dataMapper(resourceData, clickable);
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import type {
ResourceDataType,
} from "@/features/resources/types";

import { ArcHideButtonWithDialog } from "./arc-hide-button-with-dialog";

export function EventCard({
event,
resource,
Expand Down Expand Up @@ -41,6 +43,13 @@ export function EventCard({
</header>
{clickable ? (
<footer className="flex items-center">
{event.googleCalId == null ? null : (
<ArcHideButtonWithDialog
resource={resource as EditableResource}
googleCalId={event.googleCalId}
hidden={event.hidden}
/>
)}
<EditButton resource={resource as EditableResource} id={event.id} />
<DeleteButtonWithDialog
resource={resource}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
"use client";

import { useQueryClient } from "@tanstack/react-query";
import type { VariantProps } from "class-variance-authority";
import { Eye, EyeOff } from "lucide-react";
import { useState } from "react";
import { toast } from "sonner";

import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import type { buttonVariants } from "@/components/ui/button/variants";
import { fetchMutation, getKey, useMutationWrapper } from "@/features/backend";
import type { MessageResponse } from "@/features/backend/types";
import { GrammaticalCase, declineNoun } from "@/features/polish";
import type { Resource } from "@/features/resources";
import { useRouter } from "@/hooks/use-router";
import { getToastMessages } from "@/lib/get-toast-messages";
import type { OptionalPromise } from "@/types/helpers";
import { quoteText } from "@/utils";

export function ArcHideButtonWithDialog({
resource,
googleCalId,
hidden,
itemName,
showLabel = false,
onHideSuccess,
...props
}: {
resource: Resource;
googleCalId: string;
hidden: boolean;
itemName?: string;
showLabel?: boolean;
onHideSuccess?: () => OptionalPromise<boolean>;
} & VariantProps<typeof buttonVariants>) {
const [isAlertDialogOpen, setIsAlertDialogOpen] = useState(false);
const router = useRouter();
const queryClient = useQueryClient();
const { mutateAsync, isPending } = useMutationWrapper<
MessageResponse,
string
>(getKey.mutation.hideResource(resource, googleCalId), async (calId) => {
const response = await fetchMutation<MessageResponse>(`hidden`, {
resource,
method: "POST",
body: { googleCalId: calId, hide: !hidden },
});
Comment thread
GTR1701 marked this conversation as resolved.
setIsAlertDialogOpen(false);
await queryClient.invalidateQueries({
queryKey: [getKey.query.resourceList(resource)],
exact: false,
});
if ((await onHideSuccess?.()) !== false) {
router.refresh();
}
return response;
});

function handleHide() {
toast.promise(
mutateAsync(googleCalId),
getToastMessages.resource(resource).modify,
Comment thread
GTR1701 marked this conversation as resolved.
);
}

const declensions = declineNoun(resource);
const label = hidden
? `Pokaż ${declensions.accusative}`
: `Ukryj ${declensions.accusative}`;

return (
<AlertDialog open={isAlertDialogOpen} onOpenChange={setIsAlertDialogOpen}>
<AlertDialogTrigger asChild>
<Button
variant="icon"
size={showLabel ? "sm" : "icon"}
aria-label={label}
tooltip={showLabel ? undefined : label}
{...props}
>
{showLabel ? label : null}
{hidden ? <Eye /> : <EyeOff />}
</Button>
</AlertDialogTrigger>
<AlertDialogContent
onCloseAutoFocus={(event) => {
event.preventDefault();
}}
>
Comment thread
GTR1701 marked this conversation as resolved.
Comment thread
GTR1701 marked this conversation as resolved.
Comment thread
GTR1701 marked this conversation as resolved.
<AlertDialogHeader>
<AlertDialogTitle className="text-balance">
{hidden
? "Czy na pewno chcesz pokazać"
: "Czy na pewno chcesz ukryć"}{" "}
{
itemName == null
? declineNoun(resource, {
case: GrammaticalCase.Accusative,
prependDeterminer: "this",
}) // e.g. tę organizację studencką
: `${declensions.accusative} ${quoteText(itemName)}` // e.g. organizację studencką „KN Solvro”
}
?
</AlertDialogTitle>
<AlertDialogDescription>
{hidden
? "Wydarzenie zostanie ponownie wyświetlone w kalendarzu."
: "Wydarzenie zostanie ukryte w kalendarzu."}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Anuluj</AlertDialogCancel>
<AlertDialogAction asChild>
<Button
variant={hidden ? "default" : "destructive"}
onClick={handleHide}
loading={isPending}
>
{hidden ? (
<>
<Eye />
Pokaż
</>
) : (
<>
<EyeOff />
Ukryj
</>
)}
</Button>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}
4 changes: 4 additions & 0 deletions src/features/abstract-resource-calendar/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
export const CALENDAR_MAX_EVENTS_PER_DAY = 5;

export const WEEKDAYS = ["Pn", "Wt", "Śr", "Cz", "Pt", "So", "Nd"];

export const HIDDEN_EVENT_QUERY_PARAMS: Record<string, string> = {
showHidden: "true",
};
14 changes: 10 additions & 4 deletions src/features/backend/api/fetch-resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,18 @@ export async function fetchResources<
>(
resource: T,
includeRelations: B = false as B,
queryParameters?: Record<string, string>,
): Promise<
B extends true ? ResourceDataWithRelations<T>[] : ResourceDataType<T>[]
> {
const result = await fetchQuery<GetResourcesWithRelationsResponse<T>>("", {
resource,
includeRelations,
});
const queryString = new URLSearchParams(queryParameters ?? {}).toString();
const endpointSuffix = queryString ? `?${queryString}` : "";
const result = await fetchQuery<GetResourcesWithRelationsResponse<T>>(
endpointSuffix,
{
resource,
includeRelations,
},
);
Comment thread
GTR1701 marked this conversation as resolved.
return result.data;
}
2 changes: 2 additions & 0 deletions src/features/backend/utils/get-key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ export const getKey = {
mutation: {
deleteResource: (resource: Resource, id: ResourcePk) =>
`delete__${resource}__${sanitizeId(id)}`,
hideResource: (resource: Resource, id: ResourcePk) =>
`hide__${resource}__${sanitizeId(id)}`,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,11 @@ export function DeleteButtonWithDialog({
<Trash2 />
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogContent
onCloseAutoFocus={(event) => {
event.preventDefault();
}}
>
Comment thread
GTR1701 marked this conversation as resolved.
Comment thread
GTR1701 marked this conversation as resolved.
Comment thread
GTR1701 marked this conversation as resolved.
<AlertDialogHeader>
<AlertDialogTitle className="text-balance">
Czy na pewno chcesz usunąć{" "}
Expand Down
1 change: 1 addition & 0 deletions src/features/resources/data/resource-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ export const RESOURCE_METADATA = {
startTime: getRoundedDate(0),
endTime: getRoundedDate(24),
accentColor: null,
hidden: false,
},
},
},
Expand Down
4 changes: 4 additions & 0 deletions src/features/resources/schemas/calendar-event-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ export const CalendarEventSchema = z.object({
location: z.string().nullish(),
googleCalId: z.string().nullish(),
accentColor: ColorValueSchema.nullish(),
hidden: z
.boolean()
.nullish()
.transform((value) => value ?? false),
});
Loading