feat: project edit page add translations on config step
This commit is contained in:
@@ -56,19 +56,21 @@
|
||||
<!-- Page Header -->
|
||||
<div class="space-y-4">
|
||||
<h1 class="text-[40px]/12 font-bold text-black">
|
||||
{$t("wizard.configuration.title")}
|
||||
{$t("pages.project.edit.configuration.title")}
|
||||
</h1>
|
||||
<p class="text-content text-base font-normal">{$t("wizard.configuration.subtitle")}</p>
|
||||
<p class="text-content text-base font-normal">
|
||||
{$t("pages.project.edit.configuration.subtitle")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Languages Section -->
|
||||
<div class="space-y-6">
|
||||
<div class="space-y-4">
|
||||
<h2 class="text-2xl font-bold text-black">
|
||||
{$t("wizard.configuration.languages.title")}
|
||||
{$t("pages.project.edit.configuration.languages.title")}
|
||||
</h2>
|
||||
<p class="text-content text-base font-normal">
|
||||
{$t("wizard.configuration.languages.description")}
|
||||
{$t("pages.project.edit.configuration.languages.description")}
|
||||
</p>
|
||||
</div>
|
||||
<LanguageSelector languages={configuration.languages} onChange={handleLanguagesChange} />
|
||||
@@ -78,25 +80,20 @@
|
||||
<div class="space-y-6">
|
||||
<div class="space-y-4">
|
||||
<h2 class="text-2xl font-bold text-black">
|
||||
{$t("wizard.configuration.rounds.title")}
|
||||
{$t("pages.project.edit.configuration.rounds.title")}
|
||||
</h2>
|
||||
<p class="text-content text-base font-normal">
|
||||
{$t("wizard.configuration.rounds.description")}
|
||||
{$t("pages.project.edit.configuration.rounds.description")}
|
||||
</p>
|
||||
</div>
|
||||
<RoundSelector bind:rounds={configuration.fundingRounds} onChange={handleRoundsChange} />
|
||||
</div>
|
||||
|
||||
<!-- Continue Button -->
|
||||
<div class="flex justify-start">
|
||||
<Button
|
||||
kind="secondary"
|
||||
size="md"
|
||||
onclick={handleContinue}
|
||||
data-testid="config-continue-btn"
|
||||
>
|
||||
<div class="mb- flex justify-start">
|
||||
<Button kind="secondary" size="md" onclick={handleContinue}>
|
||||
{#snippet children()}
|
||||
{$t("wizard.configuration.continue")}
|
||||
{$t("pages.project.edit.configuration.continue")}
|
||||
{/snippet}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -133,13 +133,13 @@
|
||||
<Select
|
||||
bind:value={primaryLanguage}
|
||||
id="primary-language-{primaryLanguage}"
|
||||
labelText={$t("wizard.configuration.languages.primaryLabel")}
|
||||
labelText={$t("pages.project.edit.configuration.languages.primaryLabel")}
|
||||
required={true}
|
||||
error={showError ? errors.languages : undefined}
|
||||
onBlur={handleBlur}
|
||||
onChange={handlePrimaryChange}
|
||||
>
|
||||
<option value="">{$t("wizard.configuration.languages.selectPlaceholder")}</option>
|
||||
<option value="">{$t("common.select")}</option>
|
||||
{#each availableLanguages as lang}
|
||||
<option value={lang.code} disabled={isLanguageDisabled(lang.code, primaryLanguage)}
|
||||
>{lang.name}</option
|
||||
@@ -154,12 +154,10 @@
|
||||
<Select
|
||||
bind:value={secondaryLanguages[index]}
|
||||
id="secondary-language-{index}-{secondary}"
|
||||
labelText={$t("wizard.configuration.languages.secondaryLabel")}
|
||||
labelText={$t("pages.project.edit.configuration.languages.secondaryLabel")}
|
||||
onChange={(value) => handleSecondaryChange(index, value)}
|
||||
>
|
||||
<option value=""
|
||||
>{$t("wizard.configuration.languages.selectPlaceholder")}</option
|
||||
>
|
||||
<option value="">{$t("common.select")}</option>
|
||||
{#each availableLanguages as lang}
|
||||
<option
|
||||
value={lang.code}
|
||||
@@ -175,7 +173,7 @@
|
||||
onclick={() => removeSecondaryLanguage(index)}
|
||||
data-testid="language-remove-btn-{index}"
|
||||
class="hover:bg-light-muted text-secondary hover:text-tertiary rounded-lg p-2 transition-colors"
|
||||
aria-label={$t("wizard.configuration.languages.removeButton")}
|
||||
aria-label={$t("common.remove")}
|
||||
>
|
||||
<svg
|
||||
class="h-5 w-5"
|
||||
@@ -206,6 +204,6 @@
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 8v8m-4-4h8" />
|
||||
</svg>
|
||||
{$t("wizard.configuration.languages.addButton")}
|
||||
{$t("pages.project.edit.configuration.languages.addButton")}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
checked={rounds === 1}
|
||||
onchange={() => handleChange(1)}
|
||||
id="round-1-radio"
|
||||
label={$t("wizard.configuration.rounds.option1")}
|
||||
label={$t("pages.project.edit.configuration.rounds.option1")}
|
||||
/>
|
||||
|
||||
<!-- 2 Rounds Option -->
|
||||
@@ -49,6 +49,6 @@
|
||||
checked={rounds === 2}
|
||||
onchange={() => handleChange(2)}
|
||||
id="round-2-radio"
|
||||
label={$t("wizard.configuration.rounds.option2")}
|
||||
label={$t("pages.project.edit.configuration.rounds.option2")}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -52,12 +52,12 @@
|
||||
|
||||
// Define the six wizard steps (reactive to language changes)
|
||||
const steps = $derived<Tab[]>([
|
||||
{ id: 1, label: $t("pages.project.edit.tabs.configuration.title") },
|
||||
{ id: 2, label: $t("pages.project.edit.tabs.campaign.title") },
|
||||
{ id: 3, label: $t("pages.project.edit.tabs.rewards.title") },
|
||||
{ id: 4, label: $t("pages.project.edit.tabs.collaborations.title") },
|
||||
{ id: 5, label: $t("pages.project.edit.tabs.budget.title") },
|
||||
{ id: 6, label: $t("pages.project.edit.tabs.aboutYou.title") },
|
||||
{ id: 1, label: $t("pages.project.edit.tabs.configuration") },
|
||||
{ id: 2, label: $t("pages.project.edit.tabs.campaign") },
|
||||
{ id: 3, label: $t("pages.project.edit.tabs.rewards") },
|
||||
{ id: 4, label: $t("pages.project.edit.tabs.collaborations") },
|
||||
{ id: 5, label: $t("pages.project.edit.tabs.budget") },
|
||||
{ id: 6, label: $t("pages.project.edit.tabs.aboutYou") },
|
||||
]);
|
||||
|
||||
// Reactive values from store
|
||||
@@ -95,131 +95,131 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="mx-auto max-w-6xl">
|
||||
<!-- Storage Error Alert -->
|
||||
{#if $persistenceError}
|
||||
<div
|
||||
class="bg-tertiary/10 border-tertiary mb-6 rounded-lg border p-4"
|
||||
role="alert"
|
||||
aria-live="assertive"
|
||||
>
|
||||
<div class="flex items-start gap-3">
|
||||
<svg
|
||||
class="text-tertiary h-5 w-5 flex-shrink-0"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<div class="flex-1">
|
||||
<h3 class="text-secondary text-sm font-semibold">
|
||||
{$t("wizard.errors.storage.title")}
|
||||
</h3>
|
||||
<p class="text-tertiary mt-1 text-sm">
|
||||
{#if $persistenceError === "storage_quota_exceeded"}
|
||||
{$t("wizard.errors.storage.quota_exceeded")}
|
||||
{:else}
|
||||
{$t("wizard.errors.storage.save_failed")}
|
||||
{/if}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="text-tertiary hover:text-secondary flex-shrink-0"
|
||||
onclick={() => persistenceError.set(null)}
|
||||
aria-label={$t("wizard.errors.storage.close")}
|
||||
>
|
||||
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20">
|
||||
<div class="wrapper">
|
||||
<div class="p-10 pb-20">
|
||||
<!-- Storage Error Alert -->
|
||||
{#if $persistenceError}
|
||||
<div
|
||||
class="bg-tertiary/10 border-tertiary mb-6 rounded-lg border p-4"
|
||||
role="alert"
|
||||
aria-live="assertive"
|
||||
>
|
||||
<div class="flex items-start gap-3">
|
||||
<svg
|
||||
class="text-tertiary h-5 w-5 flex-shrink-0"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="flex-1">
|
||||
<h3 class="text-secondary text-sm font-semibold">
|
||||
{$t("wizard.errors.storage.title")}
|
||||
</h3>
|
||||
<p class="text-tertiary mt-1 text-sm">
|
||||
{#if $persistenceError === "storage_quota_exceeded"}
|
||||
{$t("wizard.errors.storage.quota_exceeded")}
|
||||
{:else}
|
||||
{$t("wizard.errors.storage.save_failed")}
|
||||
{/if}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="text-tertiary hover:text-secondary flex-shrink-0"
|
||||
onclick={() => persistenceError.set(null)}
|
||||
aria-label={$t("wizard.errors.storage.close")}
|
||||
>
|
||||
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<!-- Header with title and action buttons -->
|
||||
<div
|
||||
class="bg-soft-purple border-variant1 mb-6 flex items-center justify-between gap-4 rounded-3xl border px-6 py-4 shadow-sm"
|
||||
>
|
||||
<!-- Left section: Icon + Title/Subtitle -->
|
||||
<div class="flex flex-1 items-center gap-4">
|
||||
<!-- Edit icon (rotated 180°) -->
|
||||
<div class="flex shrink-0 items-center justify-center">
|
||||
<div class="rotate-180">
|
||||
<EditIcon width="24" height="24" />
|
||||
<!-- Header with title and action buttons -->
|
||||
<div
|
||||
class="bg-soft-purple border-variant1 mb-6 flex items-center justify-between gap-4 rounded-3xl border px-6 py-4 shadow-sm"
|
||||
>
|
||||
<!-- Left section: Icon + Title/Subtitle -->
|
||||
<div class="flex flex-1 items-center gap-4">
|
||||
<!-- Edit icon (rotated 180°) -->
|
||||
<div class="flex shrink-0 items-center justify-center">
|
||||
<div class="rotate-180">
|
||||
<EditIcon width="24" height="24" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Title and subtitle column -->
|
||||
<div class="flex min-w-0 flex-1 flex-col justify-center">
|
||||
<input
|
||||
type="text"
|
||||
value={title}
|
||||
oninput={(e) => onTitleChange?.(e.currentTarget.value)}
|
||||
placeholder={$t("system.loading")}
|
||||
class="w-full border-0 bg-transparent pb-0 text-2xl leading-8 font-bold text-black focus:ring-0 focus:outline-none"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={subtitle}
|
||||
oninput={(e) => onSubtitleChange?.(e.currentTarget.value)}
|
||||
placeholder={$t("system.loading")}
|
||||
class="w-full border-0 bg-transparent pt-0 text-sm leading-6 font-normal text-black focus:ring-0 focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Title and subtitle column -->
|
||||
<div class="flex min-w-0 flex-1 flex-col justify-center">
|
||||
<input
|
||||
type="text"
|
||||
value={title}
|
||||
oninput={(e) => onTitleChange?.(e.currentTarget.value)}
|
||||
placeholder={$t("wizard.header.titlePlaceholder")}
|
||||
class="w-full border-0 bg-transparent pb-0 text-2xl leading-8 font-bold text-black focus:ring-0 focus:outline-none"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={subtitle}
|
||||
oninput={(e) => onSubtitleChange?.(e.currentTarget.value)}
|
||||
placeholder={$t("wizard.header.subtitlePlaceholder")}
|
||||
class="w-full border-0 bg-transparent pt-0 text-sm leading-6 font-normal text-black focus:ring-0 focus:outline-none"
|
||||
/>
|
||||
<!-- Save success Toast -->
|
||||
{#if showSuccessToast}
|
||||
<Toast variant="success" bind:showToast={showSuccessToast}
|
||||
>{$t("wizard.successToast")}</Toast
|
||||
>
|
||||
{/if}
|
||||
|
||||
<!-- Right section: Action Buttons -->
|
||||
<div class="flex shrink-0 items-center gap-[16px]">
|
||||
<Button kind="ghost" size="md" disabled={true}>
|
||||
<EyeIcon width="20" height="20" />
|
||||
{$t("common.preview")}
|
||||
</Button>
|
||||
<Button
|
||||
kind="secondary"
|
||||
size="md"
|
||||
onclick={handleSave}
|
||||
disabled={$hasUnsavedChanges ? false : true}
|
||||
>
|
||||
{$t("common.save")}
|
||||
</Button>
|
||||
<Button
|
||||
class="disabled:pointer-events-none disabled:opacity-24"
|
||||
kind="primary"
|
||||
size="md"
|
||||
onclick={handlePublish}
|
||||
disabled={currentStep !== 7}
|
||||
>
|
||||
{$t("common.publish")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Save success Toast -->
|
||||
{#if showSuccessToast}
|
||||
<Toast variant="success" bind:showToast={showSuccessToast}
|
||||
>{$t("wizard.successToast")}</Toast
|
||||
>
|
||||
{/if}
|
||||
<!-- Tab Navigation -->
|
||||
<div class="mb-8">
|
||||
<TabNavigation tabs={steps} currentTab={currentStep} onTabClick={handleTabClick} />
|
||||
</div>
|
||||
|
||||
<!-- Right section: Action Buttons -->
|
||||
<div class="flex shrink-0 items-center gap-[16px]">
|
||||
<Button kind="ghost" size="md" disabled={true} data-testid="wizard-preview-btn">
|
||||
<EyeIcon width="20" height="20" />
|
||||
{$t("wizard.buttons.preview")}
|
||||
</Button>
|
||||
<Button
|
||||
kind="secondary"
|
||||
size="md"
|
||||
onclick={handleSave}
|
||||
disabled={$hasUnsavedChanges ? false : true}
|
||||
data-testid="wizard-save-btn"
|
||||
>
|
||||
{$t("wizard.buttons.save")}
|
||||
</Button>
|
||||
<Button
|
||||
class="disabled:pointer-events-none disabled:opacity-24"
|
||||
kind="primary"
|
||||
size="md"
|
||||
onclick={handlePublish}
|
||||
data-testid="wizard-publish-btn"
|
||||
disabled={currentStep !== 7}
|
||||
>
|
||||
{$t("wizard.buttons.publish")}
|
||||
</Button>
|
||||
<!-- Step Content -->
|
||||
<div class="min-h-100">
|
||||
{@render currentStepContent()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab Navigation -->
|
||||
<div class="mb-8">
|
||||
<TabNavigation tabs={steps} currentTab={currentStep} onTabClick={handleTabClick} />
|
||||
</div>
|
||||
|
||||
<!-- Step Content -->
|
||||
<div class="min-h-100">
|
||||
{@render currentStepContent()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+29
-18
@@ -4,7 +4,12 @@
|
||||
"greeting": "Hola",
|
||||
"farewell": "Adiós",
|
||||
"donate": "Donar",
|
||||
"donateAmount": "Dona {{ amount }}"
|
||||
"donateAmount": "Dona {{ amount }}",
|
||||
"save": "Guardar",
|
||||
"publish": "Publicar",
|
||||
"preview": "Vista previa",
|
||||
"select": "Elige una opción",
|
||||
"remove": "Quitar"
|
||||
},
|
||||
"domain": {
|
||||
"_": "Business concepts (project, reward, contribution, etc.)",
|
||||
@@ -25,24 +30,30 @@
|
||||
"project": {
|
||||
"edit": {
|
||||
"tabs": {
|
||||
"configuration": {
|
||||
"title": "Configuración"
|
||||
"configuration": "Configuración",
|
||||
"campaign": "Campaña",
|
||||
"rewards": "Recompensas",
|
||||
"collaborations": "Colaboraciones",
|
||||
"budget": "Presupuesto",
|
||||
"aboutYou": "Sobre ti"
|
||||
},
|
||||
"configuration": {
|
||||
"title": "Configuración",
|
||||
"subtitle": "Configura los datos básicos de tu campaña",
|
||||
"languages": {
|
||||
"title": "Idiomas de la campaña",
|
||||
"description": "Cuáles son los idiomas en los que publicarás el contenido de la campaña",
|
||||
"primaryLabel": "Idioma principal del contenido",
|
||||
"secondaryLabel": "Idioma secundario del contenido",
|
||||
"addButton": "Añadir idioma"
|
||||
},
|
||||
"campaign": {
|
||||
"title": "Campaña"
|
||||
"rounds": {
|
||||
"title": "Elige las rondas que tendrá tu campaña",
|
||||
"description": "La configuración predeterminada son 40 días cada ronda, puedes solicitar modificaciones a tu asesor si tu proyecto es seleccionado",
|
||||
"option1": "1 Ronda",
|
||||
"option2": "2 Rondas"
|
||||
},
|
||||
"rewards": {
|
||||
"title": "Recompensas"
|
||||
},
|
||||
"collaborations": {
|
||||
"title": "Colaboraciones"
|
||||
},
|
||||
"budget": {
|
||||
"title": "Presupuesto"
|
||||
},
|
||||
"aboutYou": {
|
||||
"title": "Sobre ti"
|
||||
}
|
||||
"continue": "Continuar con info de campaña"
|
||||
},
|
||||
"rewards": {
|
||||
"edit": "Editar"
|
||||
@@ -56,6 +67,7 @@
|
||||
},
|
||||
"system": {
|
||||
"_": "System messages (errors, notifications, validation, etc.)",
|
||||
"loading": "Cargando...",
|
||||
"notImplemented": "Esta funcionalidad aún no está implementada. Estamos trabajando en ello, ¡gracias por tu paciencia!"
|
||||
},
|
||||
"reward": {
|
||||
@@ -1118,7 +1130,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"loading": "Cargando...",
|
||||
"lang": {
|
||||
"error": {
|
||||
"notAvailable": "El idioma seleccionado \"{{lang}}\" no está disponible para este proyecto. Mostrando contenido en el idioma disponible."
|
||||
|
||||
Reference in New Issue
Block a user