diff --git a/app/portal/projects/page.tsx b/app/portal/projects/page.tsx
index 1fbe4e7..e877601 100644
--- a/app/portal/projects/page.tsx
+++ b/app/portal/projects/page.tsx
@@ -23,6 +23,7 @@ export default async function PortalProjectsPage() {
defaultLocale: locale.defaultLocale,
translations: projectTranslations.get(project.id) ?? [],
}));
+ const number = new Intl.NumberFormat(locale.locale);
return (
@@ -47,6 +48,9 @@ export default async function PortalProjectsPage() {
{project.status === "completed" ? t("portal.status.project.completed") : project.status === "active" ? t("portal.status.project.active") : t("portal.status.project.waiting")}
+ ) : null}
{project.dueDate && (
@@ -57,7 +61,7 @@ export default async function PortalProjectsPage() {
{t("portal.labels.progress")}
- %{project.progress}
+ {t("portal.labels.percent", { value: number.format(project.progress) })}
diff --git a/app/portal/revisions/page.tsx b/app/portal/revisions/page.tsx
index 0fddef1..0a84da2 100644
--- a/app/portal/revisions/page.tsx
+++ b/app/portal/revisions/page.tsx
@@ -65,7 +65,7 @@ export default async function PortalRevisionsPage() {
- {t("portal.labels.project")} →
+ {t("portal.labels.openProjectCta")}
diff --git a/app/portal/tasks/page.tsx b/app/portal/tasks/page.tsx
index 6a710e5..910a9ad 100644
--- a/app/portal/tasks/page.tsx
+++ b/app/portal/tasks/page.tsx
@@ -64,11 +64,14 @@ export default async function PortalTasksPage() {
{projectNames.get(task.projectId!)}
+ {task.description ? (
+
{task.description}
+ ) : null}
- {date ? formatDate(date, locale.locale) : "-"}
+ {date ? formatDate(date, locale.locale) : t("portal.labels.noDate")}
{isDone ?
:
}
diff --git a/components/system/destructive-confirmation.tsx b/components/system/destructive-confirmation.tsx
index 6d664dd..10d587f 100644
--- a/components/system/destructive-confirmation.tsx
+++ b/components/system/destructive-confirmation.tsx
@@ -12,7 +12,7 @@ import {
} from "poyraz-ui/molecules";
type DestructiveConfirmationProps = {
- cancelLabel?: string;
+ cancelLabel: string;
confirmLabel: string;
description: string;
loading?: boolean;
@@ -23,7 +23,7 @@ type DestructiveConfirmationProps = {
};
export function DestructiveConfirmation({
- cancelLabel = "Vazgeç",
+ cancelLabel,
confirmLabel,
description,
loading = false,
diff --git a/components/system/feedback-state.tsx b/components/system/feedback-state.tsx
index 274c34b..265b3c0 100644
--- a/components/system/feedback-state.tsx
+++ b/components/system/feedback-state.tsx
@@ -45,7 +45,7 @@ export function FeedbackState({ action, description, title, variant }: FeedbackS
);
}
-export function LoadingState({ label = "İçerik yükleniyor" }: { label?: string }) {
+export function LoadingState({ label }: { label: string }) {
return (
{label}
@@ -60,10 +60,10 @@ export function LoadingState({ label = "İçerik yükleniyor" }: { label?: strin
);
}
-export function RetryAction({ onClick }: { onClick: () => void }) {
+export function RetryAction({ label, onClick }: { label: string; onClick: () => void }) {
return (
);
}
diff --git a/components/system/status-badge.tsx b/components/system/status-badge.tsx
index 5d8036f..f71da78 100644
--- a/components/system/status-badge.tsx
+++ b/components/system/status-badge.tsx
@@ -2,38 +2,39 @@ import { Badge } from "poyraz-ui/atoms";
import type { ComponentProps } from "react";
const statusPresentation = {
- accepted: { label: "Kabul edildi", variant: "success" },
- active: { label: "Aktif", variant: "success" },
- archived: { label: "Arşivlendi", variant: "outline" },
- cancelled: { label: "İptal edildi", variant: "outline" },
- completed: { label: "Tamamlandı", variant: "success" },
- done: { label: "Tamamlandı", variant: "success" },
- draft: { label: "Taslak", variant: "secondary" },
- expired: { label: "Süresi doldu", variant: "destructive" },
- in_progress: { label: "Devam ediyor", variant: "info" },
- overdue: { label: "Gecikmiş", variant: "destructive" },
- paid: { label: "Ödendi", variant: "success" },
- paused: { label: "Duraklatıldı", variant: "warning" },
- pending: { label: "Bekliyor", variant: "warning" },
- planned: { label: "Planlandı", variant: "secondary" },
- planning: { label: "Planlanıyor", variant: "secondary" },
- rejected: { label: "Reddedildi", variant: "destructive" },
- revoked: { label: "İptal edildi", variant: "destructive" },
- sent: { label: "Gönderildi", variant: "info" },
- todo: { label: "Yapılacak", variant: "secondary" },
-} as const satisfies Record["variant"]> }>;
+ accepted: { labelKey: "status.common.accepted", variant: "success" },
+ active: { labelKey: "status.common.active", variant: "success" },
+ archived: { labelKey: "status.common.archived", variant: "outline" },
+ cancelled: { labelKey: "status.common.cancelled", variant: "outline" },
+ completed: { labelKey: "status.common.completed", variant: "success" },
+ done: { labelKey: "status.common.done", variant: "success" },
+ draft: { labelKey: "status.common.draft", variant: "secondary" },
+ expired: { labelKey: "status.common.expired", variant: "destructive" },
+ in_progress: { labelKey: "status.common.inProgress", variant: "info" },
+ overdue: { labelKey: "status.common.overdue", variant: "destructive" },
+ paid: { labelKey: "status.common.paid", variant: "success" },
+ paused: { labelKey: "status.common.paused", variant: "warning" },
+ pending: { labelKey: "status.common.pending", variant: "warning" },
+ planned: { labelKey: "status.common.planned", variant: "secondary" },
+ planning: { labelKey: "status.common.planning", variant: "secondary" },
+ rejected: { labelKey: "status.common.rejected", variant: "destructive" },
+ revoked: { labelKey: "status.common.revoked", variant: "destructive" },
+ sent: { labelKey: "status.common.sent", variant: "info" },
+ todo: { labelKey: "status.common.todo", variant: "secondary" },
+} as const satisfies Record["variant"]> }>;
export type NetaStatus = keyof typeof statusPresentation;
type StatusBadgeProps = Omit, "children" | "variant"> & {
+ label: string;
status: NetaStatus;
};
-export function StatusBadge({ status, ...props }: StatusBadgeProps) {
+export function StatusBadge({ label, status, ...props }: StatusBadgeProps) {
const presentation = statusPresentation[status];
return (
- {presentation.label}
+ {label}
);
}
diff --git a/locales/en/index.ts b/locales/en/index.ts
index 98c70e3..09dc5d5 100644
--- a/locales/en/index.ts
+++ b/locales/en/index.ts
@@ -51,6 +51,11 @@ export const enCatalog = {
"invite.expired": "This invitation has expired. Ask the freelancer for a new link.",
"invite.accepted": "This invitation was already used. You can sign in with your account.",
"invite.revoked": "This invitation was revoked. Ask the freelancer for a new link.",
+ "invite.unavailable": "This invitation is no longer available. Ask the freelancer for a new link.",
+ "invite.notFound": "The invitation link is invalid or could not be found.",
+ "invite.invalidInput": "The invitation details are invalid. Check your name and password.",
+ "invite.emailRegistered": "An account already exists with this email address.",
+ "invite.clientLinked": "A portal account already exists for this client.",
"invite.success": "Your portal account has been created. You can sign in now.",
"language": "Language",
"marketing.headline": "Manage freelance work, clients and finance in one place.",
@@ -859,9 +864,9 @@ export const enCatalog = {
"portal.appearance.brandingNotice": "Logo, color and brand settings are managed by the freelancer; only your personal theme preference changes here.",
"portal.appearance.autoSave": "Saved automatically on selection",
"portal.profile.title": "Profile",
- "portal.profile.description": "Profile editing will be completed in the next phase. This page prepares the route and authorization boundary now.",
+ "portal.profile.description": "Manage the name and profile photo displayed in your portal account.",
"portal.security.title": "Security",
- "portal.security.description": "Password and session security controls will be completed in the next phase. This page is isolated from owner-only security settings.",
+ "portal.security.description": "Change your portal account password and securely sign out other sessions.",
"languages.title": "Languages",
"languages.description": "Manage instance languages, the default language, completion and usage impact.",
"languages.actions.add": "Add language",
@@ -1117,8 +1122,12 @@ export const enCatalog = {
"actions.newRequest": "Create new request",
"labels.delivery": "Delivery",
"labels.deadline": "Due",
+ "labels.noDate": "No date",
+ "labels.openProject": "Open project",
+ "labels.openProjectCta": "Open project →",
"labels.progress": "Progress",
"labels.project": "Project",
+ "labels.percent": "{value}%",
"labels.remainingQuota": "Remaining quota",
"labels.unlimited": "Unlimited",
"tabs.overview": "Overview",
@@ -1135,6 +1144,17 @@ export const enCatalog = {
"revision.descriptionPlaceholder": "Could this section be blue? Also, let's update the copy...",
"revision.success": "Your revision request has been sent.",
"revision.error": "Could not create revision request.",
+ "revision.errors.descriptionRequired": "Revision description is required.",
+ "planTypes.assets": "Visual assets",
+ "planTypes.audience": "Target audience",
+ "planTypes.color_palette": "Color palette",
+ "planTypes.design_system": "Design system",
+ "planTypes.goal": "Goal",
+ "planTypes.notes": "Notes",
+ "planTypes.overview": "Overview",
+ "planTypes.problem": "Problem solved",
+ "planTypes.scope": "Scope",
+ "planTypes.typography": "Typography",
"status.project.active": "Active",
"status.project.completed": "Completed",
"status.project.waiting": "Waiting",
@@ -1147,6 +1167,25 @@ export const enCatalog = {
"status.revision.rejected": "Rejected",
},
status: {
+ "common.accepted": "Accepted",
+ "common.active": "Active",
+ "common.archived": "Archived",
+ "common.cancelled": "Cancelled",
+ "common.completed": "Completed",
+ "common.done": "Done",
+ "common.draft": "Draft",
+ "common.expired": "Expired",
+ "common.inProgress": "In progress",
+ "common.overdue": "Overdue",
+ "common.paid": "Paid",
+ "common.paused": "Paused",
+ "common.pending": "Pending",
+ "common.planned": "Planned",
+ "common.planning": "Planning",
+ "common.rejected": "Rejected",
+ "common.revoked": "Revoked",
+ "common.sent": "Sent",
+ "common.todo": "To do",
"project.active": "Active",
"project.completed": "Completed",
"task.todo": "To do",
diff --git a/locales/tr/index.ts b/locales/tr/index.ts
index 8085dec..f7278e8 100644
--- a/locales/tr/index.ts
+++ b/locales/tr/index.ts
@@ -51,6 +51,11 @@ export const trCatalog = {
"invite.expired": "Bu davetin süresi dolmuş. Freelancer'dan yeni bir bağlantı istemelisin.",
"invite.accepted": "Bu davet daha önce kullanılmış. Hesabınla giriş yapabilirsin.",
"invite.revoked": "Bu davet iptal edilmiş. Freelancer'dan yeni bir bağlantı istemelisin.",
+ "invite.unavailable": "Bu davet artık kullanılamıyor. Freelancer'dan yeni bir bağlantı istemelisin.",
+ "invite.notFound": "Davet bağlantısı geçersiz veya bulunamadı.",
+ "invite.invalidInput": "Davet bilgileri geçersiz. Lütfen adını ve şifreni kontrol et.",
+ "invite.emailRegistered": "Bu e-posta adresiyle kayıtlı bir hesap zaten var.",
+ "invite.clientLinked": "Bu müşteri için portal hesabı zaten mevcut.",
"invite.success": "Portal hesabın oluşturuldu. Şimdi giriş yapabilirsin.",
"language": "Dil",
"marketing.headline": "Freelancer işlerini, müşterilerini ve finansını tek yerde yönet.",
@@ -859,9 +864,9 @@ export const trCatalog = {
"portal.appearance.brandingNotice": "Logo, renk ve marka ayarları freelancer tarafından yönetilir; burada yalnız kişisel tema tercihiniz değişir.",
"portal.appearance.autoSave": "Seçince otomatik kaydedilir",
"portal.profile.title": "Profil",
- "portal.profile.description": "Profil düzenleme bir sonraki fazda tamamlanacak. Bu sayfa route ve yetki sınırını şimdiden hazırlar.",
+ "portal.profile.description": "Portal hesabınızda görünen adınızı ve profil fotoğrafınızı yönetin.",
"portal.security.title": "Güvenlik",
- "portal.security.description": "Şifre ve oturum güvenliği kontrolleri bir sonraki fazda tamamlanacak. Bu sayfa owner-only güvenlik ayarlarından izoledir.",
+ "portal.security.description": "Portal hesabınızın şifresini değiştirin ve diğer oturumları güvenli şekilde kapatın.",
"languages.title": "Diller",
"languages.description": "Instance dillerini, varsayılan dili, tamamlanma durumunu ve kullanım etkilerini yönetin.",
"languages.actions.add": "Dil ekle",
@@ -1117,8 +1122,12 @@ export const trCatalog = {
"actions.newRequest": "Yeni Talep Oluştur",
"labels.delivery": "Teslim",
"labels.deadline": "Son Teslim",
+ "labels.noDate": "Tarih yok",
+ "labels.openProject": "Projeyi aç",
+ "labels.openProjectCta": "Projeyi aç →",
"labels.progress": "İlerleme",
"labels.project": "Proje",
+ "labels.percent": "%{value}",
"labels.remainingQuota": "Kalan Hak",
"labels.unlimited": "Sınırsız",
"tabs.overview": "Genel Bakış",
@@ -1135,6 +1144,17 @@ export const trCatalog = {
"revision.descriptionPlaceholder": "Şu kısmın rengi mavi olabilir mi? Ayrıca metinleri güncelleyelim...",
"revision.success": "Revizyon talebiniz başarıyla iletildi.",
"revision.error": "Revizyon talebi oluşturulamadı.",
+ "revision.errors.descriptionRequired": "Revizyon açıklaması zorunludur.",
+ "planTypes.assets": "Görsel varlıklar",
+ "planTypes.audience": "Hedef kitle",
+ "planTypes.color_palette": "Renk paleti",
+ "planTypes.design_system": "Tasarım sistemi",
+ "planTypes.goal": "Amaç",
+ "planTypes.notes": "Notlar",
+ "planTypes.overview": "Genel bakış",
+ "planTypes.problem": "Çözdüğü problem",
+ "planTypes.scope": "Kapsam",
+ "planTypes.typography": "Tipografi",
"status.project.active": "Aktif",
"status.project.completed": "Tamamlandı",
"status.project.waiting": "Beklemede",
@@ -1147,6 +1167,25 @@ export const trCatalog = {
"status.revision.rejected": "Reddedildi",
},
status: {
+ "common.accepted": "Kabul edildi",
+ "common.active": "Aktif",
+ "common.archived": "Arşivlendi",
+ "common.cancelled": "İptal edildi",
+ "common.completed": "Tamamlandı",
+ "common.done": "Tamamlandı",
+ "common.draft": "Taslak",
+ "common.expired": "Süresi doldu",
+ "common.inProgress": "Devam ediyor",
+ "common.overdue": "Gecikmiş",
+ "common.paid": "Ödendi",
+ "common.paused": "Duraklatıldı",
+ "common.pending": "Bekliyor",
+ "common.planned": "Planlandı",
+ "common.planning": "Planlanıyor",
+ "common.rejected": "Reddedildi",
+ "common.revoked": "İptal edildi",
+ "common.sent": "Gönderildi",
+ "common.todo": "Yapılacak",
"project.active": "Aktif",
"project.completed": "Tamamlandı",
"task.todo": "Yapılacak",