feat: persist portal invitation locales
This commit is contained in:
+34
-14
@@ -9,6 +9,7 @@ import { Input, Label } from "poyraz-ui/atoms";
|
||||
import { Alert, AlertDescription } from "poyraz-ui/molecules";
|
||||
import { getPortalInvitationPreview } from "@/server/auth/invitations";
|
||||
import { getPublicBranding } from "@/server/branding/runtime";
|
||||
import { createTranslator } from "@/server/i18n/translator";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -17,7 +18,7 @@ export default async function InvitationPage({
|
||||
searchParams,
|
||||
}: {
|
||||
params: Promise<{ token: string }>;
|
||||
searchParams: Promise<{ error?: string; message?: string }>;
|
||||
searchParams: Promise<{ error?: string; code?: string; message?: string }>;
|
||||
}) {
|
||||
const { token } = await params;
|
||||
const invitation = getPortalInvitationPreview(token);
|
||||
@@ -27,28 +28,47 @@ export default async function InvitationPage({
|
||||
notFound();
|
||||
}
|
||||
|
||||
const t = createTranslator(invitation.locale, ["auth"]).t;
|
||||
const query = await searchParams;
|
||||
const queryCode = query.code ?? null;
|
||||
const queryMessage = queryCode ? t(queryCode) : query.message;
|
||||
const resolvedQueryMessage = queryMessage === queryCode ? query.message : queryMessage;
|
||||
const marketing = {
|
||||
headline: t("auth.marketing.headline"),
|
||||
description: t("auth.marketing.description", { app: branding.organizationName ?? branding.applicationName }),
|
||||
openSource: t("auth.marketing.openSource"),
|
||||
github: t("auth.marketing.github"),
|
||||
via: t("auth.marketing.via"),
|
||||
builtBy: t("auth.marketing.builtBy"),
|
||||
highlights: [
|
||||
t("auth.highlights.clients"),
|
||||
t("auth.highlights.calendar"),
|
||||
t("auth.highlights.finance"),
|
||||
t("auth.highlights.reports"),
|
||||
] as [string, string, string, string],
|
||||
};
|
||||
const isUsable = invitation.status === "pending";
|
||||
const unavailableMessage =
|
||||
invitation.status === "expired"
|
||||
? "Bu davetin süresi dolmuş. Freelancer'dan yeni bir bağlantı istemelisin."
|
||||
? t("auth.invite.expired")
|
||||
: invitation.status === "accepted"
|
||||
? "Bu davet daha önce kullanılmış. Hesabınla giriş yapabilirsin."
|
||||
? t("auth.invite.accepted")
|
||||
: invitation.status === "revoked"
|
||||
? "Bu davet iptal edilmiş. Freelancer'dan yeni bir bağlantı istemelisin."
|
||||
? t("auth.invite.revoked")
|
||||
: null;
|
||||
|
||||
return (
|
||||
<>
|
||||
{query.error && query.message ? <ErrorToaster message={query.message} /> : null}
|
||||
{query.error && resolvedQueryMessage ? <ErrorToaster message={resolvedQueryMessage} /> : null}
|
||||
<AuthPageShell
|
||||
branding={{
|
||||
applicationName: branding.organizationName ?? branding.applicationName,
|
||||
lightLogoUrl: branding.lightLogoUrl,
|
||||
darkLogoUrl: branding.darkLogoUrl,
|
||||
}}
|
||||
title="Müşteri portalına katıl"
|
||||
description="Davet edilen hesabın için adını ve şifreni belirle."
|
||||
title={t("auth.invite.title")}
|
||||
description={t("auth.invite.description")}
|
||||
marketing={marketing}
|
||||
form={
|
||||
isUsable ? (
|
||||
<form className="space-y-6">
|
||||
@@ -57,28 +77,28 @@ export default async function InvitationPage({
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="email" className="flex items-center gap-2">
|
||||
<Mail className="h-4 w-4 text-muted-foreground" />
|
||||
E-posta
|
||||
{t("auth.invite.email")}
|
||||
</Label>
|
||||
<Input id="email" type="email" value={invitation.email} disabled />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="displayName" className="flex items-center gap-2">
|
||||
<UserRound className="h-4 w-4 text-muted-foreground" />
|
||||
Ad soyad
|
||||
{t("auth.invite.displayName")}
|
||||
</Label>
|
||||
<Input id="displayName" name="displayName" required maxLength={120} />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="password" className="flex items-center gap-2">
|
||||
<LockKeyhole className="h-4 w-4 text-muted-foreground" />
|
||||
Şifre
|
||||
{t("auth.invite.password")}
|
||||
</Label>
|
||||
<Input id="password" name="password" type="password" required minLength={8} maxLength={128} />
|
||||
<p className="text-xs text-muted-foreground">En az 8 karakter kullan.</p>
|
||||
<p className="text-xs text-muted-foreground">{t("auth.invite.passwordHelp")}</p>
|
||||
</div>
|
||||
</div>
|
||||
<SubmitButton size="lg" formAction={acceptInvitation} className="w-full" pendingText="Hesap oluşturuluyor...">
|
||||
Portal hesabını oluştur
|
||||
<SubmitButton size="lg" formAction={acceptInvitation} className="w-full" pendingText={t("auth.invite.pending")}>
|
||||
{t("auth.invite.submit")}
|
||||
</SubmitButton>
|
||||
</form>
|
||||
) : (
|
||||
@@ -90,7 +110,7 @@ export default async function InvitationPage({
|
||||
secondaryAction={null}
|
||||
footer={
|
||||
<Link href="/login" className="text-sm font-medium text-primary hover:text-primary-hover">
|
||||
Giriş sayfasına dön
|
||||
{t("auth.invite.backToLogin")}
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user