Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,9 @@
"auth_terms_of_service": "Terms of Service",
"auth_privacy_policy": "Privacy Policy",
"auth_cookie_policy": "Cookie Policy",
"auth_all_three_required": "All three agreements are required to register.",
"auth_eula": "End User License Agreement",
"auth_open_link_first": "Open each policy link to enable its checkbox.",
"auth_all_three_required": "All agreements are required to register.",
"auth_all_fields_required": "All fields are required.",
"auth_must_agree_all_policies": "You must agree to all required policies to register.",
"auth_account_exists": "An account with this email already exists.",
Expand Down
4 changes: 3 additions & 1 deletion messages/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,9 @@
"auth_terms_of_service": "利用規約に同意する",
"auth_privacy_policy": "プライバシーポリシーに同意する",
"auth_cookie_policy": "Cookie ポリシーに同意する",
"auth_all_three_required": "登録には 3 つすべてへの同意が必要です。",
"auth_eula": "エンドユーザー使用許諾契約に同意する",
"auth_open_link_first": "各ポリシーのリンクを開くとチェックボックスが有効になります。",
"auth_all_three_required": "登録にはすべての同意が必要です。",
"auth_all_fields_required": "すべての項目を入力してください。",
"auth_must_agree_all_policies": "登録するには必須ポリシーすべてに同意してください。",
"auth_account_exists": "このメールアドレスのアカウントはすでに存在します。",
Expand Down
10 changes: 5 additions & 5 deletions src/routes/auth/create-account/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ export const actions: Actions = {
const company = readNonEmptyString(data.get('company'));
const recaptchaToken = readNonEmptyString(data.get('recaptchaToken'));

const agreedTerms = data.get('agreedTerms') === 'true';
const agreedPrivacy = data.get('agreedPrivacy') === 'true';
const agreedCookies = data.get('agreedCookies') === 'true';
const agreedTerms = data.get('agreedTerms') === 'true';
const agreedEula = data.get('agreedEula') === 'true';

// ── Validation ─────────────────────────────────────────────
if (!firstName || !lastName || !email || !password || !confirmPassword || !company) {
Expand Down Expand Up @@ -58,7 +58,7 @@ export const actions: Actions = {
});
}

