mirror of
https://github.com/hex248/sprint.git
synced 2026-02-08 02:33:01 +00:00
use ServerQueryInput properly
This commit is contained in:
@@ -1,50 +1,35 @@
|
|||||||
|
import type { IssueCreateRequest, IssueRecord } from "@issue/shared";
|
||||||
|
import { toast } from "sonner";
|
||||||
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
||||||
import type { ServerQueryInput } from "..";
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
export async function create({
|
export async function create(request: IssueCreateRequest & ServerQueryInput<IssueRecord>) {
|
||||||
projectId,
|
const { onSuccess, onError, ...body } = request;
|
||||||
title,
|
|
||||||
description,
|
|
||||||
sprintId,
|
|
||||||
assigneeId,
|
|
||||||
status,
|
|
||||||
onSuccess,
|
|
||||||
onError,
|
|
||||||
}: {
|
|
||||||
projectId: number;
|
|
||||||
title: string;
|
|
||||||
description: string;
|
|
||||||
sprintId?: number | null;
|
|
||||||
assigneeId?: number | null;
|
|
||||||
status?: string;
|
|
||||||
} & ServerQueryInput) {
|
|
||||||
const url = new URL(`${getServerURL()}/issue/create`);
|
|
||||||
url.searchParams.set("projectId", `${projectId}`);
|
|
||||||
url.searchParams.set("title", title.trim());
|
|
||||||
if (description.trim() !== "") url.searchParams.set("description", description.trim());
|
|
||||||
if (sprintId != null) url.searchParams.set("sprintId", `${sprintId}`);
|
|
||||||
if (assigneeId != null) url.searchParams.set("assigneeId", `${assigneeId}`);
|
|
||||||
if (status != null && status.trim() !== "") url.searchParams.set("status", status.trim());
|
|
||||||
|
|
||||||
const csrfToken = getCsrfToken();
|
const csrfToken = getCsrfToken();
|
||||||
const headers: HeadersInit = {};
|
|
||||||
if (csrfToken) headers["X-CSRF-Token"] = csrfToken;
|
|
||||||
|
|
||||||
const res = await fetch(url.toString(), {
|
const res = await fetch(`${getServerURL()}/issue/create`, {
|
||||||
headers,
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(csrfToken ? { "X-CSRF-Token": csrfToken } : {}),
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await res.text();
|
const error = await res.json().catch(() => res.text());
|
||||||
onError?.(error || `failed to create issue (${res.status})`);
|
const message =
|
||||||
|
typeof error === "string" ? error : error.error || `failed to create issue (${res.status})`;
|
||||||
|
toast.error(message);
|
||||||
|
onError?.(error);
|
||||||
} else {
|
} else {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (!data.id) {
|
if (!data.id) {
|
||||||
|
toast.error(`failed to create issue (${res.status})`);
|
||||||
onError?.(`failed to create issue (${res.status})`);
|
onError?.(`failed to create issue (${res.status})`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
onSuccess?.(data, res);
|
onSuccess?.(data, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import type { SuccessResponse } from "@issue/shared";
|
||||||
|
import { toast } from "sonner";
|
||||||
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
||||||
import type { ServerQueryInput } from "..";
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
@@ -7,24 +9,27 @@ export async function remove({
|
|||||||
onError,
|
onError,
|
||||||
}: {
|
}: {
|
||||||
issueId: number;
|
issueId: number;
|
||||||
} & ServerQueryInput) {
|
} & ServerQueryInput<SuccessResponse>) {
|
||||||
const url = new URL(`${getServerURL()}/issue/delete`);
|
|
||||||
url.searchParams.set("id", `${issueId}`);
|
|
||||||
|
|
||||||
const csrfToken = getCsrfToken();
|
const csrfToken = getCsrfToken();
|
||||||
const headers: HeadersInit = {};
|
|
||||||
if (csrfToken) headers["X-CSRF-Token"] = csrfToken;
|
|
||||||
|
|
||||||
const res = await fetch(url.toString(), {
|
const res = await fetch(`${getServerURL()}/issue/delete`, {
|
||||||
headers,
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(csrfToken ? { "X-CSRF-Token": csrfToken } : {}),
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ id: issueId }),
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await res.text();
|
const error = await res.json().catch(() => res.text());
|
||||||
onError?.(error || `failed to delete issue (${res.status})`);
|
const message =
|
||||||
|
typeof error === "string" ? error : error.error || `failed to delete issue (${res.status})`;
|
||||||
|
toast.error(message);
|
||||||
|
onError?.(error);
|
||||||
} else {
|
} else {
|
||||||
const data = await res.text();
|
const data = await res.json();
|
||||||
onSuccess?.(data, res);
|
onSuccess?.(data, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,30 @@
|
|||||||
|
import type { IssuesReplaceStatusRequest, ReplaceStatusResponse } from "@issue/shared";
|
||||||
|
import { toast } from "sonner";
|
||||||
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
||||||
import type { ServerQueryInput } from "..";
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
export async function replaceStatus({
|
export async function replaceStatus(
|
||||||
organisationId,
|
request: IssuesReplaceStatusRequest & ServerQueryInput<ReplaceStatusResponse>,
|
||||||
oldStatus,
|
) {
|
||||||
newStatus,
|
const { onSuccess, onError, ...body } = request;
|
||||||
onSuccess,
|
|
||||||
onError,
|
|
||||||
}: {
|
|
||||||
organisationId: number;
|
|
||||||
oldStatus: string;
|
|
||||||
newStatus: string;
|
|
||||||
} & ServerQueryInput) {
|
|
||||||
const url = new URL(`${getServerURL()}/issues/replace-status`);
|
|
||||||
url.searchParams.set("organisationId", `${organisationId}`);
|
|
||||||
url.searchParams.set("oldStatus", oldStatus);
|
|
||||||
url.searchParams.set("newStatus", newStatus);
|
|
||||||
|
|
||||||
const csrfToken = getCsrfToken();
|
const csrfToken = getCsrfToken();
|
||||||
const headers: HeadersInit = {};
|
|
||||||
if (csrfToken) headers["X-CSRF-Token"] = csrfToken;
|
|
||||||
|
|
||||||
const res = await fetch(url.toString(), {
|
const res = await fetch(`${getServerURL()}/issues/replace-status`, {
|
||||||
headers,
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(csrfToken ? { "X-CSRF-Token": csrfToken } : {}),
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await res.text();
|
const error = await res.json().catch(() => res.text());
|
||||||
onError?.(error || `failed to replace status (${res.status})`);
|
const message =
|
||||||
|
typeof error === "string" ? error : error.error || `failed to replace status (${res.status})`;
|
||||||
|
toast.error(message);
|
||||||
|
onError?.(error);
|
||||||
} else {
|
} else {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
onSuccess?.(data, res);
|
onSuccess?.(data, res);
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import type { IssueRecord } from "@issue/shared";
|
||||||
|
import { toast } from "sonner";
|
||||||
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
||||||
import type { ServerQueryInput } from "..";
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
@@ -17,31 +19,32 @@ export async function update({
|
|||||||
sprintId?: number | null;
|
sprintId?: number | null;
|
||||||
assigneeId?: number | null;
|
assigneeId?: number | null;
|
||||||
status?: string;
|
status?: string;
|
||||||
} & ServerQueryInput) {
|
} & ServerQueryInput<IssueRecord>) {
|
||||||
const url = new URL(`${getServerURL()}/issue/update`);
|
|
||||||
url.searchParams.set("id", `${issueId}`);
|
|
||||||
if (title !== undefined) url.searchParams.set("title", title);
|
|
||||||
if (description !== undefined) url.searchParams.set("description", description);
|
|
||||||
if (sprintId !== undefined) {
|
|
||||||
url.searchParams.set("sprintId", sprintId === null ? "null" : `${sprintId}`);
|
|
||||||
}
|
|
||||||
if (assigneeId !== undefined) {
|
|
||||||
url.searchParams.set("assigneeId", assigneeId === null ? "null" : `${assigneeId}`);
|
|
||||||
}
|
|
||||||
if (status !== undefined) url.searchParams.set("status", status);
|
|
||||||
|
|
||||||
const csrfToken = getCsrfToken();
|
const csrfToken = getCsrfToken();
|
||||||
const headers: HeadersInit = {};
|
|
||||||
if (csrfToken) headers["X-CSRF-Token"] = csrfToken;
|
|
||||||
|
|
||||||
const res = await fetch(url.toString(), {
|
const res = await fetch(`${getServerURL()}/issue/update`, {
|
||||||
headers,
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(csrfToken ? { "X-CSRF-Token": csrfToken } : {}),
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
id: issueId,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
sprintId,
|
||||||
|
assigneeId,
|
||||||
|
status,
|
||||||
|
}),
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await res.text();
|
const error = await res.json().catch(() => res.text());
|
||||||
onError?.(error || `failed to update issue (${res.status})`);
|
const message =
|
||||||
|
typeof error === "string" ? error : error.error || `failed to update issue (${res.status})`;
|
||||||
|
toast.error(message);
|
||||||
|
onError?.(error);
|
||||||
} else {
|
} else {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
onSuccess?.(data, res);
|
onSuccess?.(data, res);
|
||||||
|
|||||||
@@ -1,35 +1,28 @@
|
|||||||
|
import type { OrgAddMemberRequest, OrganisationMemberRecord } from "@issue/shared";
|
||||||
|
import { toast } from "sonner";
|
||||||
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
||||||
import type { ServerQueryInput } from "..";
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
export async function addMember({
|
export async function addMember(request: OrgAddMemberRequest & ServerQueryInput<OrganisationMemberRecord>) {
|
||||||
organisationId,
|
const { onSuccess, onError, ...body } = request;
|
||||||
userId,
|
|
||||||
role = "member",
|
|
||||||
onSuccess,
|
|
||||||
onError,
|
|
||||||
}: {
|
|
||||||
organisationId: number;
|
|
||||||
userId: number;
|
|
||||||
role?: string;
|
|
||||||
} & ServerQueryInput) {
|
|
||||||
const url = new URL(`${getServerURL()}/organisation/add-member`);
|
|
||||||
url.searchParams.set("organisationId", `${organisationId}`);
|
|
||||||
url.searchParams.set("userId", `${userId}`);
|
|
||||||
url.searchParams.set("role", role);
|
|
||||||
|
|
||||||
const csrfToken = getCsrfToken();
|
const csrfToken = getCsrfToken();
|
||||||
const headers: HeadersInit = {};
|
|
||||||
if (csrfToken) headers["X-CSRF-Token"] = csrfToken;
|
|
||||||
|
|
||||||
const res = await fetch(url.toString(), {
|
const res = await fetch(`${getServerURL()}/organisation/add-member`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers,
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(csrfToken ? { "X-CSRF-Token": csrfToken } : {}),
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await res.text();
|
const error = await res.json().catch(() => res.text());
|
||||||
onError?.(error || `failed to add member (${res.status})`);
|
const message =
|
||||||
|
typeof error === "string" ? error : error.error || `failed to add member (${res.status})`;
|
||||||
|
toast.error(message);
|
||||||
|
onError?.(error);
|
||||||
} else {
|
} else {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
onSuccess?.(data, res);
|
onSuccess?.(data, res);
|
||||||
|
|||||||
@@ -1,23 +1,17 @@
|
|||||||
|
import type { OrganisationResponse } from "@issue/shared";
|
||||||
import { getServerURL } from "@/lib/utils";
|
import { getServerURL } from "@/lib/utils";
|
||||||
import type { ServerQueryInput } from "..";
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
export async function byUser({
|
export async function byUser({ onSuccess, onError }: ServerQueryInput<OrganisationResponse[]>) {
|
||||||
userId,
|
const res = await fetch(`${getServerURL()}/organisations/by-user`, {
|
||||||
onSuccess,
|
|
||||||
onError,
|
|
||||||
}: {
|
|
||||||
userId: number;
|
|
||||||
} & ServerQueryInput) {
|
|
||||||
const url = new URL(`${getServerURL()}/organisations/by-user`);
|
|
||||||
url.searchParams.set("userId", `${userId}`);
|
|
||||||
|
|
||||||
const res = await fetch(url.toString(), {
|
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await res.text();
|
const error = await res.json().catch(() => res.text());
|
||||||
onError?.(error || `failed to get organisations (${res.status})`);
|
const message =
|
||||||
|
typeof error === "string" ? error : error.error || `failed to get organisations (${res.status})`;
|
||||||
|
onError?.(message);
|
||||||
} else {
|
} else {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
onSuccess?.(data, res);
|
onSuccess?.(data, res);
|
||||||
|
|||||||
@@ -1,44 +1,37 @@
|
|||||||
|
import type { OrganisationRecord, OrgCreateRequest } from "@issue/shared";
|
||||||
|
import { toast } from "sonner";
|
||||||
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
||||||
import type { ServerQueryInput } from "..";
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
export async function create({
|
export async function create(request: OrgCreateRequest & ServerQueryInput<OrganisationRecord>) {
|
||||||
name,
|
const { onSuccess, onError, ...body } = request;
|
||||||
slug,
|
|
||||||
userId,
|
|
||||||
description,
|
|
||||||
onSuccess,
|
|
||||||
onError,
|
|
||||||
}: {
|
|
||||||
name: string;
|
|
||||||
slug: string;
|
|
||||||
userId: number;
|
|
||||||
description: string;
|
|
||||||
} & ServerQueryInput) {
|
|
||||||
const url = new URL(`${getServerURL()}/organisation/create`);
|
|
||||||
url.searchParams.set("name", name.trim());
|
|
||||||
url.searchParams.set("slug", slug.trim());
|
|
||||||
url.searchParams.set("userId", `${userId}`);
|
|
||||||
if (description.trim() !== "") url.searchParams.set("description", description.trim());
|
|
||||||
|
|
||||||
const csrfToken = getCsrfToken();
|
const csrfToken = getCsrfToken();
|
||||||
const headers: HeadersInit = {};
|
|
||||||
if (csrfToken) headers["X-CSRF-Token"] = csrfToken;
|
|
||||||
|
|
||||||
const res = await fetch(url.toString(), {
|
const res = await fetch(`${getServerURL()}/organisation/create`, {
|
||||||
headers,
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(csrfToken ? { "X-CSRF-Token": csrfToken } : {}),
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await res.text();
|
const error = await res.json().catch(() => res.text());
|
||||||
onError?.(error || `failed to create organisation (${res.status})`);
|
const message =
|
||||||
|
typeof error === "string"
|
||||||
|
? error
|
||||||
|
: error.error || `failed to create organisation (${res.status})`;
|
||||||
|
toast.error(message);
|
||||||
|
onError?.(error);
|
||||||
} else {
|
} else {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (!data.id) {
|
if (!data.id) {
|
||||||
|
toast.error(`failed to create organisation (${res.status})`);
|
||||||
onError?.(`failed to create organisation (${res.status})`);
|
onError?.(`failed to create organisation (${res.status})`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
onSuccess?.(data, res);
|
onSuccess?.(data, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export async function members({
|
|||||||
onError,
|
onError,
|
||||||
}: {
|
}: {
|
||||||
organisationId: number;
|
organisationId: number;
|
||||||
} & ServerQueryInput) {
|
} & ServerQueryInput<OrganisationMemberResponse[]>) {
|
||||||
const url = new URL(`${getServerURL()}/organisation/members`);
|
const url = new URL(`${getServerURL()}/organisation/members`);
|
||||||
url.searchParams.set("organisationId", `${organisationId}`);
|
url.searchParams.set("organisationId", `${organisationId}`);
|
||||||
|
|
||||||
|
|||||||
@@ -1,32 +1,28 @@
|
|||||||
|
import type { OrgRemoveMemberRequest, SuccessResponse } from "@issue/shared";
|
||||||
|
import { toast } from "sonner";
|
||||||
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
||||||
import type { ServerQueryInput } from "..";
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
export async function removeMember({
|
export async function removeMember(request: OrgRemoveMemberRequest & ServerQueryInput<SuccessResponse>) {
|
||||||
organisationId,
|
const { onSuccess, onError, ...body } = request;
|
||||||
userId,
|
|
||||||
onSuccess,
|
|
||||||
onError,
|
|
||||||
}: {
|
|
||||||
organisationId: number;
|
|
||||||
userId: number;
|
|
||||||
} & ServerQueryInput) {
|
|
||||||
const url = new URL(`${getServerURL()}/organisation/remove-member`);
|
|
||||||
url.searchParams.set("organisationId", `${organisationId}`);
|
|
||||||
url.searchParams.set("userId", `${userId}`);
|
|
||||||
|
|
||||||
const csrfToken = getCsrfToken();
|
const csrfToken = getCsrfToken();
|
||||||
const headers: HeadersInit = {};
|
|
||||||
if (csrfToken) headers["X-CSRF-Token"] = csrfToken;
|
|
||||||
|
|
||||||
const res = await fetch(url.toString(), {
|
const res = await fetch(`${getServerURL()}/organisation/remove-member`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers,
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(csrfToken ? { "X-CSRF-Token": csrfToken } : {}),
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await res.text();
|
const error = await res.json().catch(() => res.text());
|
||||||
onError?.(error || `failed to remove member (${res.status})`);
|
const message =
|
||||||
|
typeof error === "string" ? error : error.error || `failed to remove member (${res.status})`;
|
||||||
|
toast.error(message);
|
||||||
|
onError?.(error);
|
||||||
} else {
|
} else {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
onSuccess?.(data, res);
|
onSuccess?.(data, res);
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import type { OrganisationRecord } from "@issue/shared";
|
||||||
|
import { toast } from "sonner";
|
||||||
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
||||||
import type { ServerQueryInput } from "..";
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
@@ -15,28 +17,33 @@ export async function update({
|
|||||||
description?: string;
|
description?: string;
|
||||||
slug?: string;
|
slug?: string;
|
||||||
statuses?: Record<string, string>;
|
statuses?: Record<string, string>;
|
||||||
} & ServerQueryInput) {
|
} & ServerQueryInput<OrganisationRecord>) {
|
||||||
const url = new URL(`${getServerURL()}/organisation/update`);
|
|
||||||
url.searchParams.set("id", `${organisationId}`);
|
|
||||||
if (name !== undefined) url.searchParams.set("name", name);
|
|
||||||
if (description !== undefined) url.searchParams.set("description", description);
|
|
||||||
if (slug !== undefined) url.searchParams.set("slug", slug);
|
|
||||||
if (statuses !== undefined) {
|
|
||||||
url.searchParams.set("statuses", JSON.stringify(statuses));
|
|
||||||
}
|
|
||||||
|
|
||||||
const csrfToken = getCsrfToken();
|
const csrfToken = getCsrfToken();
|
||||||
const headers: HeadersInit = {};
|
|
||||||
if (csrfToken) headers["X-CSRF-Token"] = csrfToken;
|
|
||||||
|
|
||||||
const res = await fetch(url.toString(), {
|
const res = await fetch(`${getServerURL()}/organisation/update`, {
|
||||||
headers,
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(csrfToken ? { "X-CSRF-Token": csrfToken } : {}),
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
id: organisationId,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
slug,
|
||||||
|
statuses,
|
||||||
|
}),
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await res.text();
|
const error = await res.json().catch(() => res.text());
|
||||||
onError?.(error || `failed to update organisation (${res.status})`);
|
const message =
|
||||||
|
typeof error === "string"
|
||||||
|
? error
|
||||||
|
: error.error || `failed to update organisation (${res.status})`;
|
||||||
|
toast.error(message);
|
||||||
|
onError?.(error);
|
||||||
} else {
|
} else {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
onSuccess?.(data, res);
|
onSuccess?.(data, res);
|
||||||
|
|||||||
@@ -1,35 +1,30 @@
|
|||||||
|
import type { OrganisationMemberRecord, OrgUpdateMemberRoleRequest } from "@issue/shared";
|
||||||
|
import { toast } from "sonner";
|
||||||
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
||||||
import type { ServerQueryInput } from "..";
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
export async function updateMemberRole({
|
export async function updateMemberRole(
|
||||||
organisationId,
|
request: OrgUpdateMemberRoleRequest & ServerQueryInput<OrganisationMemberRecord>,
|
||||||
userId,
|
) {
|
||||||
role,
|
const { onSuccess, onError, ...body } = request;
|
||||||
onSuccess,
|
|
||||||
onError,
|
|
||||||
}: {
|
|
||||||
organisationId: number;
|
|
||||||
userId: number;
|
|
||||||
role: string;
|
|
||||||
} & ServerQueryInput) {
|
|
||||||
const url = new URL(`${getServerURL()}/organisation/update-member-role`);
|
|
||||||
url.searchParams.set("organisationId", `${organisationId}`);
|
|
||||||
url.searchParams.set("userId", `${userId}`);
|
|
||||||
url.searchParams.set("role", role);
|
|
||||||
|
|
||||||
const csrfToken = getCsrfToken();
|
const csrfToken = getCsrfToken();
|
||||||
const headers: HeadersInit = {};
|
|
||||||
if (csrfToken) headers["X-CSRF-Token"] = csrfToken;
|
|
||||||
|
|
||||||
const res = await fetch(url.toString(), {
|
const res = await fetch(`${getServerURL()}/organisation/update-member-role`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers,
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(csrfToken ? { "X-CSRF-Token": csrfToken } : {}),
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await res.text();
|
const error = await res.json().catch(() => res.text());
|
||||||
onError?.(error || `failed to update member role (${res.status})`);
|
const message =
|
||||||
|
typeof error === "string" ? error : error.error || `failed to update member role (${res.status})`;
|
||||||
|
toast.error(message);
|
||||||
|
onError?.(error);
|
||||||
} else {
|
} else {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
onSuccess?.(data, res);
|
onSuccess?.(data, res);
|
||||||
|
|||||||
@@ -1,44 +1,35 @@
|
|||||||
|
import type { ProjectCreateRequest, ProjectRecord } from "@issue/shared";
|
||||||
|
import { toast } from "sonner";
|
||||||
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
||||||
import type { ServerQueryInput } from "..";
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
export async function create({
|
export async function create(request: ProjectCreateRequest & ServerQueryInput<ProjectRecord>) {
|
||||||
key,
|
const { onSuccess, onError, ...body } = request;
|
||||||
name,
|
|
||||||
creatorId,
|
|
||||||
organisationId,
|
|
||||||
onSuccess,
|
|
||||||
onError,
|
|
||||||
}: {
|
|
||||||
key: string;
|
|
||||||
name: string;
|
|
||||||
creatorId: number;
|
|
||||||
organisationId: number;
|
|
||||||
} & ServerQueryInput) {
|
|
||||||
const url = new URL(`${getServerURL()}/project/create`);
|
|
||||||
url.searchParams.set("key", key.trim());
|
|
||||||
url.searchParams.set("name", name.trim());
|
|
||||||
url.searchParams.set("creatorId", `${creatorId}`);
|
|
||||||
url.searchParams.set("organisationId", `${organisationId}`);
|
|
||||||
|
|
||||||
const csrfToken = getCsrfToken();
|
const csrfToken = getCsrfToken();
|
||||||
const headers: HeadersInit = {};
|
|
||||||
if (csrfToken) headers["X-CSRF-Token"] = csrfToken;
|
|
||||||
|
|
||||||
const res = await fetch(url.toString(), {
|
const res = await fetch(`${getServerURL()}/project/create`, {
|
||||||
headers,
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(csrfToken ? { "X-CSRF-Token": csrfToken } : {}),
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await res.text();
|
const error = await res.json().catch(() => res.text());
|
||||||
onError?.(error || `failed to create project (${res.status})`);
|
const message =
|
||||||
|
typeof error === "string" ? error : error.error || `failed to create project (${res.status})`;
|
||||||
|
toast.error(message);
|
||||||
|
onError?.(error);
|
||||||
} else {
|
} else {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (!data.id) {
|
if (!data.id) {
|
||||||
|
toast.error(`failed to create project (${res.status})`);
|
||||||
onError?.(`failed to create project (${res.status})`);
|
onError?.(`failed to create project (${res.status})`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
onSuccess?.(data, res);
|
onSuccess?.(data, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { SprintRecord } from "@issue/shared";
|
||||||
import { getServerURL } from "@/lib/utils";
|
import { getServerURL } from "@/lib/utils";
|
||||||
import type { ServerQueryInput } from "..";
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
@@ -7,7 +8,7 @@ export async function byProject({
|
|||||||
onError,
|
onError,
|
||||||
}: {
|
}: {
|
||||||
projectId: number;
|
projectId: number;
|
||||||
} & ServerQueryInput) {
|
} & ServerQueryInput<SprintRecord[]>) {
|
||||||
const url = new URL(`${getServerURL()}/sprints/by-project`);
|
const url = new URL(`${getServerURL()}/sprints/by-project`);
|
||||||
url.searchParams.set("projectId", `${projectId}`);
|
url.searchParams.set("projectId", `${projectId}`);
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import type { SprintRecord } from "@issue/shared";
|
||||||
|
import { toast } from "sonner";
|
||||||
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
||||||
import type { ServerQueryInput } from "..";
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
@@ -12,36 +14,41 @@ export async function create({
|
|||||||
}: {
|
}: {
|
||||||
projectId: number;
|
projectId: number;
|
||||||
name: string;
|
name: string;
|
||||||
color: string;
|
color?: string;
|
||||||
startDate: Date;
|
startDate: Date;
|
||||||
endDate: Date;
|
endDate: Date;
|
||||||
} & ServerQueryInput) {
|
} & ServerQueryInput<SprintRecord>) {
|
||||||
const url = new URL(`${getServerURL()}/sprint/create`);
|
|
||||||
url.searchParams.set("projectId", `${projectId}`);
|
|
||||||
url.searchParams.set("name", name.trim());
|
|
||||||
url.searchParams.set("color", color);
|
|
||||||
url.searchParams.set("startDate", startDate.toISOString());
|
|
||||||
url.searchParams.set("endDate", endDate.toISOString());
|
|
||||||
|
|
||||||
const csrfToken = getCsrfToken();
|
const csrfToken = getCsrfToken();
|
||||||
const headers: HeadersInit = {};
|
|
||||||
if (csrfToken) headers["X-CSRF-Token"] = csrfToken;
|
|
||||||
|
|
||||||
const res = await fetch(url.toString(), {
|
const res = await fetch(`${getServerURL()}/sprint/create`, {
|
||||||
headers,
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(csrfToken ? { "X-CSRF-Token": csrfToken } : {}),
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
projectId,
|
||||||
|
name: name.trim(),
|
||||||
|
color,
|
||||||
|
startDate: startDate.toISOString(),
|
||||||
|
endDate: endDate.toISOString(),
|
||||||
|
}),
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await res.text();
|
const error = await res.json().catch(() => res.text());
|
||||||
onError?.(error || `failed to create sprint (${res.status})`);
|
const message =
|
||||||
|
typeof error === "string" ? error : error.error || `failed to create sprint (${res.status})`;
|
||||||
|
toast.error(message);
|
||||||
|
onError?.(error);
|
||||||
} else {
|
} else {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (!data.id) {
|
if (!data.id) {
|
||||||
|
toast.error(`failed to create sprint (${res.status})`);
|
||||||
onError?.(`failed to create sprint (${res.status})`);
|
onError?.(`failed to create sprint (${res.status})`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
onSuccess?.(data, res);
|
onSuccess?.(data, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,28 @@
|
|||||||
|
import type { TimerEndRequest, TimerState } from "@issue/shared";
|
||||||
|
import { toast } from "sonner";
|
||||||
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
||||||
import type { ServerQueryInput } from "..";
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
export async function end({
|
export async function end(request: TimerEndRequest & ServerQueryInput<TimerState>) {
|
||||||
issueId,
|
const { onSuccess, onError, ...body } = request;
|
||||||
onSuccess,
|
|
||||||
onError,
|
|
||||||
}: {
|
|
||||||
issueId: number;
|
|
||||||
} & ServerQueryInput) {
|
|
||||||
const url = new URL(`${getServerURL()}/timer/end`);
|
|
||||||
url.searchParams.set("issueId", `${issueId}`);
|
|
||||||
|
|
||||||
const csrfToken = getCsrfToken();
|
const csrfToken = getCsrfToken();
|
||||||
const headers: HeadersInit = {};
|
|
||||||
if (csrfToken) headers["X-CSRF-Token"] = csrfToken;
|
|
||||||
|
|
||||||
const res = await fetch(url.toString(), {
|
const res = await fetch(`${getServerURL()}/timer/end`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers,
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(csrfToken ? { "X-CSRF-Token": csrfToken } : {}),
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await res.text();
|
const error = await res.json().catch(() => res.text());
|
||||||
onError?.(error || `failed to end timer (${res.status})`);
|
const message =
|
||||||
|
typeof error === "string" ? error : error.error || `failed to end timer (${res.status})`;
|
||||||
|
toast.error(message);
|
||||||
|
onError?.(error);
|
||||||
} else {
|
} else {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
onSuccess?.(data, res);
|
onSuccess?.(data, res);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
import type { TimerState } from "@issue/shared";
|
||||||
|
import { getServerURL } from "@/lib/utils";
|
||||||
import type { ServerQueryInput } from "..";
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
export async function get({
|
export async function get({
|
||||||
@@ -7,22 +8,19 @@ export async function get({
|
|||||||
onError,
|
onError,
|
||||||
}: {
|
}: {
|
||||||
issueId: number;
|
issueId: number;
|
||||||
} & ServerQueryInput) {
|
} & ServerQueryInput<TimerState>) {
|
||||||
const url = new URL(`${getServerURL()}/timer/get`);
|
const url = new URL(`${getServerURL()}/timer/get`);
|
||||||
url.searchParams.set("issueId", `${issueId}`);
|
url.searchParams.set("issueId", `${issueId}`);
|
||||||
|
|
||||||
const csrfToken = getCsrfToken();
|
|
||||||
const headers: HeadersInit = {};
|
|
||||||
if (csrfToken) headers["X-CSRF-Token"] = csrfToken;
|
|
||||||
|
|
||||||
const res = await fetch(url.toString(), {
|
const res = await fetch(url.toString(), {
|
||||||
headers,
|
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await res.text();
|
const error = await res.json().catch(() => res.text());
|
||||||
onError?.(error || `failed to get timer (${res.status})`);
|
const message =
|
||||||
|
typeof error === "string" ? error : error.error || `failed to get timer (${res.status})`;
|
||||||
|
onError?.(message);
|
||||||
} else {
|
} else {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
onSuccess?.(data, res);
|
onSuccess?.(data, res);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
import type { TimerState } from "@issue/shared";
|
||||||
|
import { getServerURL } from "@/lib/utils";
|
||||||
import type { ServerQueryInput } from "..";
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
export async function getInactive({
|
export async function getInactive({
|
||||||
@@ -7,24 +8,21 @@ export async function getInactive({
|
|||||||
onError,
|
onError,
|
||||||
}: {
|
}: {
|
||||||
issueId: number;
|
issueId: number;
|
||||||
} & ServerQueryInput) {
|
} & ServerQueryInput<TimerState[]>) {
|
||||||
const url = new URL(`${getServerURL()}/timer/get-inactive`);
|
const url = new URL(`${getServerURL()}/timer/get-inactive`);
|
||||||
url.searchParams.set("issueId", `${issueId}`);
|
url.searchParams.set("issueId", `${issueId}`);
|
||||||
|
|
||||||
const csrfToken = getCsrfToken();
|
|
||||||
const headers: HeadersInit = {};
|
|
||||||
if (csrfToken) headers["X-CSRF-Token"] = csrfToken;
|
|
||||||
|
|
||||||
const res = await fetch(url.toString(), {
|
const res = await fetch(url.toString(), {
|
||||||
headers,
|
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await res.text();
|
const error = await res.json().catch(() => res.text());
|
||||||
onError?.(error || `failed to get timers (${res.status})`);
|
const message =
|
||||||
|
typeof error === "string" ? error : error.error || `failed to get timers (${res.status})`;
|
||||||
|
onError?.(message);
|
||||||
} else {
|
} else {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
onSuccess?.(data, res);
|
onSuccess?.(data || [], res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,28 @@
|
|||||||
|
import type { TimerState, TimerToggleRequest } from "@issue/shared";
|
||||||
|
import { toast } from "sonner";
|
||||||
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
||||||
import type { ServerQueryInput } from "..";
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
export async function toggle({
|
export async function toggle(request: TimerToggleRequest & ServerQueryInput<TimerState>) {
|
||||||
issueId,
|
const { onSuccess, onError, ...body } = request;
|
||||||
onSuccess,
|
|
||||||
onError,
|
|
||||||
}: {
|
|
||||||
issueId: number;
|
|
||||||
} & ServerQueryInput) {
|
|
||||||
const url = new URL(`${getServerURL()}/timer/toggle`);
|
|
||||||
url.searchParams.set("issueId", `${issueId}`);
|
|
||||||
|
|
||||||
const csrfToken = getCsrfToken();
|
const csrfToken = getCsrfToken();
|
||||||
const headers: HeadersInit = {};
|
|
||||||
if (csrfToken) headers["X-CSRF-Token"] = csrfToken;
|
|
||||||
|
|
||||||
const res = await fetch(url.toString(), {
|
const res = await fetch(`${getServerURL()}/timer/toggle`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers,
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(csrfToken ? { "X-CSRF-Token": csrfToken } : {}),
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await res.text();
|
const error = await res.json().catch(() => res.text());
|
||||||
onError?.(error || `failed to toggle timer (${res.status})`);
|
const message =
|
||||||
|
typeof error === "string" ? error : error.error || `failed to toggle timer (${res.status})`;
|
||||||
|
toast.error(message);
|
||||||
|
onError?.(error);
|
||||||
} else {
|
} else {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
onSuccess?.(data, res);
|
onSuccess?.(data, res);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export async function byUsername({
|
|||||||
onError,
|
onError,
|
||||||
}: {
|
}: {
|
||||||
username: string;
|
username: string;
|
||||||
} & ServerQueryInput) {
|
} & ServerQueryInput<UserRecord>) {
|
||||||
const url = new URL(`${getServerURL()}/user/by-username`);
|
const url = new URL(`${getServerURL()}/user/by-username`);
|
||||||
url.searchParams.set("username", username);
|
url.searchParams.set("username", username);
|
||||||
|
|
||||||
@@ -17,8 +17,10 @@ export async function byUsername({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await res.text();
|
const error = await res.json().catch(() => res.text());
|
||||||
onError?.(error || `failed to get user (${res.status})`);
|
const message =
|
||||||
|
typeof error === "string" ? error : error.error || `failed to get user (${res.status})`;
|
||||||
|
onError?.(message);
|
||||||
} else {
|
} else {
|
||||||
const data = (await res.json()) as UserRecord;
|
const data = (await res.json()) as UserRecord;
|
||||||
onSuccess?.(data, res);
|
onSuccess?.(data, res);
|
||||||
|
|||||||
@@ -1,44 +1,35 @@
|
|||||||
|
import type { UserRecord, UserUpdateRequest } from "@issue/shared";
|
||||||
|
import { toast } from "sonner";
|
||||||
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
import { getCsrfToken, getServerURL } from "@/lib/utils";
|
||||||
import type { ServerQueryInput } from "..";
|
import type { ServerQueryInput } from "..";
|
||||||
|
|
||||||
export async function update({
|
export async function update(request: UserUpdateRequest & ServerQueryInput<UserRecord>) {
|
||||||
id,
|
const { onSuccess, onError, ...body } = request;
|
||||||
name,
|
|
||||||
password,
|
|
||||||
avatarURL,
|
|
||||||
onSuccess,
|
|
||||||
onError,
|
|
||||||
}: {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
password: string;
|
|
||||||
avatarURL: string | null;
|
|
||||||
} & ServerQueryInput) {
|
|
||||||
const url = new URL(`${getServerURL()}/user/update`);
|
|
||||||
url.searchParams.set("id", `${id}`);
|
|
||||||
url.searchParams.set("name", name.trim());
|
|
||||||
url.searchParams.set("password", password.trim());
|
|
||||||
url.searchParams.set("avatarURL", avatarURL || "null");
|
|
||||||
|
|
||||||
const csrfToken = getCsrfToken();
|
const csrfToken = getCsrfToken();
|
||||||
const headers: HeadersInit = {};
|
|
||||||
if (csrfToken) headers["X-CSRF-Token"] = csrfToken;
|
|
||||||
|
|
||||||
const res = await fetch(url.toString(), {
|
const res = await fetch(`${getServerURL()}/user/update`, {
|
||||||
headers,
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...(csrfToken ? { "X-CSRF-Token": csrfToken } : {}),
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await res.text();
|
const error = await res.json().catch(() => res.text());
|
||||||
onError?.(error || `failed to update user (${res.status})`);
|
const message =
|
||||||
|
typeof error === "string" ? error : error.error || `failed to update user (${res.status})`;
|
||||||
|
toast.error(message);
|
||||||
|
onError?.(error);
|
||||||
} else {
|
} else {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (!data.id) {
|
if (!data.id) {
|
||||||
|
toast.error(`failed to update user (${res.status})`);
|
||||||
onError?.(`failed to update user (${res.status})`);
|
onError?.(`failed to update user (${res.status})`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
onSuccess?.(data, res);
|
onSuccess?.(data, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export async function uploadAvatar({
|
|||||||
onError,
|
onError,
|
||||||
}: {
|
}: {
|
||||||
file: File;
|
file: File;
|
||||||
} & ServerQueryInput) {
|
} & ServerQueryInput<string>) {
|
||||||
const MAX_FILE_SIZE = 5 * 1024 * 1024;
|
const MAX_FILE_SIZE = 5 * 1024 * 1024;
|
||||||
const ALLOWED_TYPES = ["image/png", "image/jpeg", "image/webp", "image/gif"];
|
const ALLOWED_TYPES = ["image/png", "image/jpeg", "image/webp", "image/gif"];
|
||||||
|
|
||||||
@@ -36,8 +36,10 @@ export async function uploadAvatar({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = await res.text();
|
const error = await res.json().catch(() => res.text());
|
||||||
onError?.(error || `Failed to upload avatar (${res.status})`);
|
const message =
|
||||||
|
typeof error === "string" ? error : error.error || `Failed to upload avatar (${res.status})`;
|
||||||
|
onError?.(message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user