Skip to content

Instantly share code, notes, and snippets.

@hungdev
Created June 21, 2025 15:32
Show Gist options
  • Save hungdev/e860cbae2b7cf243d6319e15a0008e28 to your computer and use it in GitHub Desktop.
Save hungdev/e860cbae2b7cf243d6319e15a0008e28 to your computer and use it in GitHub Desktop.
example form
import { useState } from 'react';
import { Text, TouchableOpacity, View } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
import Ionicons from 'react-native-vector-icons/Ionicons';
import { unwrapResult } from '@reduxjs/toolkit';
import { useDispatch, useSelector } from 'react-redux';
import AppBackground from 'src/components/AppBackground';
import Button from 'src/components/Button';
import ControllerForm from 'src/components/ControllerForm';
import { useForm } from 'src/libs/ValidationForm';
import { Colors } from 'src/themes';
import HeaderLogo from '../../components/HeaderLogo/HeaderLogo';
import styles from './styles';
import { login } from 'store/authSlice';
import { showToast } from 'components/Toast';
import useTranslation from 'src/hooks/translation';
import { BASE_URL } from 'src/config/constant';

export default function Login({ navigation }) {
  const { t } = useTranslation();
  const control = useForm();
  const dispatch = useDispatch();
  const { errors, handleSubmit, values, register } = control;
  const [isSecure, setIsSecure] = useState(true);

  const isDisableSubmit = Object.keys(errors)?.length || !values?.username || !values?.password;

  const currentLang = useSelector(state => state.dict.currentLang);
  const global = useSelector(state => state.dict.global);
  const loading = useSelector(state => state.auth.loading);

  const url = {
    Policies: `${BASE_URL}api/files/${global?.find(el => el?.code === 'policies')?.value}`,
    Terms: `${BASE_URL}api/files/${global?.find(el => el?.code === 'terms')?.value}`
  };
  


  const fields = [
    {
      id: 'username',
      title: t('login.form.email'),
      name: 'username',
      placeholder: t('login.form.emailPlaceholder'),
      error: errors?.username,
      rules: {
        required: {
          value: true,
          message: t('common.validate.email.required'),
        },
        validate(v) {
          if (v && !v?.match(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i)) {
            return t('common.validate.email.invalid');
          }
        },
      },
      defaultValue: '[email protected]',
    },
    {
      id: 'password',
      title: t('login.form.password'),
      name: 'password',
      inputStyle: styles.passWordInputStyle,
      inputProps: { secureTextEntry: isSecure, },
      placeholder: t('login.form.passwordPlaceholder'),
      error: errors?.password,
      defaultValue: 'admin',
      rightComponent: (
        <TouchableOpacity style={styles.btnEye} onPress={() => setIsSecure(!isSecure)}>
          <Ionicons name={isSecure ? 'eye-outline' : 'eye-off-outline'} size={25} color={Colors.primaryBlueVividSkyBlue} />
        </TouchableOpacity>
      ),
      rules: {
        required: {
          value: true,
          message: t('common.validate.newpassword.required'),
        },
        // minLength: { value: 8, message: t('common.validate.newpassword.minlength') },
        maxLength: {
          value: 100,
          message: t('common.validate.newpassword.maxlength')
        },

      },
    },
  ];

  const onLogin = async (values) => {
    try {
      const user = await dispatch(login(values)).unwrap();
      // console.tron.log('vvv', user);
      // showToast({ type: 'success', message: "login success" });
    } catch (err) {
      console.tron.log('hello error', JSON.stringify(err));
      showToast({ message: err?.detail });
    }
  };


  return (
    <>
      <SafeAreaView style={styles.safeArea} edges={['top', 'bottom', 'left', 'right']}>
        <AppBackground isLoading={loading}>
          <KeyboardAwareScrollView>
            <View style={styles.screenContainer}>
              <HeaderLogo />
              <View style={{ marginBottom: 'auto' }}>
                <Text style={[styles.headerScreen, styles.headerAuth]}>{t('login.title')}</Text>
                <Text style={styles.txtSubtitle}>{t('login.subtitle')}</Text>
                <ControllerForm
                  fields={fields}
                  control={control}
                />
                <TouchableOpacity style={styles.btnForgot} onPress={() => navigation.navigate('ForgotPassword')}>
                  <Text style={styles.forgotPassText}>{t('login.password.forgot')}</Text>
                </TouchableOpacity>
              </View>
              <Button
                disabled={!!isDisableSubmit}
                style={styles.btnSubmitLogin}
                btnText={t('login.form.button')}
                onPress={handleSubmit(onLogin)}
              // onPress={setLanguage('vi')}
              />
              <TouchableOpacity onPress={() => navigation.navigate('Register')}>
                <Text style={styles.txtRegister}>{t('login.footer.textToRegister')}</Text>
              </TouchableOpacity>
              <Text style={styles.txtStoreData}>{t('login.footer.text')}</Text>
              <View style={styles.rowPrivacyPolicy}>
                <TouchableOpacity style={styles.privacy} onPress={() => navigation.navigate('Term')}>
                  <Text style={styles.txtPrivacyPolicy}>{t('common.regulations')}</Text>
                </TouchableOpacity>
                <Text>, </Text>
                <TouchableOpacity style={styles.privacy} onPress={() => navigation.navigate('Policy')}>
                  <Text style={styles.txtPrivacyPolicy}>{t('common.policy')}</Text>
                </TouchableOpacity>
              </View>
            </View>
          </KeyboardAwareScrollView>
        </AppBackground>
      </SafeAreaView>
    </>
  );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment