cleaned up the form, added security sign up

This commit is contained in:
Johannes
2025-11-19 17:35:09 +01:00
parent 256a0ec81a
commit 044a657d51
16 changed files with 107 additions and 82 deletions

View File

@@ -1891,8 +1891,9 @@ checksums:
setup/organization/create/no_membership_found: 6d6e792661c79452984dc671a2590847
setup/organization/create/no_membership_found_description: ba067dacf419041c8bcdb51ee6b0125b
setup/organization/create/title: 771924a960b2f7019cf8db55543c0715
setup/signup/create_administrator: e5b7e90150ebecf18a248f50a011bb7f
setup/signup/this_user_has_all_the_power: 1af3a7367d412d17f0f16c0e104b3520
setup/signup/create_administrator: bb44729d41138e400802509641de1d46
setup/signup/receive_security_updates: de5127f5847cdd412906607e1402f48d
setup/signup/security_updates_consent_description: 4643df07f13cec619e7fd91c8f14d93b
templates/address: 5a9a8bc26f90d84c90105690a2eb23a1
templates/address_description: e45b92c5cfff59ae7381e8bfb43b173f
templates/alignment_and_engagement_survey_description: a959f7abf4c7bc55371381a73d3113aa

View File

@@ -2036,7 +2036,8 @@
},
"signup": {
"create_administrator": "Administrator erstellen",
"this_user_has_all_the_power": "Dieser Benutzer hat alle Rechte."
"receive_security_updates": "Sicherheitsupdates",
"security_updates_consent_description": "Nur sicherheitsrelevante Informationen, Datenschutzrichtlinie gilt."
}
},
"templates": {

View File

@@ -2035,8 +2035,9 @@
}
},
"signup": {
"create_administrator": "Create Administrator",
"this_user_has_all_the_power": "This user has all the power."
"create_administrator": "You're the admin!",
"receive_security_updates": "Security updates",
"security_updates_consent_description": "Security relevant information only, Privacy Policy applies."
}
},
"templates": {

View File

@@ -2035,8 +2035,9 @@
}
},
"signup": {
"create_administrator": "Crear administrador",
"this_user_has_all_the_power": "Este usuario tiene todo el poder."
"create_administrator": "¡Eres el administrador!",
"receive_security_updates": "Actualizaciones de seguridad",
"security_updates_consent_description": "Solo información relevante para la seguridad, se aplica la política de privacidad."
}
},
"templates": {

View File

@@ -2036,7 +2036,8 @@
},
"signup": {
"create_administrator": "Créer un administrateur",
"this_user_has_all_the_power": "Cet utilisateur a tout le pouvoir."
"receive_security_updates": "Mises à jour de sécurité",
"security_updates_consent_description": "Informations pertinentes pour la sécurité uniquement, la politique de confidentialité s'applique."
}
},
"templates": {

View File

@@ -2036,7 +2036,8 @@
},
"signup": {
"create_administrator": "管理者を作成",
"this_user_has_all_the_power": "このユーザーはすべての権限を持っています。"
"receive_security_updates": "セキュリティアップデート",
"security_updates_consent_description": "セキュリティに関連する情報のみ、プライバシーポリシーが適用されます。"
}
},
"templates": {

View File

@@ -2035,8 +2035,9 @@
}
},
"signup": {
"create_administrator": "Beheerder aanmaken",
"this_user_has_all_the_power": "Deze gebruiker heeft alle macht."
"create_administrator": "Je bent de beheerder!",
"receive_security_updates": "Beveiligingsupdates",
"security_updates_consent_description": "Alleen informatie relevant voor de beveiliging, privacybeleid is van toepassing."
}
},
"templates": {

View File

@@ -2036,7 +2036,8 @@
},
"signup": {
"create_administrator": "Criar Administrador",
"this_user_has_all_the_power": "Esse usuário tem todo o poder."
"receive_security_updates": "Atualizações de segurança",
"security_updates_consent_description": "Apenas informações relevantes de segurança, Política de Privacidade aplicável."
}
},
"templates": {

View File

@@ -2036,7 +2036,8 @@
},
"signup": {
"create_administrator": "Criar Administrador",
"this_user_has_all_the_power": "Este utilizador tem todo o poder."
"receive_security_updates": "Atualizações de segurança",
"security_updates_consent_description": "Apenas informações relevantes para a segurança, aplica-se a Política de Privacidade."
}
},
"templates": {

View File

@@ -2036,7 +2036,8 @@
},
"signup": {
"create_administrator": "Creare Administrator",
"this_user_has_all_the_power": "Acest utilizator are toată puterea."
"receive_security_updates": "Actualizări de securitate",
"security_updates_consent_description": "Doar informații relevante pentru securitate, se aplică Politica de confidențialitate."
}
},
"templates": {

View File

@@ -2036,7 +2036,8 @@
},
"signup": {
"create_administrator": "创建 管理员",
"this_user_has_all_the_power": "此 用户 拥有 所有 权力。"
"receive_security_updates": "安全更新",
"security_updates_consent_description": "仅限安全相关信息,适用隐私政策。"
}
},
"templates": {

View File

@@ -2035,8 +2035,9 @@
}
},
"signup": {
"create_administrator": "建立管理員",
"this_user_has_all_the_power": "此使用者擁有所有權限。"
"create_administrator": "您是管理員",
"receive_security_updates": "安全性更新",
"security_updates_consent_description": "僅限安全相關資訊,適用隱私權政策。"
}
},
"templates": {

View File

@@ -15,8 +15,10 @@ import { createUserAction } from "@/modules/auth/signup/actions";
import { TermsPrivacyLinks } from "@/modules/auth/signup/components/terms-privacy-links";
import { SSOOptions } from "@/modules/ee/sso/components/sso-options";
import { Button } from "@/modules/ui/components/button";
import { Checkbox } from "@/modules/ui/components/checkbox";
import { FormControl, FormError, FormField, FormItem } from "@/modules/ui/components/form";
import { Input } from "@/modules/ui/components/input";
import { Label } from "@/modules/ui/components/label";
import { PasswordInput } from "@/modules/ui/components/password-input";
import { createEmailTokenAction } from "../../../auth/actions";
import { PasswordChecks } from "./password-checks";
@@ -48,6 +50,7 @@ interface SignupFormProps {
samlTenant: string;
samlProduct: string;
turnstileSiteKey?: string;
isAdminAccountCreation?: boolean;
}
export const SignupForm = ({
@@ -69,6 +72,7 @@ export const SignupForm = ({
samlTenant,
samlProduct,
turnstileSiteKey,
isAdminAccountCreation = false,
}: SignupFormProps) => {
const [showLogin, setShowLogin] = useState(false);
const searchParams = useSearchParams();
@@ -76,6 +80,7 @@ export const SignupForm = ({
const inviteToken = searchParams?.get("inviteToken");
const router = useRouter();
const [turnstileToken, setTurnstileToken] = useState<string>();
const [securityUpdatesConsent, setSecurityUpdatesConsent] = useState(true);
const turnstile = useTurnstile();
@@ -102,6 +107,47 @@ export const SignupForm = ({
throw new Error(t("auth.signup.please_verify_captcha"));
}
if (securityUpdatesConsent && isAdminAccountCreation) {
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10 second timeout
const response = await fetch("https://ee.formbricks.com/api/security-updates/consent", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: data.email,
name: data.name,
consent: true,
}),
signal: controller.signal,
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error("API call failed");
}
} catch {
toast.error(
<div>
Security list sign up didn&apos;t work, please sign up here manually.{" "}
<a
href="https://app.formbricks.com/s/cmgeq5ao90n4jvl01s9beewcu"
target="_blank"
rel="noopener noreferrer"
className="underline">
Sign up here
</a>
</div>,
{ duration: 10000 }
);
setSecurityUpdatesConsent(false);
}
}
const createUserResponse = await createUserAction({
name: data.name,
email: data.email,
@@ -224,6 +270,24 @@ export const SignupForm = ({
/>
</div>
<PasswordChecks password={form.watch("password")} />
{showLogin && isAdminAccountCreation && (
<div className="my-2 flex items-start space-x-2 rounded-md border border-slate-200 bg-slate-100 p-2">
<Checkbox
id="security-updates-consent"
checked={securityUpdatesConsent}
onCheckedChange={(checked) => setSecurityUpdatesConsent(checked === true)}
className="mt-0.5"
/>
<div className="flex-1 text-left">
<Label htmlFor="security-updates-consent" className="text-sm">
{t("setup.signup.receive_security_updates")}
</Label>
<p className="mt-1 text-xs text-slate-600">
{t("setup.signup.security_updates_consent_description")}
</p>
</div>
</div>
)}
</div>
)}
{isTurnstileConfigured && showLogin && turnstileSiteKey && (
@@ -279,15 +343,18 @@ export const SignupForm = ({
/>
)}
<TermsPrivacyLinks termsUrl={termsUrl} privacyUrl={privacyUrl} />
<div className="mt-9 text-center text-xs">
<span className="leading-5 text-slate-500">{t("auth.signup.have_an_account")}</span>
<br />
<Link
href={inviteToken ? `/auth/login?callbackUrl=${callbackUrl}` : "/auth/login"}
className="font-semibold text-slate-600 underline hover:text-slate-700">
{t("auth.signup.log_in")}
</Link>
</div>
{!isAdminAccountCreation && (
<div className="mt-9 text-center text-xs">
<span className="leading-5 text-slate-500">{t("auth.signup.have_an_account")}</span>
<br />
<Link
href={inviteToken ? `/auth/login?callbackUrl=${callbackUrl}` : "/auth/login"}
className="font-semibold text-slate-600 underline hover:text-slate-700">
{t("auth.signup.log_in")}
</Link>
</div>
)}
</div>
);
};

View File

@@ -26,7 +26,6 @@ export const TermsPrivacyLinks = ({ termsUrl, privacyUrl }: TermsPrivacyLinksPro
{t("auth.signup.privacy_policy")}
</Link>
)}
<hr className="mx-6 mt-3"></hr>
</div>
);
};

View File

@@ -36,9 +36,7 @@ export const SignupPage = async () => {
const t = await getTranslate();
return (
<div className="flex flex-col items-center">
<h2 className="mb-6 text-xl font-medium">{t("setup.signup.create_administrator")}</h2>
<p className="text-sm text-slate-800">{t("setup.signup.this_user_has_all_the_power")}</p>
<hr className="my-6 w-full border-slate-200" />
<h2 className="mb-2 text-xl font-medium">{t("setup.signup.create_administrator")}</h2>
<SignupForm
webAppUrl={WEBAPP_URL}
termsUrl={TERMS_URL}
@@ -57,6 +55,7 @@ export const SignupPage = async () => {
samlTenant={SAML_TENANT}
samlProduct={SAML_PRODUCT}
turnstileSiteKey={TURNSTILE_SITE_KEY}
isAdminAccountCreation
/>
</div>
);

52
pnpm-lock.yaml generated
View File

@@ -377,12 +377,6 @@ importers:
papaparse:
specifier: 5.5.2
version: 5.5.2
posthog-js:
specifier: 1.240.0
version: 1.240.0
posthog-node:
specifier: 5.9.2
version: 5.9.2
prismjs:
specifier: 1.30.0
version: 1.30.0
@@ -2882,9 +2876,6 @@ packages:
engines: {node: '>=18'}
hasBin: true
'@posthog/core@1.2.2':
resolution: {integrity: sha512-f16Ozx6LIigRG+HsJdt+7kgSxZTHeX5f1JlCGKI1lXcvlZgfsCR338FuMI2QRYXGl+jg/vYFzGOTQBxl90lnBg==}
'@preact/preset-vite@2.10.1':
resolution: {integrity: sha512-59lyGBXNfZIr5OOuBUB4/IB8AqF/ULbvYnyItgK/2BJnsGJqaeaJobRVtMp1129obHQuj8oZ/dVxB9inmH8Xig==}
peerDependencies:
@@ -5687,9 +5678,6 @@ packages:
core-js-compat@3.46.0:
resolution: {integrity: sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==}
core-js@3.46.0:
resolution: {integrity: sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==}
core-util-is@1.0.3:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
@@ -6462,9 +6450,6 @@ packages:
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
engines: {node: ^12.20 || >= 14.13}
fflate@0.4.8:
resolution: {integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==}
fflate@0.7.4:
resolution: {integrity: sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==}
@@ -8246,21 +8231,6 @@ packages:
resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
engines: {node: '>=0.10.0'}
posthog-js@1.240.0:
resolution: {integrity: sha512-zZhedVycGracBMWVRvWJMkB2EiB/dUoe/eM+CsFCnda/PN3Se+V7a6CLGuLZKLF9EfHswCxxU/PIxgDrhbAgjQ==}
peerDependencies:
'@rrweb/types': 2.0.0-alpha.17
rrweb-snapshot: 2.0.0-alpha.17
peerDependenciesMeta:
'@rrweb/types':
optional: true
rrweb-snapshot:
optional: true
posthog-node@5.9.2:
resolution: {integrity: sha512-oU7FbFcH5cn40nhP04cBeT67zE76EiGWjKKzDvm6IOm5P83sqM0Ij0wMJQSHp+QI6ZN7MLzb+4xfMPUEZ4q6CA==}
engines: {node: '>=20'}
preact-render-to-string@5.2.6:
resolution: {integrity: sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==}
peerDependencies:
@@ -9838,9 +9808,6 @@ packages:
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
engines: {node: '>= 8'}
web-vitals@4.2.4:
resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==}
webidl-conversions@3.0.1:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
@@ -13121,8 +13088,6 @@ snapshots:
dependencies:
playwright: 1.56.1
'@posthog/core@1.2.2': {}
'@preact/preset-vite@2.10.1(@babel/core@7.28.5)(preact@10.26.6)(vite@6.4.1(@types/node@22.15.18)(jiti@2.4.2)(terser@5.39.1)(tsx@4.19.4)(yaml@2.8.1))':
dependencies:
'@babel/core': 7.28.5
@@ -16287,8 +16252,6 @@ snapshots:
dependencies:
browserslist: 4.27.0
core-js@3.46.0: {}
core-util-is@1.0.3: {}
create-require@1.1.1: {}
@@ -17251,8 +17214,6 @@ snapshots:
node-domexception: 1.0.0
web-streams-polyfill: 3.3.3
fflate@0.4.8: {}
fflate@0.7.4: {}
file-entry-cache@6.0.1:
@@ -19128,17 +19089,6 @@ snapshots:
dependencies:
xtend: 4.0.2
posthog-js@1.240.0:
dependencies:
core-js: 3.46.0
fflate: 0.4.8
preact: 10.26.6
web-vitals: 4.2.4
posthog-node@5.9.2:
dependencies:
'@posthog/core': 1.2.2
preact-render-to-string@5.2.6(preact@10.26.6):
dependencies:
preact: 10.26.6
@@ -20863,8 +20813,6 @@ snapshots:
web-streams-polyfill@3.3.3: {}
web-vitals@4.2.4: {}
webidl-conversions@3.0.1: {}
webidl-conversions@7.0.0: {}