mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-19 19:21:15 -05:00
Validation Fields
This commit is contained in:
@@ -1,7 +1,15 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { TSurveyOpenTextQuestion, TSurveyWithAnalytics } from "@formbricks/types/v1/surveys";
|
||||
import { Button, Input, Label } from "@formbricks/ui";
|
||||
import { Button, Input, Label, Select } from "@formbricks/ui";
|
||||
import { TrashIcon, PlusIcon } from "@heroicons/react/24/solid";
|
||||
import { useState } from "react";
|
||||
|
||||
const questionTypes = [
|
||||
{ value: "text", label: "Text" },
|
||||
{ value: "email", label: "Email" },
|
||||
{ value: "url", label: "URL" },
|
||||
{ value: "number", label: "Number" },
|
||||
{ value: "phone", label: "Phone Number" },
|
||||
];
|
||||
|
||||
interface OpenQuestionFormProps {
|
||||
localSurvey: TSurveyWithAnalytics;
|
||||
@@ -13,6 +21,7 @@ interface OpenQuestionFormProps {
|
||||
}
|
||||
|
||||
export default function OpenQuestionForm({
|
||||
localSurvey,
|
||||
question,
|
||||
questionIdx,
|
||||
updateQuestion,
|
||||
@@ -20,6 +29,15 @@ export default function OpenQuestionForm({
|
||||
}: OpenQuestionFormProps): JSX.Element {
|
||||
const [showSubheader, setShowSubheader] = useState(!!question.subheader);
|
||||
|
||||
// Function to handle question type change
|
||||
const handleQuestionTypeChange = (value: string) => {
|
||||
updateQuestion(questionIdx, { inputType: value });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
handleQuestionTypeChange("text");
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<form>
|
||||
<div className="mt-3">
|
||||
@@ -76,6 +94,23 @@ export default function OpenQuestionForm({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Add a dropdown to select the question type */}
|
||||
<div className="mt-3">
|
||||
<Label htmlFor="questionType">Question Type</Label>
|
||||
<div className="flex items-center">
|
||||
{questionTypes.map((type) => (
|
||||
<div
|
||||
key={type.value}
|
||||
onClick={() => handleQuestionTypeChange(type.value)}
|
||||
className={`mr-2 cursor-pointer rounded-md border p-2 ${
|
||||
question.inputType === type.value ? "bg-slate-50" : "bg-white"
|
||||
}`}>
|
||||
{type.label}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,25 @@ import { BackButton } from "./BackButton";
|
||||
import Headline from "./Headline";
|
||||
import Subheader from "./Subheader";
|
||||
import SubmitButton from "./SubmitButton";
|
||||
import { useState } from "preact/hooks";
|
||||
|
||||
function validateInput(value: string, questionType: string): boolean {
|
||||
switch (questionType) {
|
||||
case "email":
|
||||
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
return emailPattern.test(value);
|
||||
case "url":
|
||||
const urlPattern = /^(ftp|http|https):\/\/[^ "]+$/;
|
||||
return urlPattern.test(value);
|
||||
case "number":
|
||||
return !isNaN(parseFloat(value));
|
||||
case "phone":
|
||||
const phonePattern = /^\+?[0-9]+$/;
|
||||
return phonePattern.test(value);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
interface OpenTextQuestionProps {
|
||||
question: TSurveyOpenTextQuestion;
|
||||
@@ -28,11 +47,21 @@ export default function OpenTextQuestion({
|
||||
brandColor,
|
||||
autoFocus = true,
|
||||
}: OpenTextQuestionProps) {
|
||||
const [isValid, setIsValid] = useState(true);
|
||||
|
||||
const handleInputChange = (inputValue: string) => {
|
||||
const isValidInput = validateInput(inputValue, question.inputType);
|
||||
setIsValid(isValidInput);
|
||||
onChange({ [question.id]: inputValue });
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
onSubmit({ [question.id]: value });
|
||||
if (isValid) {
|
||||
onSubmit({ [question.id]: value, inputType: question.inputType });
|
||||
}
|
||||
}}
|
||||
className="w-full">
|
||||
<Headline headline={question.headline} questionId={question.id} required={question.required} />
|
||||
@@ -44,12 +73,12 @@ export default function OpenTextQuestion({
|
||||
id={question.id}
|
||||
placeholder={question.placeholder}
|
||||
required={question.required}
|
||||
value={value}
|
||||
onInput={(e) => {
|
||||
onChange({ [question.id]: e.currentTarget.value });
|
||||
}}
|
||||
value={value as string}
|
||||
onInput={(e) => handleInputChange(e.currentTarget.value)}
|
||||
autoFocus={autoFocus}
|
||||
className="block w-full rounded-md border border-slate-100 bg-slate-50 p-2 shadow-sm focus:border-slate-500 focus:outline-none focus:ring-0 sm:text-sm"
|
||||
className={`block w-full rounded-md border ${
|
||||
isValid ? "border-slate-100" : "border-red-500"
|
||||
} bg-slate-50 p-2 shadow-sm focus:border-slate-500 focus:outline-none focus:ring-0 sm:text-sm`}
|
||||
/>
|
||||
) : (
|
||||
<textarea
|
||||
@@ -58,12 +87,12 @@ export default function OpenTextQuestion({
|
||||
id={question.id}
|
||||
placeholder={question.placeholder}
|
||||
required={question.required}
|
||||
value={value}
|
||||
onInput={(e) => {
|
||||
onChange({ [question.id]: e.currentTarget.value });
|
||||
}}
|
||||
value={value as string}
|
||||
onInput={(e) => handleInputChange(e.currentTarget.value)}
|
||||
autoFocus={autoFocus}
|
||||
className="block w-full rounded-md border border-slate-100 bg-slate-50 p-2 shadow-sm focus:border-slate-500 focus:ring-0 sm:text-sm"></textarea>
|
||||
className={`block w-full rounded-md border ${
|
||||
isValid ? "border-slate-100" : "border-red-500" // Apply red border for invalid input
|
||||
} bg-slate-50 p-2 shadow-sm focus:border-slate-500 focus:outline-none focus:ring-0 sm:text-sm`}></textarea>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-4 flex w-full justify-between">
|
||||
|
||||
@@ -145,6 +145,7 @@ export const ZSurveyOpenTextQuestion = ZSurveyQuestionBase.extend({
|
||||
placeholder: z.string().optional(),
|
||||
longAnswer: z.boolean().optional(),
|
||||
logic: z.array(ZSurveyOpenTextLogic).optional(),
|
||||
inputType: z.enum(["text", "email", "url", "number", "phone"]).optional().default("text"),
|
||||
});
|
||||
|
||||
export type TSurveyOpenTextQuestion = z.infer<typeof ZSurveyOpenTextQuestion>;
|
||||
|
||||
Reference in New Issue
Block a user