add OTP + fix field

This commit is contained in:
rizky 2024-09-02 09:12:58 -07:00
parent 86551c1ba8
commit f54e3c683c
3 changed files with 95 additions and 3 deletions

View File

@ -135,7 +135,7 @@ export const FieldInput: FC<{
{prefix && prefix !== "" ? ( {prefix && prefix !== "" ? (
<div <div
className={cx( className={cx(
"c-px-2 c-flex c-flex-row c-items-center", "c-pl-2 c-flex c-flex-row c-items-center",
css` css`
color: gray; color: gray;
` `
@ -200,7 +200,7 @@ export const FieldInput: FC<{
{suffix && suffix !== "" ? ( {suffix && suffix !== "" ? (
<div <div
className={cx( className={cx(
"c-px-2 c-flex c-flex-row c-items-center", "c-pr-2 c-flex c-flex-row c-items-center",
css` css`
color: gray; color: gray;
` `

View File

@ -10,6 +10,7 @@ import { FieldRichText } from "./TypeRichText";
import { FieldUpload } from "./TypeUpload"; import { FieldUpload } from "./TypeUpload";
import { KeyValue } from "./KeyValue"; import { KeyValue } from "./KeyValue";
import { InputMask, format } from "@react-input/mask"; import { InputMask, format } from "@react-input/mask";
import { FieldOTP } from "./TypeOTP";
export type PropTypeInput = { export type PropTypeInput = {
type: "input"; type: "input";
@ -32,7 +33,8 @@ export type PropTypeInput = {
| "monthly" | "monthly"
| "key-value" | "key-value"
| "mask" | "mask"
| "phone"; | "phone"
| "otp";
placeholder?: string; placeholder?: string;
onFocus?: (e: FocusEvent<HTMLDivElement>) => void; onFocus?: (e: FocusEvent<HTMLDivElement>) => void;
onBlur?: (e: FocusEvent<HTMLDivElement>) => void; onBlur?: (e: FocusEvent<HTMLDivElement>) => void;
@ -110,6 +112,7 @@ export const FieldTypeInput: FC<{
const disabled = const disabled =
typeof field.disabled === "function" ? field.disabled() : field.disabled; typeof field.disabled === "function" ? field.disabled() : field.disabled;
switch (type_field) { switch (type_field) {
case "toggle": case "toggle":
return ( return (
@ -198,6 +201,8 @@ export const FieldTypeInput: FC<{
<FieldMoney field={field} fm={fm} prop={prop} arg={arg} /> <FieldMoney field={field} fm={fm} prop={prop} arg={arg} />
</> </>
); );
case "otp":
return <FieldOTP field={field} fm={fm} prop={prop} arg={arg} digit={4} />;
case "rich-text": case "rich-text":
return <FieldRichText field={field} fm={fm} prop={prop} />; return <FieldRichText field={field} fm={fm} prop={prop} />;
case "date": { case "date": {

View File

@ -0,0 +1,87 @@
import { useLocal } from "lib/utils/use-local";
import { FC } from "react";
import { FieldLocal, FieldProp, FMLocal } from "../../typings";
import { PropTypeInput } from "./TypeInput";
export const FieldOTP: FC<{
digit: number;
field: FieldLocal;
fm: FMLocal;
prop: PropTypeInput;
arg: FieldProp;
}> = ({ digit, fm, field }) => {
const local = useLocal({
otp: [] as string[],
ref: [] as HTMLInputElement[],
});
if (local.otp.length === 0 && digit) {
for (let i = 0; i < digit; i++) {
local.otp.push("");
}
}
return (
<div className="c-flex-1 c-flex c-justify-center c-items-center">
{local.otp.map((item, idx) => (
<input
type="text"
key={idx}
className={cx(
"c-rounded-md c-text-center",
css`
margin: 3px;
font-size: 3em;
padding: 0px 10px;
width: 60px;
height: 100px;
border: 1px solid #ddd;
background: white;
`
)}
onChange={() => {}}
value={item}
ref={(ref) => {
if (ref) local.ref[idx] = ref;
}}
onPaste={(e) => {
e.preventDefault();
var clipboardData =
e.clipboardData || (window as any).clipboardData;
var pastedData = clipboardData.getData("text");
for (let i = 0; i < pastedData.length; i++) {
if (i >= local.otp.length) break;
local.otp[i] = pastedData[i];
}
local.render();
}}
onKeyDown={async (e) => {
if (e.key === "Backspace") {
local.otp[idx] = "";
local.render();
const ref = local.ref[idx - 1];
if (ref) {
ref.focus();
}
} else if (parseInt(e.key) || e.key === "0") {
local.otp[idx] = e.key;
local.render();
const ref = local.ref[idx + 1];
if (ref) {
ref.focus();
}
}
const otp = local.otp.join("");
if (otp.length === digit) {
fm.data[field.name] = otp;
fm.render();
}
local.render();
}}
/>
))}
</div>
);
};