if (!agreedTerms || !agreedPrivacy || !agreedCookies) {
if (!agreedPrivacy || !agreedTerms || !agreedEula) {
return fail(400, {
message: m.auth_must_agree_all_policies(),
firstName,
Expand Down Expand Up @@ -95,9 +95,9 @@ export const actions: Actions = {
first_name: firstName,
last_name: lastName,
company,
agreed_terms: true,
agreed_privacy: true,
agreed_cookies: true
agreed_terms: true,
agreed_eula: true
}
}
});
Expand Down
14 changes: 7 additions & 7 deletions src/routes/auth/create-account/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,17 @@
let password: string = $state('');
let confirmPassword: string = $state('');

let agreedTerms: boolean = $state(false);
let agreedPrivacy: boolean = $state(false);
let agreedCookies: boolean = $state(false);
let agreedTerms: boolean = $state(false);
let agreedEula: boolean = $state(false);

let passwordValidation: IPasswordValidationResult = $derived(isStrongPassword(password));

let passwordsMatch: boolean = $derived(
password.length > 0 && confirmPassword.length > 0 && password === confirmPassword
);

let allConsentsGiven: boolean = $derived(agreedTerms && agreedPrivacy && agreedCookies);
let allConsentsGiven: boolean = $derived(agreedPrivacy && agreedTerms && agreedEula);
let redirectPath = $derived(readRedirectPath(page.url.searchParams, ''));

let canSubmit: boolean = $derived(
Expand Down Expand Up @@ -123,9 +123,9 @@
return;
}

formData.set('agreedTerms', String(agreedTerms));
formData.set('agreedPrivacy', String(agreedPrivacy));
formData.set('agreedCookies', String(agreedCookies));
formData.set('agreedTerms', String(agreedTerms));
formData.set('agreedEula', String(agreedEula));

return async ({ result }) => {
try {
Expand Down Expand Up @@ -210,9 +210,9 @@
</label>

<CreateAccountConsentFields
bind:agreedTerms
bind:agreedPrivacy
bind:agreedCookies
bind:agreedTerms
bind:agreedEula
{allConsentsGiven}
/>

Expand Down
55 changes: 43 additions & 12 deletions src/routes/auth/create-account/CreateAccountConsentFields.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,63 +2,83 @@
import { m } from '$lib/paraglide/messages.js';

interface Props {
agreedCookies: boolean;
agreedPrivacy: boolean;
agreedTerms: boolean;
agreedEula: boolean;
allConsentsGiven: boolean;
}

let {
agreedCookies = $bindable(false),
agreedPrivacy = $bindable(false),
agreedTerms = $bindable(false),
agreedEula = $bindable(false),
allConsentsGiven
}: Props = $props();

// The matching checkbox stays disabled until its policy link has been opened.
let visitedPrivacy = $state(false);
let visitedTerms = $state(false);
let visitedEula = $state(false);
</script>

<fieldset class="consent-group">
<legend class="field-label">{m.auth_required_agreements_label()}</legend>

<p class="consent-note">{m.auth_open_link_first()}</p>

<label class="consent-item">
<input type="checkbox" bind:checked={agreedTerms} class="consent-checkbox" />
<input
type="checkbox"
bind:checked={agreedPrivacy}
disabled={!visitedPrivacy}
class="consent-checkbox"
/>
<span>
{m.auth_agree_to()}
<a
href="https://app.cropwatch.io/legal/EULA"
href="https://www.cropwatch.io/legal/privacy-policy"
target="_blank"
rel="noopener noreferrer"
class="auth-link">{m.auth_terms_of_service()}</a
class="auth-link"
onclick={() => (visitedPrivacy = true)}>{m.auth_privacy_policy()}</a
>
</span>
</label>

<label class="consent-item">
<input type="checkbox" bind:checked={agreedPrivacy} class="consent-checkbox" />
<input
type="checkbox"
bind:checked={agreedTerms}
disabled={!visitedTerms}
class="consent-checkbox"
/>
<span>
{m.auth_agree_to()}
<a
href="https://app.cropwatch.io/legal/privacy-policy"
href="https://www.cropwatch.io/legal/terms-of-service"
target="_blank"
rel="noopener noreferrer"
class="auth-link">{m.auth_privacy_policy()}</a
class="auth-link"
onclick={() => (visitedTerms = true)}>{m.auth_cookie_policy()}</a
>
</span>
</label>

<label class="consent-item">
<input type="checkbox" bind:checked={agreedCookies} class="consent-checkbox" />
<input type="checkbox" bind:checked={agreedEula} disabled={!visitedEula} class="consent-checkbox" />
<span>
{m.auth_agree_to()}
<a
href="https://app.cropwatch.io/legal/cookie-policy"
href="https://www.cropwatch.io/legal/EULA"
target="_blank"
rel="noopener noreferrer"
class="auth-link">{m.auth_cookie_policy()}</a
class="auth-link"
onclick={() => (visitedEula = true)}>{m.auth_eula()}</a
>
</span>
</label>

{#if !allConsentsGiven && (agreedTerms || agreedPrivacy || agreedCookies)}
{#if !allConsentsGiven && (agreedPrivacy || agreedTerms || agreedEula)}
<p class="consent-hint">{m.auth_all_three_required()}</p>
{/if}
</fieldset>
Expand All @@ -77,6 +97,12 @@
padding: 0 0.4rem;
}

.consent-note {
margin: 0;
font-size: 0.82rem;
color: rgb(160 180 205);
}

.consent-item {
display: flex;
align-items: flex-start;
Expand All @@ -95,6 +121,11 @@
flex-shrink: 0;
}

.consent-checkbox:disabled {
cursor: not-allowed;
opacity: 0.45;
}

.consent-hint {
margin: 0;
font-size: 0.82rem;
Expand Down
Loading