mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-30 10:40:13 -05:00
Merge branch 'main' of github.com:formbricks/formbricks into feature/integrations
This commit is contained in:
@@ -28,7 +28,7 @@ export default function IsPasswordValid({
|
||||
|
||||
useEffect(() => {
|
||||
let newValidations = [...DEFAULT_VALIDATIONS];
|
||||
if (password) {
|
||||
if (password !== null) {
|
||||
newValidations = checkValidation(newValidations, 0, PASSWORD_REGEX.UPPER_AND_LOWER.test(password));
|
||||
newValidations = checkValidation(newValidations, 1, password.length >= 8);
|
||||
newValidations = checkValidation(newValidations, 2, PASSWORD_REGEX.NUMBER.test(password));
|
||||
|
||||
+6
-2
@@ -9,14 +9,18 @@ import { useState } from "react";
|
||||
export const PasswordResetForm = ({}) => {
|
||||
const router = useRouter();
|
||||
const [error, setError] = useState<string>("");
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
try {
|
||||
await forgotPassword(e.target.elements.email.value);
|
||||
|
||||
router.push("/auth/forgot-password/email-sent");
|
||||
} catch (e) {
|
||||
setError(e.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -55,7 +59,7 @@ export const PasswordResetForm = ({}) => {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Button type="submit" className="w-full justify-center">
|
||||
<Button type="submit" variant="darkCTA" className="w-full justify-center" loading={loading}>
|
||||
Reset password
|
||||
</Button>
|
||||
<div className="mt-3 text-center">
|
||||
@@ -1,7 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import IsPasswordValid from "@/components/auth/IsPasswordValid";
|
||||
import { resetPassword } from "@/lib/users/users";
|
||||
import { Button } from "@formbricks/ui";
|
||||
import { Button, PasswordInput } from "@formbricks/ui";
|
||||
import { XCircleIcon } from "@heroicons/react/24/solid";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
@@ -10,9 +11,13 @@ export const ResetPasswordForm = () => {
|
||||
const searchParams = useSearchParams();
|
||||
const router = useRouter();
|
||||
const [error, setError] = useState<string>("");
|
||||
const [password, setPassword] = useState<string | null>(null);
|
||||
const [isValid, setIsValid] = useState(false);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
const token = searchParams?.get("token");
|
||||
try {
|
||||
if (!token) throw new Error("No token provided");
|
||||
@@ -21,6 +26,8 @@ export const ResetPasswordForm = () => {
|
||||
router.push("/auth/forgot-password/reset/success");
|
||||
} catch (e) {
|
||||
setError(e.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -47,18 +54,27 @@ export const ResetPasswordForm = () => {
|
||||
New password
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<input
|
||||
<PasswordInput
|
||||
id="password"
|
||||
name="password"
|
||||
type="password"
|
||||
value={password ? password : ""}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
autoComplete="current-password"
|
||||
placeholder="*******"
|
||||
required
|
||||
className="focus:border-brand focus:ring-brand block w-full rounded-md border-slate-300 shadow-sm sm:text-sm"
|
||||
/>
|
||||
<IsPasswordValid password={password} setIsValid={setIsValid} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Button type="submit" className="w-full justify-center">
|
||||
<Button
|
||||
type="submit"
|
||||
variant="darkCTA"
|
||||
disabled={!isValid}
|
||||
className="w-full justify-center"
|
||||
loading={loading}>
|
||||
Reset password
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { GoogleButton } from "@/components/auth/GoogleButton";
|
||||
import { env } from "@/env.mjs";
|
||||
import { Button, PasswordInput } from "@formbricks/ui";
|
||||
import { XCircleIcon } from "@heroicons/react/24/solid";
|
||||
import { signIn } from "next-auth/react";
|
||||
@@ -75,7 +76,7 @@ export const SigninForm = () => {
|
||||
className="focus:border-brand focus:ring-brand block w-full rounded-md border-slate-300 shadow-sm sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
{process.env.NEXT_PUBLIC_PASSWORD_RESET_DISABLED !== "1" && isPasswordFocused && (
|
||||
{env.NEXT_PUBLIC_PASSWORD_RESET_DISABLED !== "1" && isPasswordFocused && (
|
||||
<div className="ml-1 text-right transition-all duration-500 ease-in-out">
|
||||
<Link
|
||||
href="/auth/forgot-password"
|
||||
@@ -105,18 +106,18 @@ export const SigninForm = () => {
|
||||
</Button>
|
||||
</form>
|
||||
|
||||
{process.env.NEXT_PUBLIC_GOOGLE_AUTH_ENABLED === "1" && (
|
||||
{env.NEXT_PUBLIC_GOOGLE_AUTH_ENABLED === "1" && (
|
||||
<>
|
||||
<GoogleButton />
|
||||
</>
|
||||
)}
|
||||
{process.env.NEXT_PUBLIC_GITHUB_AUTH_ENABLED === "1" && (
|
||||
{env.NEXT_PUBLIC_GITHUB_AUTH_ENABLED === "1" && (
|
||||
<>
|
||||
<GithubButton />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{process.env.NEXT_PUBLIC_SIGNUP_DISABLED !== "1" && (
|
||||
{env.NEXT_PUBLIC_SIGNUP_DISABLED !== "1" && (
|
||||
<div className="mt-9 text-center text-xs ">
|
||||
<span className="leading-5 text-slate-500">New to Formbricks?</span>
|
||||
<br />
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@formbricks/ui";
|
||||
import { PasswordInput } from "@formbricks/ui";
|
||||
import { GoogleButton } from "@/components/auth/GoogleButton";
|
||||
import IsPasswordValid from "@/components/auth/IsPasswordValid";
|
||||
import { env } from "@/env.mjs";
|
||||
import { createUser } from "@/lib/users/users";
|
||||
import { Button, PasswordInput } from "@formbricks/ui";
|
||||
import { XCircleIcon } from "@heroicons/react/24/solid";
|
||||
import Link from "next/link";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { useRef, useState } from "react";
|
||||
import { GithubButton } from "./GithubButton";
|
||||
import { GoogleButton } from "@/components/auth/GoogleButton";
|
||||
import IsPasswordValid from "@/components/auth/IsPasswordValid";
|
||||
|
||||
export const SignupForm = () => {
|
||||
const searchParams = useSearchParams();
|
||||
@@ -33,7 +33,7 @@ export const SignupForm = () => {
|
||||
searchParams?.get("inviteToken")
|
||||
);
|
||||
const url =
|
||||
process.env.NEXT_PUBLIC_EMAIL_VERIFICATION_DISABLED === "1"
|
||||
env.NEXT_PUBLIC_EMAIL_VERIFICATION_DISABLED === "1"
|
||||
? `/auth/signup-without-verification-success`
|
||||
: `/auth/verification-requested?email=${encodeURIComponent(e.target.elements.email.value)}`;
|
||||
|
||||
@@ -131,7 +131,7 @@ export const SignupForm = () => {
|
||||
className="focus:border-brand focus:ring-brand block w-full rounded-md shadow-sm sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
{process.env.NEXT_PUBLIC_PASSWORD_RESET_DISABLED !== "1" && isPasswordFocused && (
|
||||
{env.NEXT_PUBLIC_PASSWORD_RESET_DISABLED !== "1" && isPasswordFocused && (
|
||||
<div className="ml-1 text-right transition-all duration-500 ease-in-out">
|
||||
<Link
|
||||
href="/auth/forgot-password"
|
||||
@@ -163,36 +163,36 @@ export const SignupForm = () => {
|
||||
</Button>
|
||||
</form>
|
||||
|
||||
{process.env.NEXT_PUBLIC_GOOGLE_AUTH_ENABLED === "1" && (
|
||||
{env.NEXT_PUBLIC_GOOGLE_AUTH_ENABLED === "1" && (
|
||||
<>
|
||||
<GoogleButton />
|
||||
</>
|
||||
)}
|
||||
{process.env.NEXT_PUBLIC_GITHUB_AUTH_ENABLED === "1" && (
|
||||
{env.NEXT_PUBLIC_GITHUB_AUTH_ENABLED === "1" && (
|
||||
<>
|
||||
<GithubButton />{" "}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{(process.env.NEXT_PUBLIC_TERMS_URL || process.env.NEXT_PUBLIC_PRIVACY_URL) && (
|
||||
{(env.NEXT_PUBLIC_TERMS_URL || env.NEXT_PUBLIC_PRIVACY_URL) && (
|
||||
<div className="mt-3 text-center text-xs text-slate-500">
|
||||
By signing up, you agree to our
|
||||
<br />
|
||||
{process.env.NEXT_PUBLIC_TERMS_URL && (
|
||||
{env.NEXT_PUBLIC_TERMS_URL && (
|
||||
<Link
|
||||
className="font-semibold"
|
||||
href="google.com" /* {process.env.NEXT_PUBLIC_TERMS_URL} */
|
||||
href="google.com" /* {env.NEXT_PUBLIC_TERMS_URL} */
|
||||
rel="noreferrer"
|
||||
target="_blank">
|
||||
Terms of Service
|
||||
</Link>
|
||||
)}
|
||||
{process.env.NEXT_PUBLIC_TERMS_URL && process.env.NEXT_PUBLIC_PRIVACY_URL && <span> and </span>}
|
||||
{process.env.NEXT_PUBLIC_PRIVACY_URL && (
|
||||
{env.NEXT_PUBLIC_TERMS_URL && env.NEXT_PUBLIC_PRIVACY_URL && <span> and </span>}
|
||||
{env.NEXT_PUBLIC_PRIVACY_URL && (
|
||||
<Link
|
||||
className="font-semibold"
|
||||
href="google.com" /* {/* process.env.NEXT_PUBLIC_PRIVACY_URL }*/
|
||||
href="google.com" /* {/* env.NEXT_PUBLIC_PRIVACY_URL }*/
|
||||
rel="noreferrer"
|
||||
target="_blank">
|
||||
Privacy Policy.
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Input } from "@/../../packages/ui";
|
||||
import SubmitButton from "@/components/preview/SubmitButton";
|
||||
import { cn } from "@formbricks/lib/cn";
|
||||
import type { MultipleChoiceSingleQuestion } from "@formbricks/types/questions";
|
||||
import { useState } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import Headline from "./Headline";
|
||||
import Subheader from "./Subheader";
|
||||
|
||||
@@ -20,6 +20,13 @@ export default function MultipleChoiceSingleQuestion({
|
||||
brandColor,
|
||||
}: MultipleChoiceSingleProps) {
|
||||
const [selectedChoice, setSelectedChoice] = useState<string | null>(null);
|
||||
const otherSpecify = useRef<HTMLInputElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedChoice === "other") {
|
||||
otherSpecify.current?.focus();
|
||||
}
|
||||
}, [selectedChoice]);
|
||||
/* const [isIphone, setIsIphone] = useState(false);
|
||||
|
||||
|
||||
@@ -31,7 +38,7 @@ export default function MultipleChoiceSingleQuestion({
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
const value = e.currentTarget[question.id].value;
|
||||
const value = otherSpecify.current?.value || e.currentTarget[question.id].value;
|
||||
const data = {
|
||||
[question.id]: value,
|
||||
};
|
||||
@@ -72,6 +79,7 @@ export default function MultipleChoiceSingleQuestion({
|
||||
{choice.id === "other" && selectedChoice === "other" && (
|
||||
<Input
|
||||
id={`${choice.id}-label`}
|
||||
ref={otherSpecify}
|
||||
name={question.id}
|
||||
placeholder="Please specify"
|
||||
className="mt-3 bg-white focus:border-slate-300"
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import { env } from "@/env.mjs";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function LegalFooter() {
|
||||
if (!process.env.NEXT_PUBLIC_IMPRINT_URL && !process.env.NEXT_PUBLIC_PRIVACY_URL) return null;
|
||||
if (!env.NEXT_PUBLIC_IMPRINT_URL && !env.NEXT_PUBLIC_PRIVACY_URL) return null;
|
||||
return (
|
||||
<div className="top-0 z-10 w-full border-b bg-white">
|
||||
<div className="mx-auto max-w-lg p-3 text-center text-sm text-slate-400">
|
||||
{process.env.NEXT_PUBLIC_IMPRINT_URL && (
|
||||
<Link href={process.env.NEXT_PUBLIC_IMPRINT_URL} target="_blank">
|
||||
{env.NEXT_PUBLIC_IMPRINT_URL && (
|
||||
<Link href={env.NEXT_PUBLIC_IMPRINT_URL} target="_blank">
|
||||
Imprint
|
||||
</Link>
|
||||
)}
|
||||
{process.env.NEXT_PUBLIC_IMPRINT_URL && process.env.NEXT_PUBLIC_PRIVACY_URL && <span> | </span>}
|
||||
{process.env.NEXT_PUBLIC_PRIVACY_URL && (
|
||||
<Link href={process.env.NEXT_PUBLIC_PRIVACY_URL} target="_blank">
|
||||
{env.NEXT_PUBLIC_IMPRINT_URL && env.NEXT_PUBLIC_PRIVACY_URL && <span> | </span>}
|
||||
{env.NEXT_PUBLIC_PRIVACY_URL && (
|
||||
<Link href={env.NEXT_PUBLIC_PRIVACY_URL} target="_blank">
|
||||
Privacy Policy
|
||||
</Link>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user