Support missing roles and deleted user

This commit is contained in:
2025-04-01 23:26:56 +02:00
parent fc302d8ef2
commit 3694492e1a
10 changed files with 88 additions and 47 deletions

View File

@@ -9,9 +9,9 @@ export interface User {
}
export interface SystemInformation {
readonly createdBy: Option.Option<User>;
readonly createdBy: Option.Option<User | null>;
readonly createdAt: string;
readonly modifiedBy: Option.Option<User>;
readonly modifiedBy: Option.Option<User | null>;
readonly modifiedAt: Option.Option<string>;
}
@@ -113,7 +113,8 @@ const RepertoireSemaphore = Effect.unsafeMakeSemaphore(1);
export const userLookup = (userId: UserId) => pipe(
Effect.promise((signal) => client.user({ userId }).get({ fetch: { signal } })),
Effect.flatMap(mapResponse),
Effect.map((x): User => x), // safely coerce to interface
Effect.catchAll((error) => error.status === 404 ? Effect.succeed(null) : Effect.fail(error)),
Effect.map((x): User | null => x), // safely coerce to interface
UserSemaphore.withPermits(1),
);

View File

@@ -1,6 +1,7 @@
import { client } from "@/client";
import { useLoading } from "@/hooks/useLoading.ts";
import { AttachmentId, PieceId } from "common";
import { Match } from "effect";
import JSZip from "jszip";
import { OpenSheetMusicDisplay } from "opensheetmusicdisplay";
import { useCallback, useEffect, useRef } from "react";
@@ -102,7 +103,13 @@ export default function Attachment() {
if (error !== null) {
return (
<div className="w-full h-full overflow-hidden flex items-center justify-center">
<div>Wystąpił błąd: {error.status === 422 ? error.value.message : error.value}</div>
<div>
Wystąpił błąd: {Match.value(error).pipe(
Match.when({ status: 422 }, ({ value }) => value.message),
Match.when({ status: 404 }, () => "Załącznik nie istnieje"),
Match.exhaustive,
)}
</div>
</div>
);
}

View File

@@ -38,7 +38,7 @@ export function Piece() {
return (
<div className="p-4 overflow-y-auto flex flex-wrap items-start gap-4">
{error !== null ? (
Cause.isUnknownException(error) ? "Wystąpił nieznany błąd" : `Wystąpił błąd: ${error.value}`
Cause.isUnknownException(error) ? "Wystąpił nieznany błąd" : `Wystąpił błąd: ${JSON.stringify(error.value)}`
) : (<>
<div className="flex flex-col gap-4 p-4 border rounded">
<h3 className="font-bold text-lg">Utwór</h3>

View File

@@ -8,7 +8,7 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@
import { useLoadingEffect } from "@/hooks/useLoading";
import { authors, created, DEBOUNCE, modified } from "@/snippets";
import { PieceId } from "common";
import { Cause, Effect } from "effect";
import { Cause, Effect, Match } from "effect";
import { Loader2, Plus } from "lucide-react";
import { FormEventHandler, useId, useRef, useState } from "react";
import { Link, useNavigate } from "react-router-dom";
@@ -91,7 +91,7 @@ export function Pieces() {
) : error !== null ? (
<TableRow>
<TableCell colSpan={4} className="text-center">
{Cause.isUnknownException(error) ? "Wystąpił nieznany błąd" : `Wystąpił błąd: ${error.value}`}
{Cause.isUnknownException(error) ? "Wystąpił nieznany błąd" : `Wystąpił błąd: ${JSON.stringify(error.value)}`}
</TableCell>
</TableRow>
) : (
@@ -124,7 +124,14 @@ function PieceRow(props: PieceRow.Props) {
if (error !== null) {
return (
<TableRow>
<TableCell colSpan={4}>Wystąpił błąd: {error.status === 422 ? error.value.message : error.value}</TableCell>
<TableCell colSpan={4}>
Wystąpił błąd: {Match.value(error).pipe(
Match.when({ status: 401 }, () => "Zaloguj się ponownie"),
Match.when({ status: 422 }, ({ value }) => value.message),
Match.when({ status: 404 }, () => "Utwór nie istnieje"),
Match.exhaustive,
)}
</TableCell>
</TableRow>
);
}

View File

@@ -9,7 +9,7 @@ import { useLoadingEffect } from "@/hooks/useLoading";
import { mapProp, Update, Updater } from "@/hooks/useStore";
import { authors, DEBOUNCE, saveDelay } from "@/snippets";
import { PieceId, RepertoireId } from "common";
import { Array, Cause, Effect, Option, pipe } from "effect";
import { Array, Cause, Effect, Match, Option, pipe } from "effect";
import { ChevronDown, ChevronUp, CircleMinus, Loader2, Plus } from "lucide-react";
import { FormEventHandler, useCallback, useId, useMemo, useRef, useState } from "react";
import { Link, useNavigate, useParams } from "react-router-dom";
@@ -36,7 +36,7 @@ export function Repertoire() {
return (
<div className="p-4 overflow-y-auto flex flex-wrap items-start gap-4">
{error !== null ? (
Cause.isUnknownException(error) ? "Wystąpił nieznany błąd" : `Wystąpił błąd: ${error.value}`
Cause.isUnknownException(error) ? "Wystąpił nieznany błąd" : `Wystąpił błąd: ${JSON.stringify(error.value)}`
) : (<>
<div className="flex flex-col gap-4 p-4 border rounded">
<h3 className="font-bold">Repertuar</h3>
@@ -343,7 +343,7 @@ function AddEntryDialogContent(props: AddEntryDialogContent.Props) {
) : error !== null ? (
<TableRow>
<TableCell colSpan={4} className="text-center">
{Cause.isUnknownException(error) ? "Wystąpił nieznany błąd" : `Wystąpił błąd: ${error.value}`}
{Cause.isUnknownException(error) ? "Wystąpił nieznany błąd" : `Wystąpił błąd: ${JSON.stringify(error.value)}`}
</TableCell>
</TableRow>
) : (
@@ -410,7 +410,14 @@ function EntryDialogPieceRow(props: EntryDialogPieceRow.Props) {
if (error !== null) {
return (
<TableRow>
<TableCell colSpan={2}>Wystąpił błąd: {error.status === 422 ? error.value.message : error.value}</TableCell>
<TableCell colSpan={2}>
Wystąpił błąd: {Match.value(error).pipe(
Match.when({ status: 401 }, () => "Zaloguj się ponownie"),
Match.when({ status: 422 }, ({ value }) => value.message),
Match.when({ status: 404 }, () => "Utwór nie istnieje"),
Match.exhaustive,
)}
</TableCell>
</TableRow>
);
}

View File

@@ -8,7 +8,7 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@
import { useLoadingEffect } from "@/hooks/useLoading";
import { created, DEBOUNCE, modified } from "@/snippets";
import { RepertoireId } from "common";
import { Cause, Effect } from "effect";
import { Cause, Effect, Match } from "effect";
import { Loader2, Plus } from "lucide-react";
import { FormEventHandler, ReactNode, useId, useRef, useState } from "react";
import { Link, useNavigate } from "react-router-dom";
@@ -79,7 +79,7 @@ export function Repertoires() {
) : error !== null ? (
<TableRow>
<TableCell colSpan={4} className="text-center">
{Cause.isUnknownException(error) ? "Wystąpił nieznany błąd" : `Wystąpił błąd: ${error.value}`}
{Cause.isUnknownException(error) ? "Wystąpił nieznany błąd" : `Wystąpił błąd: ${JSON.stringify(error.value)}`}
</TableCell>
</TableRow>
) : (
@@ -112,7 +112,14 @@ function RepertoireRow(props: RepertoireRow.Props) {
if (error !== null) {
return (
<TableRow>
<TableCell colSpan={4}>Wystąpił błąd: {error.status === 422 ? error.value.message : error.value}</TableCell>
<TableCell colSpan={4}>
Wystąpił błąd: {Match.value(error).pipe(
Match.when({ status: 401 }, () => "Zaloguj się ponownie"),
Match.when({ status: 422 }, ({ value }) => value.message),
Match.when({ status: 404 }, () => "Repertuar nie istnieje"),
Match.exhaustive,
)}
</TableCell>
</TableRow>
);
}

View File

@@ -36,7 +36,11 @@ export function created({ createdAt, createdBy }: SystemInformation): ReactNode
if (Option.isSome(createdBy)) {
nodes.push(<br />);
nodes.push(`przez ${createdBy.value.displayName}`);
if (createdBy.value !== null) {
nodes.push(`przez ${createdBy.value.displayName}`);
} else {
nodes.push("przez nieznanego użytkownika");
}
}
return nodes;
@@ -48,7 +52,11 @@ export function modified({ modifiedAt, modifiedBy }: SystemInformation): ReactNo
if (Option.isNone(modifiedBy)) {
return "\u2014";
} else {
return `przez ${modifiedBy.value.displayName}`;
if (modifiedBy.value !== null) {
return `przez ${modifiedBy.value.displayName}`;
} else {
return "przez nieznanego użytkownika";
}
}
}
@@ -56,7 +64,11 @@ export function modified({ modifiedAt, modifiedBy }: SystemInformation): ReactNo
if (Option.isSome(modifiedBy)) {
nodes.push(<br />);
nodes.push(`przez ${modifiedBy.value.displayName}`);
if (modifiedBy.value !== null) {
nodes.push(`przez ${modifiedBy.value.displayName}`);
} else {
nodes.push("przez nieznanego użytkownika");
}
}
return nodes;