fixes coderabbit feedback

This commit is contained in:
pandeymangg
2025-11-21 11:41:55 +05:30
parent 3ab62968e5
commit a2a6870a21
13 changed files with 97 additions and 96 deletions

View File

@@ -3,7 +3,6 @@
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { HashIcon, PlusIcon, SmileIcon, StarIcon } from "lucide-react";
import { useTranslation } from "react-i18next";
import { TI18nString } from "@formbricks/types/i18n";
import { TSurveyRatingElement } from "@formbricks/types/surveys/elements";
import { TSurvey } from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
@@ -26,7 +25,6 @@ interface RatingQuestionFormProps {
locale: TUserLocale;
isStorageConfigured: boolean;
isExternalUrlsAllowed?: boolean;
buttonLabel?: TI18nString;
}
export const RatingQuestionForm = ({
@@ -40,7 +38,6 @@ export const RatingQuestionForm = ({
locale,
isStorageConfigured = true,
isExternalUrlsAllowed,
buttonLabel,
}: RatingQuestionFormProps) => {
const { t } = useTranslation();
const surveyLanguageCodes = extractLanguageCodes(localSurvey.languages);
@@ -181,27 +178,6 @@ export const RatingQuestionForm = ({
</div>
</div>
<div className="mt-3">
{!question.required && (
<div className="flex-1">
<QuestionFormInput
id="buttonLabel"
value={buttonLabel}
label={t("environments.surveys.edit.next_button_label")}
localSurvey={localSurvey}
questionIdx={questionIdx}
placeholder={"skip"}
isInvalid={isInvalid}
updateQuestion={updateQuestion}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
locale={locale}
isStorageConfigured={isStorageConfigured}
/>
</div>
)}
</div>
{question.scale !== "star" && (
<AdvancedOptionToggle
isChecked={question.isColorCodingEnabled}

View File

@@ -27,7 +27,6 @@ interface BlockConditionalProps {
setTtc: (ttc: TResponseTtc) => void;
surveyId: string;
autoFocusEnabled: boolean;
currentBlockId: string;
isBackButtonHidden: boolean;
onOpenExternalURL?: (url: string) => void | Promise<void>;
dir?: "ltr" | "rtl" | "auto";
@@ -208,8 +207,6 @@ export function BlockConditional({
onChange={(responseData) => handleElementChange(element.id, responseData)}
onBack={() => {}}
onFileUpload={onFileUpload}
isFirstElement={false}
isLastElement={false}
languageCode={languageCode}
prefilledElementValue={prefilledResponseData?.[element.id]}
skipPrefilled={skipPrefilled}

View File

@@ -30,8 +30,6 @@ interface ElementConditionalProps {
onChange: (responseData: TResponseData) => void;
onBack: () => void;
onFileUpload: (file: TJsFileUploadParams["file"], config?: TUploadFileConfig) => Promise<string>;
isFirstElement: boolean;
isLastElement: boolean;
languageCode: string;
prefilledElementValue?: TResponseDataValue;
skipPrefilled?: boolean;

View File

@@ -777,7 +777,6 @@ export function Survey({
isLastBlock={block.id === localSurvey.blocks[localSurvey.blocks.length - 1].id}
languageCode={selectedLanguage}
autoFocusEnabled={autoFocusEnabled}
currentBlockId={blockId}
isBackButtonHidden={localSurvey.isBackButtonHidden}
onOpenExternalURL={onOpenExternalURL}
dir={dir}

View File

@@ -11,7 +11,7 @@ export const LinkIcon = ({ className }: LinkIconProps) => {
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className={className}>

View File

@@ -36,44 +36,58 @@ export function AddressQuestion({
const [startTime, setStartTime] = useState(performance.now());
const isMediaAvailable = question.imageUrl || question.videoUrl;
const formRef = useRef<HTMLFormElement>(null);
useTtc(question.id, ttc, setTtc, startTime, setStartTime, question.id === currentQuestionId);
const safeValue = useMemo(() => {
return Array.isArray(value) ? value : ["", "", "", "", "", ""];
}, [value]);
const isCurrent = question.id === currentQuestionId;
const fields = [
{
id: "addressLine1",
...question.addressLine1,
label: question.addressLine1.placeholder[languageCode],
},
{
id: "addressLine2",
...question.addressLine2,
label: question.addressLine2.placeholder[languageCode],
},
{
id: "city",
...question.city,
label: question.city.placeholder[languageCode],
},
{
id: "state",
...question.state,
label: question.state.placeholder[languageCode],
},
{
id: "zip",
...question.zip,
label: question.zip.placeholder[languageCode],
},
{
id: "country",
...question.country,
label: question.country.placeholder[languageCode],
},
];
const fields = useMemo(
() => [
{
id: "addressLine1",
...question.addressLine1,
label: question.addressLine1.placeholder[languageCode],
},
{
id: "addressLine2",
...question.addressLine2,
label: question.addressLine2.placeholder[languageCode],
},
{
id: "city",
...question.city,
label: question.city.placeholder[languageCode],
},
{
id: "state",
...question.state,
label: question.state.placeholder[languageCode],
},
{
id: "zip",
...question.zip,
label: question.zip.placeholder[languageCode],
},
{
id: "country",
...question.country,
label: question.country.placeholder[languageCode],
},
],
[
question.addressLine1,
question.addressLine2,
question.city,
question.state,
question.zip,
question.country,
languageCode,
]
);
const handleChange = (fieldId: string, fieldValue: string) => {
const newValue = fields.map((field) => {
@@ -102,6 +116,25 @@ export function AddressQuestion({
[question.id, autoFocusEnabled, currentQuestionId]
);
const isFieldRequired = useCallback(
(field: (typeof fields)[number]) => {
if (field.required) {
return true;
}
// if all fields are optional and the question is required, then the fields should be required
if (
fields.filter((currField) => currField.show).every((currField) => !currField.required) &&
question.required
) {
return true;
}
return false;
},
[fields, question.required]
);
return (
<form key={question.id} onSubmit={handleSubmit} className="fb-w-full" ref={formRef}>
<div>
@@ -118,32 +151,17 @@ export function AddressQuestion({
<div className="fb-flex fb-flex-col fb-space-y-2 fb-mt-4 fb-w-full">
{fields.map((field, index) => {
const isFieldRequired = () => {
if (field.required) {
return true;
}
// if all fields are optional and the question is required, then the fields should be required
if (
fields.filter((currField) => currField.show).every((currField) => !currField.required) &&
question.required
) {
return true;
}
return false;
};
const isRequired = isFieldRequired(field);
return (
field.show && (
<div className="fb-space-y-1">
<Label htmlForId={field.id} text={isFieldRequired() ? `${field.label}*` : field.label} />
<div className="fb-space-y-1" key={field.id}>
<Label htmlForId={field.id} text={isRequired ? `${field.label}*` : field.label} />
<Input
id={field.id}
key={field.id}
required={isFieldRequired()}
required={isRequired}
value={safeValue[index] || ""}
type={field.id === "email" ? "email" : "text"}
type="text"
onChange={(e) => {
handleChange(field.id, e.currentTarget.value);
}}

View File

@@ -35,10 +35,11 @@ export function CalQuestion({
useTtc(question.id, ttc, setTtc, startTime, setStartTime, question.id === currentQuestionId);
const onSuccessfulBooking = useCallback(() => {
setErrorMessage("");
onChange({ [question.id]: "booked" });
const updatedttc = getUpdatedTtc(ttc, question.id, performance.now() - startTime);
setTtc(updatedttc);
}, [onChange, question.id, setTtc, startTime, ttc]);
}, [onChange, question.id, setTtc, startTime, ttc, setErrorMessage]);
return (
<form

View File

@@ -96,7 +96,7 @@ export function ConsentQuestion({
aria-labelledby={`${question.id}-label`}
required={question.required}
/>
<span id={`${question.id}-label`} className="fb-ml-3 fb-mr-3 fb-font-medium fb-flex-1" dir="auto">
<span className="fb-ml-3 fb-mr-3 fb-font-medium fb-flex-1" dir="auto">
{getLocalizedValue(question.label, languageCode)}
</span>
</label>

View File

@@ -127,10 +127,14 @@ export function DateQuestion({
key={question.id}
onSubmit={(e) => {
e.preventDefault();
// Validate required field
if (question.required && !value) {
setErrorMessage(t("errors.please_select_a_date"));
return;
}
setErrorMessage("");
const updatedTtcObj = getUpdatedTtc(ttc, question.id, performance.now() - startTime);
setTtc(updatedTtcObj);
}}
@@ -189,6 +193,15 @@ export function DateQuestion({
isOpen={datePickerOpen}
onChange={(value) => {
const date = value as Date;
if (!date) {
if (question.required) {
setErrorMessage(t("errors.please_select_a_date"));
}
return;
}
setErrorMessage("");
setSelectedDate(date);
// Get the timezone offset in minutes and convert it to milliseconds

View File

@@ -237,9 +237,8 @@ export function MultipleChoiceMultiQuestion({
baseLabelClassName
)}
onKeyDown={(e) => {
// Accessibility: if spacebar was pressed pass this down to the input
// Accessibility: if spacebar was pressed pass this down to the checkbox
if (e.key === " ") {
if (otherSelected) return;
e.preventDefault();
document.getElementById(otherOption.id)?.click();
}
@@ -248,7 +247,7 @@ export function MultipleChoiceMultiQuestion({
<input
type="checkbox"
dir={dir}
tabIndex={-1}
tabIndex={isCurrent ? 0 : -1}
id={otherOption.id}
name={question.id}
value={getLocalizedValue(otherOption.label, languageCode)}
@@ -279,7 +278,7 @@ export function MultipleChoiceMultiQuestion({
<input
ref={otherSpecify}
dir={otherOptionInputDir}
id={`${otherOption.id}-label`}
id={`${otherOption.id}-specify`}
maxLength={250}
name={question.id}
tabIndex={isCurrent ? 0 : -1}

View File

@@ -180,9 +180,7 @@ export function MultipleChoiceSingleQuestion({
<label
tabIndex={isCurrent ? 0 : -1}
className={cn(
value === getLocalizedValue(otherOption.label, languageCode)
? "fb-border-brand fb-bg-input-bg-selected fb-z-10"
: "fb-border-border",
otherSelected ? "fb-border-brand fb-bg-input-bg-selected fb-z-10" : "fb-border-border",
"fb-text-heading focus-within:fb-border-brand fb-bg-input-bg focus-within:fb-bg-input-bg-selected hover:fb-bg-input-bg-selected fb-rounded-custom fb-relative fb-flex fb-cursor-pointer fb-flex-col fb-border fb-p-4 focus:fb-outline-none"
)}
onKeyDown={(e) => {
@@ -224,11 +222,11 @@ export function MultipleChoiceSingleQuestion({
{otherSelected ? (
<input
ref={otherSpecify}
id={`${otherOption.id}-label`}
id={`${otherOption.id}-input`}
dir={otherOptionInputDir}
name={question.id}
pattern=".*\S+.*"
value={value}
value={value ?? ""}
onChange={(e) => {
onChange({ [question.id]: e.currentTarget.value });
}}

View File

@@ -169,7 +169,7 @@ export function OpenTextQuestion({
)}
{question.inputType === "text" && question.charLimit?.max !== undefined && (
<span
className={`fb-text-xs ${currentLength >= question.charLimit?.max ? "fb-text-red-500 font-semibold" : "text-neutral-400"}`}>
className={`fb-text-xs ${currentLength >= question.charLimit?.max ? "fb-text-red-500 fb-font-semibold" : "fb-text-neutral-400"}`}>
{currentLength}/{question.charLimit?.max}
</span>
)}

View File

@@ -45,9 +45,11 @@ export function StackedCardsContainer({
const blockIdxTemp = useMemo(() => {
if (currentBlockId === "start") return survey.welcomeCard.enabled ? -1 : 0;
if (!survey.blocks.map((block) => block.id).includes(currentBlockId)) {
return survey.blocks.length;
}
return survey.blocks.findIndex((block) => block.id === currentBlockId);
}, [currentBlockId, survey]);
@@ -132,7 +134,7 @@ export function StackedCardsContainer({
// Reset block progress, when card arrangement changes
useEffect(() => {
if (shouldResetBlockId) {
setBlockId(survey.welcomeCard.enabled ? "start" : survey.blocks[0]?.id);
setBlockId(survey.welcomeCard.enabled ? "start" : survey.blocks[0].id);
}
// eslint-disable-next-line react-hooks/exhaustive-deps -- Only update when cardArrangement changes
}, [cardArrangement]);