fix: use strings for pin datatype to allow more variations (#1335)

This commit is contained in:
Matti Nannt
2023-10-20 10:11:39 +02:00
committed by GitHub
parent a97f745406
commit 569e9a6ee2
6 changed files with 25 additions and 27 deletions
@@ -49,7 +49,7 @@ export default function ResponseOptionsCard({
const isPinProtectionEnabled = localSurvey.pin !== null;
const [verifyProtectWithPinError, setverifyProtectWithPinError] = useState<string | null>(null);
const [verifyProtectWithPinError, setVerifyProtectWithPinError] = useState<string | null>(null);
const handleRedirectCheckMark = () => {
setRedirectToggle((prev) => !prev);
@@ -80,20 +80,21 @@ export default function ResponseOptionsCard({
};
const handleProtectSurveyPinChange = (pin: string) => {
const pinAsNumber = Number(pin);
if (isNaN(pinAsNumber)) return toast.error("PIN can only contain numbers");
setLocalSurvey({ ...localSurvey, pin: pinAsNumber });
//check if pin only contains numbers
const validation = /^\d+$/;
const isValidPin = validation.test(pin);
if (!isValidPin) return toast.error("PIN can only contain numbers");
setLocalSurvey({ ...localSurvey, pin });
};
const handleProtectSurveyPinBlurEvent = () => {
if (!localSurvey.pin) return setverifyProtectWithPinError(null);
if (!localSurvey.pin) return setVerifyProtectWithPinError(null);
const regexPattern = /^\d{4}$/;
const isValidPin = regexPattern.test(`${localSurvey.pin}`);
if (!isValidPin) return setverifyProtectWithPinError("PIN must be a four digit number.");
setverifyProtectWithPinError(null);
if (!isValidPin) return setVerifyProtectWithPinError("PIN must be a four digit number.");
setVerifyProtectWithPinError(null);
};
const handleSurveyPinInputKeyDown: KeyboardEventHandler<HTMLInputElement> = (e) => {
@@ -502,11 +503,10 @@ export default function ResponseOptionsCard({
<Label htmlFor="headline">Add PIN</Label>
<Input
autoFocus
type="number"
id="heading"
id="pin"
isInvalid={Boolean(verifyProtectWithPinError)}
className="mb-4 mt-2 bg-white"
name="heading"
name="pin"
placeholder="1234"
onBlur={handleProtectSurveyPinBlurEvent}
defaultValue={localSurvey.pin ? localSurvey.pin : undefined}
+5 -5
View File
@@ -9,7 +9,7 @@ interface LinkSurveyEmailData {
} | null;
}
interface ISurveyPinValidationResponse {
interface TSurveyPinValidationResponse {
error?: TSurveyPinValidationResponseError;
survey?: TSurvey;
}
@@ -30,15 +30,15 @@ export async function verifyTokenAction(token: string, surveyId: string): Promis
return await verifyTokenForLinkSurvey(token, surveyId);
}
export async function validateSurveyPin(
export async function validateSurveyPinAction(
surveyId: string,
pin: number
): Promise<ISurveyPinValidationResponse> {
pin: string
): Promise<TSurveyPinValidationResponse> {
try {
const survey = await getSurvey(surveyId);
if (!survey) return { error: TSurveyPinValidationResponseError.NOT_FOUND };
const originalPin = survey.pin;
const originalPin = survey.pin?.toString();
if (!originalPin) return { survey };
@@ -5,7 +5,7 @@ import { TProduct } from "@formbricks/types/v1/product";
import { TResponse } from "@formbricks/types/v1/responses";
import { OTPInput } from "@formbricks/ui/OTPInput";
import { useCallback, useEffect, useState } from "react";
import { validateSurveyPin } from "@/app/s/[surveyId]/actions";
import { validateSurveyPinAction } from "@/app/s/[surveyId]/actions";
import { TSurvey } from "@formbricks/types/v1/surveys";
import { TSurveyPinValidationResponseError } from "@/app/s/[surveyId]/types";
import LinkSurvey from "@/app/s/[surveyId]/components/LinkSurvey";
@@ -40,8 +40,8 @@ const LinkSurveyPinScreen: NextPage<LinkSurveyPinScreenProps> = (props) => {
const [error, setError] = useState<TSurveyPinValidationResponseError>();
const [survey, setSurvey] = useState<TSurvey>();
const _validateSurveyPinAsync = useCallback(async (surveyId: string, pin: number) => {
const response = await validateSurveyPin(surveyId, pin);
const _validateSurveyPinAsync = useCallback(async (surveyId: string, pin: string) => {
const response = await validateSurveyPinAction(surveyId, pin);
if (response.error) {
setError(response.error);
} else if (response.survey) {
@@ -69,12 +69,10 @@ const LinkSurveyPinScreen: NextPage<LinkSurveyPinScreenProps> = (props) => {
const validPinRegex = /^\d{4}$/;
const isValidPin = validPinRegex.test(localPinEntry);
const pinAsNumber = Number(localPinEntry);
if (isValidPin) {
// Show loading and check against the server
setLoading(true);
_validateSurveyPinAsync(surveyId, pinAsNumber);
_validateSurveyPinAsync(surveyId, localPinEntry);
return;
}
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Survey" ALTER COLUMN "pin" SET DATA TYPE TEXT;
+2 -4
View File
@@ -267,13 +267,11 @@ model Survey {
productOverwrites Json?
/// @zod.custom(imports.ZSurveySingleUse)
/// [SurveySingleUse]
singleUse Json? @default("{\"enabled\": false, \"isEncrypted\": true}")
singleUse Json? @default("{\"enabled\": false, \"isEncrypted\": true}")
/// @zod.custom(imports.ZSurveyVerifyEmail)
/// [SurveyVerifyEmail]
verifyEmail Json?
// PIN Protected Surveys
pin Int?
pin String?
}
model Event {
+1 -1
View File
@@ -325,7 +325,7 @@ export const ZSurvey = z.object({
surveyClosedMessage: ZSurveyClosedMessage.nullable(),
singleUse: ZSurveySingleUse.nullable(),
verifyEmail: ZSurveyVerifyEmail.nullable(),
pin: z.number().nullable().optional(),
pin: z.string().nullable().optional(),
});
export const ZSurveyInput = z.object({