Skip to content

Commit

Permalink
Merge pull request #39 from dribble-njr/feature/common-comps
Browse files Browse the repository at this point in the history
feat: captcha input and password input
  • Loading branch information
dribble-njr authored Dec 5, 2024
2 parents a29f69d + 87e9e6e commit 0f880d2
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 19 deletions.
30 changes: 11 additions & 19 deletions apps/mobile/app/(guide)/create-kitchen.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import CaptchaInput from '@/components/CaptchaInput';
import FieldInput from '@/components/FieldInput';
import ParallaxScrollView from '@/components/ParallaxScrollView';
import PasswordInput from '@/components/PasswordInput';
import { ThemedView } from '@/components/ThemedView';
import { UserService } from '@/service';
import { RegisterAdminDTO } from '@imperial-kitchen/types';
import { Formik } from 'formik';
import { useTranslation } from 'react-i18next';
import { Alert } from 'react-native';
import { Button, Text, TextInput } from 'react-native-paper';
import { Button, Text } from 'react-native-paper';
import * as Yup from 'yup';

export default function CreateKitchen() {
Expand Down Expand Up @@ -56,30 +58,20 @@ export default function CreateKitchen() {
<>
<FieldInput i18nKey="common" name="name" />

<FieldInput
<CaptchaInput
i18nKey="common"
name="email"
right={
<TextInput.Affix
onPress={async () => {
await setFieldTouched('email', true, true);
if (!errors.email) {
sendCaptcha(values.email);
}
}}
text={t('common.sendCaptcha')}
/>
}
onSendCaptcha={async () => {
await setFieldTouched('email', true, true);
if (!errors.email) {
sendCaptcha(values.email);
}
}}
/>

<FieldInput i18nKey="common" name="captcha" />

<FieldInput
i18nKey="common"
name="password"
secureTextEntry
right={<TextInput.Icon icon="eye" onPress={() => {}} />}
/>
<PasswordInput i18nKey="common" name="password" />

<Button mode="contained" onPress={() => handleSubmit()}>
{t('common.confirm')}
Expand Down
59 changes: 59 additions & 0 deletions apps/mobile/components/CaptchaInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { ThemedView } from '@/components/ThemedView';
import { useField } from 'formik';
import { useTranslation } from 'react-i18next';
import { HelperText, TextInput, TextInputProps } from 'react-native-paper';
import { useState, useEffect, useRef } from 'react';

interface CaptchaInputProps extends TextInputProps {
i18nKey: string;
name: string;
onSendCaptcha: () => Promise<void>;
}

export default function CaptchaInput({ i18nKey, name, onSendCaptcha, ...textInputProps }: CaptchaInputProps) {
const [field, meta, helpers] = useField(name);
const hasError = meta.touched && Boolean(meta.error);
const { t } = useTranslation();
const [countdown, setCountdown] = useState(0);
const timerRef = useRef<ReturnType<typeof setTimeout>>();

useEffect(() => {
if (countdown > 0) {
timerRef.current = setTimeout(() => {
setCountdown((prev) => prev - 1);
}, 1000);
}
return () => {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
};
}, [countdown]);

const handleSendCaptcha = async () => {
await onSendCaptcha();
setCountdown(60);
};

return (
<ThemedView>
<TextInput
mode="outlined"
label={t(`${i18nKey}.${name}`)}
value={field.value}
error={hasError}
placeholder={`${t('common.enter')}${t(`${i18nKey}.${name}`)}...`}
onChangeText={(value) => helpers.setValue(value)}
onBlur={() => helpers.setTouched(true)}
right={
<TextInput.Affix
text={countdown > 0 ? `${countdown}s` : t('common.sendCaptcha')}
onPress={countdown === 0 ? handleSendCaptcha : undefined}
/>
}
{...textInputProps}
/>
{hasError && <HelperText type="error">{meta.error}</HelperText>}
</ThemedView>
);
}
41 changes: 41 additions & 0 deletions apps/mobile/components/PasswordInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { ThemedView } from '@/components/ThemedView';
import { useField } from 'formik';
import { useTranslation } from 'react-i18next';
import { HelperText, TextInput, TextInputProps } from 'react-native-paper';
import { useState } from 'react';
import { Keyboard } from 'react-native';

interface PasswordInputProps extends TextInputProps {
i18nKey: string;
name: string;
}

export default function PasswordInput({ i18nKey, name, ...textInputProps }: PasswordInputProps) {
const [field, meta, helpers] = useField(name);
const hasError = meta.touched && Boolean(meta.error);
const { t } = useTranslation();
const [showPassword, setShowPassword] = useState(false);

const handleTogglePassword = () => {
Keyboard.dismiss();
setShowPassword(!showPassword);
};

return (
<ThemedView>
<TextInput
mode="outlined"
label={t(`${i18nKey}.${name}`)}
value={field.value}
error={hasError}
placeholder={`${t('common.enter')}${t(`${i18nKey}.${name}`)}...`}
onChangeText={(value) => helpers.setValue(value)}
onBlur={() => helpers.setTouched(true)}
secureTextEntry={!showPassword}
right={<TextInput.Icon icon={showPassword ? 'eye-off' : 'eye'} onPress={handleTogglePassword} />}
{...textInputProps}
/>
{hasError && <HelperText type="error">{meta.error}</HelperText>}
</ThemedView>
);
}

0 comments on commit 0f880d2

Please sign in to comment.