chore: clean up types

This commit is contained in:
Henry
2026-04-20 21:54:23 +01:00
parent b4b07f3120
commit 39bca3b39f
16 changed files with 84 additions and 39 deletions

View File

@@ -85,7 +85,7 @@ export interface RenderSuggestionsProps {
export interface WorkspaceMember { export interface WorkspaceMember {
publicId: string; publicId: string;
user: { user: {
id: string; id: string | null;
name: string | null; name: string | null;
image: string | null; image: string | null;
} | null; } | null;

View File

@@ -1,6 +1,6 @@
import type { Locale as DateFnsLocale } from "date-fns"; import type { Locale as DateFnsLocale } from "date-fns";
import { useLingui } from "@lingui/react"; import { useLingui } from "@lingui/react";
import { de, enGB, es, fr, it, nl, pl, ru, ptBR} from "date-fns/locale"; import { de, enGB, es, fr, it, nl, pl, ptBR, ru } from "date-fns/locale";
import type { Locale } from "~/locales"; import type { Locale } from "~/locales";
import { useLinguiContext } from "~/providers/lingui"; import { useLinguiContext } from "~/providers/lingui";
@@ -19,7 +19,7 @@ export function useLocalisation() {
nl, nl,
ru, ru,
pl, pl,
"pt-BR": ptBR, ptbr: ptBR,
}; };
const currentDateLocale = dateLocaleMap[locale] ?? enGB; const currentDateLocale = dateLocaleMap[locale] ?? enGB;

View File

@@ -22,8 +22,8 @@ const loadMessages = async (locale: Locale) => {
return (await import("~/locales/ru/messages")).messages; return (await import("~/locales/ru/messages")).messages;
case "pl": case "pl":
return (await import("~/locales/pl/messages")).messages; return (await import("~/locales/pl/messages")).messages;
case "pt-BR": case "ptbr":
return (await import("~/locales/pt-BR/messages")).messages; return (await import("~/locales/ptbr/messages")).messages;
default: default:
return enMessages; return enMessages;
} }

View File

@@ -2,9 +2,9 @@ import type { DropResult } from "react-beautiful-dnd";
import Link from "next/link"; import Link from "next/link";
import { useParams } from "next/navigation"; import { useParams } from "next/navigation";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { env } from "next-runtime-env";
import { t } from "@lingui/core/macro"; import { t } from "@lingui/core/macro";
import { keepPreviousData } from "@tanstack/react-query"; import { keepPreviousData } from "@tanstack/react-query";
import { env } from "next-runtime-env";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { DragDropContext, Draggable } from "react-beautiful-dnd"; import { DragDropContext, Draggable } from "react-beautiful-dnd";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";

View File

@@ -525,7 +525,6 @@ const ActivityList = ({
comment={activity.comment?.comment} comment={activity.comment?.comment}
isEdited={!!activity.comment?.updatedAt} isEdited={!!activity.comment?.updatedAt}
isAuthor={activity.comment?.createdBy === sessionData?.user.id} isAuthor={activity.comment?.createdBy === sessionData?.user.id}
isAdmin={isAdmin ?? false}
isViewOnly={!!isViewOnly} isViewOnly={!!isViewOnly}
/> />
); );

View File

@@ -17,11 +17,11 @@ import { useModal } from "~/providers/modal";
import { useWorkspace } from "~/providers/workspace"; import { useWorkspace } from "~/providers/workspace";
import { api } from "~/utils/api"; import { api } from "~/utils/api";
import { DeleteWorkspaceConfirmation } from "./components/DeleteWorkspaceConfirmation"; import { DeleteWorkspaceConfirmation } from "./components/DeleteWorkspaceConfirmation";
import UpdateWeekStartDayForm from "./components/UpdateWeekStartDayForm";
import UpdateWorkspaceDescriptionForm from "./components/UpdateWorkspaceDescriptionForm"; import UpdateWorkspaceDescriptionForm from "./components/UpdateWorkspaceDescriptionForm";
import UpdateWorkspaceEmailVisibilityForm from "./components/UpdateWorkspaceEmailVisibilityForm"; import UpdateWorkspaceEmailVisibilityForm from "./components/UpdateWorkspaceEmailVisibilityForm";
import UpdateWorkspaceNameForm from "./components/UpdateWorkspaceNameForm"; import UpdateWorkspaceNameForm from "./components/UpdateWorkspaceNameForm";
import UpdateWorkspaceUrlForm from "./components/UpdateWorkspaceUrlForm"; import UpdateWorkspaceUrlForm from "./components/UpdateWorkspaceUrlForm";
import UpdateWeekStartDayForm from "./components/UpdateWeekStartDayForm";
import { UpgradeToProConfirmation } from "./components/UpgradeToProConfirmation"; import { UpgradeToProConfirmation } from "./components/UpgradeToProConfirmation";
export default function WorkspaceSettings() { export default function WorkspaceSettings() {

View File

@@ -13,20 +13,29 @@ interface DeleteWebhookConfirmationProps {
export function DeleteWebhookConfirmation({ export function DeleteWebhookConfirmation({
workspacePublicId, workspacePublicId,
}: DeleteWebhookConfirmationProps) { }: DeleteWebhookConfirmationProps) {
const { closeModal, entityId: webhookPublicId, entityLabel: webhookName } = useModal(); const {
closeModal,
entityId: webhookPublicId,
entityLabel: webhookName,
} = useModal();
const { showPopup } = usePopup(); const { showPopup } = usePopup();
const utils = api.useUtils(); const utils = api.useUtils();
const deleteWebhookMutation = api.webhook.delete.useMutation({ const deleteWebhookMutation = api.webhook.delete.useMutation({
onSuccess: () => { onSuccess: () => {
void utils.webhook.list.invalidate({ workspacePublicId }); void utils.webhook.list.invalidate({ workspacePublicId });
showPopup({ message: t`Webhook deleted successfully`, type: "success" }); showPopup({
header: t`Webhook deleted`,
message: t`Webhook deleted successfully`,
icon: "success",
});
closeModal(); closeModal();
}, },
onError: (error) => { onError: (error) => {
showPopup({ showPopup({
header: t`Unable to delete webhook`,
message: error.message || t`Failed to delete webhook`, message: error.message || t`Failed to delete webhook`,
type: "error", icon: "error",
}); });
}, },
}); });
@@ -35,7 +44,7 @@ export function DeleteWebhookConfirmation({
if (!webhookPublicId) return; if (!webhookPublicId) return;
deleteWebhookMutation.mutate({ deleteWebhookMutation.mutate({
workspacePublicId, workspacePublicId,
webhookPublicId: webhookPublicId as string, webhookPublicId: webhookPublicId,
}); });
}; };

View File

@@ -44,7 +44,12 @@ export function NewWebhookModal({
workspacePublicId, workspacePublicId,
isEdit = false, isEdit = false,
}: NewWebhookModalProps) { }: NewWebhookModalProps) {
const { closeModal, entityId: webhookPublicId, getModalState, clearModalState } = useModal(); const {
closeModal,
entityId: webhookPublicId,
getModalState,
clearModalState,
} = useModal();
const { showPopup } = usePopup(); const { showPopup } = usePopup();
const [isTestingWebhook, setIsTestingWebhook] = useState(false); const [isTestingWebhook, setIsTestingWebhook] = useState(false);
@@ -101,13 +106,18 @@ export function NewWebhookModal({
const createWebhookMutation = api.webhook.create.useMutation({ const createWebhookMutation = api.webhook.create.useMutation({
onSuccess: () => { onSuccess: () => {
void utils.webhook.list.invalidate({ workspacePublicId }); void utils.webhook.list.invalidate({ workspacePublicId });
showPopup({ message: t`Webhook created successfully`, type: "success" }); showPopup({
header: t`Webhook created`,
message: t`Webhook created successfully`,
icon: "success",
});
closeModal(); closeModal();
}, },
onError: (error) => { onError: (error) => {
showPopup({ showPopup({
header: t`Unable to create webhook`,
message: error.message || t`Failed to create webhook`, message: error.message || t`Failed to create webhook`,
type: "error", icon: "error",
}); });
}, },
}); });
@@ -115,13 +125,18 @@ export function NewWebhookModal({
const updateWebhookMutation = api.webhook.update.useMutation({ const updateWebhookMutation = api.webhook.update.useMutation({
onSuccess: () => { onSuccess: () => {
void utils.webhook.list.invalidate({ workspacePublicId }); void utils.webhook.list.invalidate({ workspacePublicId });
showPopup({ message: t`Webhook updated successfully`, type: "success" }); showPopup({
header: t`Webhook updated`,
message: t`Webhook updated successfully`,
icon: "success",
});
closeModal(); closeModal();
}, },
onError: (error) => { onError: (error) => {
showPopup({ showPopup({
header: t`Unable to update webhook`,
message: error.message || t`Failed to update webhook`, message: error.message || t`Failed to update webhook`,
type: "error", icon: "error",
}); });
}, },
}); });
@@ -129,19 +144,25 @@ export function NewWebhookModal({
const testWebhookMutation = api.webhook.test.useMutation({ const testWebhookMutation = api.webhook.test.useMutation({
onSuccess: (result) => { onSuccess: (result) => {
if (result.success) { if (result.success) {
showPopup({ message: t`Test webhook sent successfully!`, type: "success" }); showPopup({
header: t`Test sent`,
message: t`Test webhook sent successfully!`,
icon: "success",
});
} else { } else {
showPopup({ showPopup({
header: t`Test failed`,
message: result.error || t`Webhook test failed`, message: result.error || t`Webhook test failed`,
type: "error", icon: "error",
}); });
} }
setIsTestingWebhook(false); setIsTestingWebhook(false);
}, },
onError: (error) => { onError: (error) => {
showPopup({ showPopup({
header: t`Unable to test webhook`,
message: error.message || t`Failed to test webhook`, message: error.message || t`Failed to test webhook`,
type: "error", icon: "error",
}); });
setIsTestingWebhook(false); setIsTestingWebhook(false);
}, },
@@ -151,7 +172,7 @@ export function NewWebhookModal({
if (isEdit && webhookPublicId) { if (isEdit && webhookPublicId) {
updateWebhookMutation.mutate({ updateWebhookMutation.mutate({
workspacePublicId, workspacePublicId,
webhookPublicId: webhookPublicId as string, webhookPublicId: webhookPublicId,
name: data.name, name: data.name,
url: data.url, url: data.url,
secret: data.secret || undefined, secret: data.secret || undefined,
@@ -174,11 +195,12 @@ export function NewWebhookModal({
setIsTestingWebhook(true); setIsTestingWebhook(true);
testWebhookMutation.mutate({ testWebhookMutation.mutate({
workspacePublicId, workspacePublicId,
webhookPublicId: webhookPublicId as string, webhookPublicId: webhookPublicId,
}); });
}; };
const isPending = createWebhookMutation.isPending || updateWebhookMutation.isPending; const isPending =
createWebhookMutation.isPending || updateWebhookMutation.isPending;
return ( return (
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
@@ -231,7 +253,11 @@ export function NewWebhookModal({
<Input <Input
id="secret" id="secret"
type="password" type="password"
placeholder={isEdit ? t`Enter new secret to update` : t`HMAC secret for signature verification`} placeholder={
isEdit
? t`Enter new secret to update`
: t`HMAC secret for signature verification`
}
{...register("secret")} {...register("secret")}
errorMessage={errors.secret?.message} errorMessage={errors.secret?.message}
/> />
@@ -252,7 +278,7 @@ export function NewWebhookModal({
{webhookEvents.map((event) => ( {webhookEvents.map((event) => (
<label <label
key={event} key={event}
className="flex items-center space-x-2 cursor-pointer" className="flex cursor-pointer items-center space-x-2"
> >
<input <input
type="checkbox" type="checkbox"
@@ -262,11 +288,11 @@ export function NewWebhookModal({
field.onChange([...field.value, event]); field.onChange([...field.value, event]);
} else { } else {
field.onChange( field.onChange(
field.value.filter((v) => v !== event) field.value.filter((v) => v !== event),
); );
} }
}} }}
className="h-4 w-4 rounded border-light-400 text-primary-600 focus:ring-primary-500 dark:border-dark-400" className="text-primary-600 focus:ring-primary-500 h-4 w-4 rounded border-light-400 dark:border-dark-400"
/> />
<span className="text-sm text-light-900 dark:text-dark-900"> <span className="text-sm text-light-900 dark:text-dark-900">
{event} {event}
@@ -277,17 +303,19 @@ export function NewWebhookModal({
)} )}
/> />
{errors.events && ( {errors.events && (
<p className="mt-1 text-xs text-red-500">{errors.events.message}</p> <p className="mt-1 text-xs text-red-500">
{errors.events.message}
</p>
)} )}
</div> </div>
{isEdit && ( {isEdit && (
<div> <div>
<label className="flex items-center space-x-2 cursor-pointer"> <label className="flex cursor-pointer items-center space-x-2">
<input <input
type="checkbox" type="checkbox"
{...register("active")} {...register("active")}
className="h-4 w-4 rounded border-light-400 text-primary-600 focus:ring-primary-500 dark:border-dark-400" className="text-primary-600 focus:ring-primary-500 h-4 w-4 rounded border-light-400 dark:border-dark-400"
/> />
<span className="text-sm text-light-900 dark:text-dark-900"> <span className="text-sm text-light-900 dark:text-dark-900">
{t`Active`} {t`Active`}

View File

@@ -36,7 +36,7 @@ export default function UpdateWeekStartDayForm({
setValue(newValue); setValue(newValue);
updateWorkspace.mutate({ updateWorkspace.mutate({
workspacePublicId, workspacePublicId,
weekStartDay: newValue, weekStartDay: newValue as 0 | 1 | 6,
}); });
}; };

View File

@@ -20,7 +20,7 @@ const UpdateWorkspaceUrlForm = ({
}: { }: {
workspacePublicId: string; workspacePublicId: string;
workspaceUrl: string; workspaceUrl: string;
workspacePlan: "free" | "pro" | "enterprise"; workspacePlan: "free" | "team" | "pro" | "enterprise";
disabled?: boolean; disabled?: boolean;
}) => { }) => {
const utils = api.useUtils(); const utils = api.useUtils();

View File

@@ -171,18 +171,20 @@ export default function WebhookList({ workspacePublicId }: WebhookListProps) {
const testWebhookMutation = api.webhook.test.useMutation({ const testWebhookMutation = api.webhook.test.useMutation({
onSuccess: (result) => { onSuccess: (result) => {
if (result.success) { if (result.success) {
showPopup({ message: t`Test webhook sent successfully!`, type: "success" }); showPopup({ header: t`Test sent`, message: t`Test webhook sent successfully!`, icon: "success" });
} else { } else {
showPopup({ showPopup({
header: t`Test failed`,
message: result.error || t`Webhook test failed`, message: result.error || t`Webhook test failed`,
type: "error", icon: "error",
}); });
} }
}, },
onError: (error) => { onError: (error) => {
showPopup({ showPopup({
header: t`Unable to test webhook`,
message: error.message || t`Failed to test webhook`, message: error.message || t`Failed to test webhook`,
type: "error", icon: "error",
}); });
}, },
}); });

View File

@@ -36,6 +36,7 @@ const cardMemberSchema = z.object({
email: z.string(), email: z.string(),
user: z user: z
.object({ .object({
id: z.string().nullable(),
name: z.string().nullable(), name: z.string().nullable(),
}) })
.nullable(), .nullable(),
@@ -180,6 +181,7 @@ export const activityItemSchema = z.object({
publicId: z.string(), publicId: z.string(),
user: z user: z
.object({ .object({
id: z.string().nullable(),
name: z.string().nullable(), name: z.string().nullable(),
email: z.string(), email: z.string(),
image: z.string().nullable(), image: z.string().nullable(),
@@ -189,6 +191,7 @@ export const activityItemSchema = z.object({
.nullable(), .nullable(),
user: z user: z
.object({ .object({
id: z.string().nullable(),
name: z.string().nullable(), name: z.string().nullable(),
email: z.string(), email: z.string(),
image: z.string().nullable(), image: z.string().nullable(),

View File

@@ -25,6 +25,7 @@ export const checklistResponseSchema = z.object({
// Shared user sub-object (used inside member/workspace responses) // Shared user sub-object (used inside member/workspace responses)
export const userSchema = z.object({ export const userSchema = z.object({
id: z.string().nullable(),
name: z.string().nullable(), name: z.string().nullable(),
email: z.string(), email: z.string(),
image: z.string().nullable(), image: z.string().nullable(),

View File

@@ -10,7 +10,7 @@ export const workspaceListItemSchema = z.object({
name: z.string(), name: z.string(),
description: z.string().nullable(), description: z.string().nullable(),
slug: z.string(), slug: z.string(),
plan: z.enum(["free", "pro", "enterprise"]), plan: z.enum(["free", "team", "pro", "enterprise"]),
weekStartDay: z.number().nullable(), weekStartDay: z.number().nullable(),
deletedAt: z.date().nullable(), deletedAt: z.date().nullable(),
}), }),
@@ -25,6 +25,7 @@ const workspaceMemberDetailSchema = z.object({
createdAt: z.date(), createdAt: z.date(),
user: z user: z
.object({ .object({
id: z.string().nullable(),
name: z.string().nullable(), name: z.string().nullable(),
email: z.string().optional(), email: z.string().optional(),
image: z.string().nullable(), image: z.string().nullable(),
@@ -72,7 +73,7 @@ export const workspaceCreateResponseSchema = z.object({
name: z.string(), name: z.string(),
slug: z.string(), slug: z.string(),
description: z.string().nullable(), description: z.string().nullable(),
plan: z.enum(["free", "pro", "enterprise"]), plan: z.enum(["free", "team", "pro", "enterprise"]),
}); });
// ─── workspace.update ──────────────────────────────────────── // ─── workspace.update ────────────────────────────────────────
@@ -81,7 +82,7 @@ export const workspaceUpdateResponseSchema = z.object({
name: z.string(), name: z.string(),
slug: z.string(), slug: z.string(),
description: z.string().nullable(), description: z.string().nullable(),
plan: z.enum(["free", "pro", "enterprise"]), plan: z.enum(["free", "team", "pro", "enterprise"]),
showEmailsToMembers: z.boolean().nullable(), showEmailsToMembers: z.boolean().nullable(),
weekStartDay: z.number().nullable(), weekStartDay: z.number().nullable(),
}); });

View File

@@ -170,7 +170,7 @@ export function createPlugins(db: dbClient) {
if (authorization?.startsWith("Bearer ")) { if (authorization?.startsWith("Bearer ")) {
return authorization.slice(7); return authorization.slice(7);
} }
return ctx.headers?.get("x-api-key") ?? undefined; return ctx.headers?.get("x-api-key") ?? null;
}, },
rateLimit: { rateLimit: {
enabled: true, enabled: true,

View File

@@ -220,6 +220,7 @@ export const getByPublicId = async (
with: { with: {
user: { user: {
columns: { columns: {
id: true,
name: true, name: true,
email: true, email: true,
image: true, image: true,
@@ -278,6 +279,7 @@ export const getByPublicId = async (
with: { with: {
user: { user: {
columns: { columns: {
id: true,
name: true, name: true,
email: true, email: true,
image: true, image: true,