mirror of
https://github.com/hex248/sprint.git
synced 2026-02-07 18:23:03 +00:00
use parseError
This commit is contained in:
@@ -7,7 +7,7 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from
|
||||
import { Field } from "@/components/ui/field";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { UploadAvatar } from "@/components/upload-avatar";
|
||||
import { user } from "@/lib/server";
|
||||
import { parseError, user } from "@/lib/server";
|
||||
|
||||
function AccountDialog({ trigger }: { trigger?: ReactNode }) {
|
||||
const { user: currentUser, setUser } = useAuthenticatedSession();
|
||||
@@ -41,9 +41,8 @@ function AccountDialog({ trigger }: { trigger?: ReactNode }) {
|
||||
}
|
||||
|
||||
await user.update({
|
||||
id: currentUser.id,
|
||||
name: name.trim(),
|
||||
password: password.trim(),
|
||||
password: password.trim() || undefined,
|
||||
avatarURL,
|
||||
onSuccess: (data) => {
|
||||
setError("");
|
||||
@@ -55,10 +54,11 @@ function AccountDialog({ trigger }: { trigger?: ReactNode }) {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
onError: (error) => {
|
||||
setError(error);
|
||||
onError: (err) => {
|
||||
const message = parseError(err);
|
||||
setError(message);
|
||||
|
||||
toast.error(`Error updating account: ${error}`, {
|
||||
toast.error(`Error updating account: ${message}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Field } from "@/components/ui/field";
|
||||
import { organisation, user } from "@/lib/server";
|
||||
import { organisation, parseError, user } from "@/lib/server";
|
||||
|
||||
export function AddMemberDialog({
|
||||
organisationId,
|
||||
@@ -68,11 +68,12 @@ export function AddMemberDialog({
|
||||
userData = data;
|
||||
userId = data.id;
|
||||
},
|
||||
onError: (error) => {
|
||||
setError(error || "user not found");
|
||||
onError: (err) => {
|
||||
const message = parseError(err);
|
||||
setError(message || "user not found");
|
||||
setSubmitting(false);
|
||||
|
||||
toast.error(`Error adding member: ${error}`, {
|
||||
toast.error(`Error adding member: ${message}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
@@ -95,11 +96,12 @@ export function AddMemberDialog({
|
||||
console.error(actionErr);
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
setError(error || "failed to add member");
|
||||
onError: (err) => {
|
||||
const message = parseError(err);
|
||||
setError(message || "failed to add member");
|
||||
setSubmitting(false);
|
||||
|
||||
toast.error(`Error adding member: ${error}`, {
|
||||
toast.error(`Error adding member: ${message}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
|
||||
@@ -23,7 +23,7 @@ import { Field } from "@/components/ui/field";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { SelectTrigger } from "@/components/ui/select";
|
||||
import { UserSelect } from "@/components/user-select";
|
||||
import { issue } from "@/lib/server";
|
||||
import { issue, parseError } from "@/lib/server";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { SprintSelect } from "./sprint-select";
|
||||
|
||||
@@ -116,16 +116,17 @@ export function CreateIssue({
|
||||
console.error(actionErr);
|
||||
}
|
||||
},
|
||||
onError: async (error) => {
|
||||
setError(error);
|
||||
onError: async (err) => {
|
||||
const message = parseError(err);
|
||||
setError(message);
|
||||
setSubmitting(false);
|
||||
|
||||
toast.error(`Error creating issue: ${error}`, {
|
||||
toast.error(`Error creating issue: ${message}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
|
||||
try {
|
||||
await errorAction?.(error);
|
||||
await errorAction?.(message);
|
||||
} catch (actionErr) {
|
||||
console.error(actionErr);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
} from "@/components/ui/dialog";
|
||||
import { Field } from "@/components/ui/field";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { organisation } from "@/lib/server";
|
||||
import { organisation, parseError } from "@/lib/server";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const slugify = (value: string) =>
|
||||
@@ -85,7 +85,6 @@ export function CreateOrganisation({
|
||||
name,
|
||||
slug,
|
||||
description,
|
||||
userId: user.id,
|
||||
onSuccess: async (data) => {
|
||||
setOpen(false);
|
||||
reset();
|
||||
@@ -96,10 +95,11 @@ export function CreateOrganisation({
|
||||
}
|
||||
},
|
||||
onError: async (err) => {
|
||||
setError(err || "failed to create organisation");
|
||||
const message = parseError(err);
|
||||
setError(message || "failed to create organisation");
|
||||
setSubmitting(false);
|
||||
try {
|
||||
await errorAction?.(err || "failed to create organisation");
|
||||
await errorAction?.(message || "failed to create organisation");
|
||||
} catch (actionErr) {
|
||||
console.error(actionErr);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
} from "@/components/ui/dialog";
|
||||
import { Field } from "@/components/ui/field";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { project } from "@/lib/server";
|
||||
import { parseError, project } from "@/lib/server";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const keyify = (value: string) =>
|
||||
@@ -86,24 +86,24 @@ export function CreateProject({
|
||||
await project.create({
|
||||
key,
|
||||
name,
|
||||
creatorId: user.id,
|
||||
organisationId,
|
||||
onSuccess: async (data) => {
|
||||
const project = data as ProjectRecord;
|
||||
const proj = data as ProjectRecord;
|
||||
|
||||
setOpen(false);
|
||||
reset();
|
||||
try {
|
||||
await completeAction?.(project);
|
||||
await completeAction?.(proj);
|
||||
} catch (actionErr) {
|
||||
console.error(actionErr);
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
setError(error);
|
||||
onError: (err) => {
|
||||
const message = parseError(err);
|
||||
setError(message);
|
||||
setSubmitting(false);
|
||||
|
||||
toast.error(`Error creating project: ${error}`, {
|
||||
toast.error(`Error creating project: ${message}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
import { Field } from "@/components/ui/field";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||
import { sprint } from "@/lib/server";
|
||||
import { parseError, sprint } from "@/lib/server";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const SPRINT_NAME_MAX_LENGTH = 64;
|
||||
@@ -135,11 +135,12 @@ export function CreateSprint({
|
||||
console.error(actionErr);
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
setError(error);
|
||||
onError: (err) => {
|
||||
const message = parseError(err);
|
||||
setError(message);
|
||||
setSubmitting(false);
|
||||
|
||||
toast.error(`Error creating sprint: ${error}`, {
|
||||
toast.error(`Error creating sprint: ${message}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { TimerState } from "@issue/shared";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { timer } from "@/lib/server";
|
||||
import { parseError, timer } from "@/lib/server";
|
||||
import { cn, formatTime } from "@/lib/utils";
|
||||
|
||||
export function IssueTimer({ issueId, onEnd }: { issueId: number; onEnd?: (data: TimerState) => void }) {
|
||||
@@ -19,7 +19,7 @@ export function IssueTimer({ issueId, onEnd }: { issueId: number; onEnd?: (data:
|
||||
setDisplayTime(data.workTimeMs);
|
||||
}
|
||||
},
|
||||
onError: setError,
|
||||
onError: (err) => setError(parseError(err)),
|
||||
});
|
||||
}, [issueId]);
|
||||
|
||||
@@ -41,11 +41,13 @@ export function IssueTimer({ issueId, onEnd }: { issueId: number; onEnd?: (data:
|
||||
timer.toggle({
|
||||
issueId,
|
||||
onSuccess: (data) => {
|
||||
setTimerState(data);
|
||||
setDisplayTime(data.workTimeMs);
|
||||
if (data) {
|
||||
setTimerState(data);
|
||||
setDisplayTime(data.workTimeMs);
|
||||
}
|
||||
setError(null);
|
||||
},
|
||||
onError: setError,
|
||||
onError: (err) => setError(parseError(err)),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -53,12 +55,14 @@ export function IssueTimer({ issueId, onEnd }: { issueId: number; onEnd?: (data:
|
||||
timer.end({
|
||||
issueId,
|
||||
onSuccess: (data) => {
|
||||
setTimerState(data);
|
||||
setDisplayTime(data.workTimeMs);
|
||||
if (data) {
|
||||
setTimerState(data);
|
||||
setDisplayTime(data.workTimeMs);
|
||||
onEnd?.(data);
|
||||
}
|
||||
setError(null);
|
||||
onEnd?.(data);
|
||||
},
|
||||
onError: setError,
|
||||
onError: (err) => setError(parseError(err)),
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { TimerState } from "@issue/shared";
|
||||
import { useEffect, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { timer } from "@/lib/server";
|
||||
import { parseError, timer } from "@/lib/server";
|
||||
import { formatTime } from "@/lib/utils";
|
||||
|
||||
const FALLBACK_TIME = "--:--:--";
|
||||
@@ -25,11 +25,12 @@ export function TimerDisplay({ issueId }: { issueId: number }) {
|
||||
setWorkTimeMs(data?.workTimeMs ?? 0);
|
||||
setError(null);
|
||||
},
|
||||
onError: (error) => {
|
||||
onError: (err) => {
|
||||
if (!isMounted) return;
|
||||
setError(error);
|
||||
const message = parseError(err);
|
||||
setError(message);
|
||||
|
||||
toast.error(`Error fetching timer data: ${error}`, {
|
||||
toast.error(`Error fetching timer data: ${message}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
@@ -39,19 +40,19 @@ export function TimerDisplay({ issueId }: { issueId: number }) {
|
||||
issueId,
|
||||
onSuccess: (data) => {
|
||||
if (!isMounted) return;
|
||||
const sessions = (data ?? []) as TimerState[];
|
||||
const totalWorkTime = sessions.reduce(
|
||||
const totalWorkTime = data.reduce(
|
||||
(total, session) => total + (session?.workTimeMs ?? 0),
|
||||
0,
|
||||
);
|
||||
setInactiveWorkTimeMs(totalWorkTime);
|
||||
setError(null);
|
||||
},
|
||||
onError: (error) => {
|
||||
onError: (err) => {
|
||||
if (!isMounted) return;
|
||||
setError(error);
|
||||
const message = parseError(err);
|
||||
setError(message);
|
||||
|
||||
toast.error(`Error fetching timer data: ${error}`, {
|
||||
toast.error(`Error fetching timer data: ${message}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@ import { toast } from "sonner";
|
||||
import Avatar from "@/components/avatar";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { user } from "@/lib/server";
|
||||
import { parseError, user } from "@/lib/server";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export function UploadAvatar({
|
||||
@@ -49,11 +49,12 @@ export function UploadAvatar({
|
||||
},
|
||||
);
|
||||
},
|
||||
onError: (error) => {
|
||||
setError(error);
|
||||
onError: (err) => {
|
||||
const message = parseError(err);
|
||||
setError(message);
|
||||
setUploading(false);
|
||||
|
||||
toast.error(`Error uploading avatar: ${error}`, {
|
||||
toast.error(`Error uploading avatar: ${message}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import type {
|
||||
IssueResponse,
|
||||
OrganisationMemberResponse,
|
||||
OrganisationResponse,
|
||||
ProjectRecord,
|
||||
ProjectResponse,
|
||||
@@ -107,25 +106,21 @@ export default function App() {
|
||||
const refetchOrganisations = async (options?: { selectOrganisationId?: number }) => {
|
||||
try {
|
||||
await organisation.byUser({
|
||||
userId: user.id,
|
||||
onSuccess: (data) => {
|
||||
const organisations = data as OrganisationResponse[];
|
||||
organisations.sort((a, b) => a.Organisation.name.localeCompare(b.Organisation.name));
|
||||
setOrganisations(organisations);
|
||||
data.sort((a, b) => a.Organisation.name.localeCompare(b.Organisation.name));
|
||||
setOrganisations(data);
|
||||
|
||||
let selected: OrganisationResponse | null = null;
|
||||
|
||||
if (options?.selectOrganisationId) {
|
||||
const created = organisations.find(
|
||||
(o) => o.Organisation.id === options.selectOrganisationId,
|
||||
);
|
||||
const created = data.find((o) => o.Organisation.id === options.selectOrganisationId);
|
||||
if (created) {
|
||||
selected = created;
|
||||
}
|
||||
} else {
|
||||
const deepLinkState = deepLinkStateRef.current;
|
||||
if (deepLinkParams.orgSlug && !deepLinkState.appliedOrg) {
|
||||
const match = organisations.find(
|
||||
const match = data.find(
|
||||
(org) => org.Organisation.slug.toLowerCase() === deepLinkParams.orgSlug,
|
||||
);
|
||||
deepLinkState.appliedOrg = true;
|
||||
@@ -139,9 +134,7 @@ export default function App() {
|
||||
if (!selected) {
|
||||
const savedId = localStorage.getItem("selectedOrganisationId");
|
||||
if (savedId) {
|
||||
const saved = organisations.find(
|
||||
(o) => o.Organisation.id === Number(savedId),
|
||||
);
|
||||
const saved = data.find((o) => o.Organisation.id === Number(savedId));
|
||||
if (saved) {
|
||||
selected = saved;
|
||||
}
|
||||
@@ -150,7 +143,7 @@ export default function App() {
|
||||
}
|
||||
|
||||
if (!selected) {
|
||||
selected = organisations[0] || null;
|
||||
selected = data[0] || null;
|
||||
}
|
||||
|
||||
setSelectedOrganisation(selected);
|
||||
@@ -260,7 +253,7 @@ export default function App() {
|
||||
try {
|
||||
await organisation.members({
|
||||
organisationId,
|
||||
onSuccess: (data: OrganisationMemberResponse[]) => {
|
||||
onSuccess: (data) => {
|
||||
setMembers(data.map((m) => m.User));
|
||||
},
|
||||
onError: (error) => {
|
||||
@@ -282,7 +275,7 @@ export default function App() {
|
||||
try {
|
||||
await sprint.byProject({
|
||||
projectId,
|
||||
onSuccess: (data: SprintRecord[]) => {
|
||||
onSuccess: (data) => {
|
||||
setSprints(data);
|
||||
},
|
||||
onError: (error) => {
|
||||
|
||||
Reference in New Issue
Block a user