- Email
(Required)
+
+
+
+ (
+ <>
+ {'email'}
+
+ {errors.email ? (
+
+ {errors.email.message}
+
+ ) : null}
+ >
+ )}
+ />
-
-
-
-
-
- Login
-
-
-
-
+
+ (
+ <>
+ {'password'}
+
+ {errors.password ? (
+
+ {'errors.password.message'}
+
+ ) : null}
+ >
+ )}
+ />
+
+
+
+ {t('login')}
+
+
+ {errors.root ? (
+
+ {errors.root.message}
+
+ ) : null}
+
+
+
+
+
{/* */}
-
+
diff --git a/002_source/ionic_mobile/src/pages/auth/SignUp/index.tsx b/002_source/ionic_mobile/src/pages/auth/SignUp/index.tsx
index 082a7b4..91225cb 100644
--- a/002_source/ionic_mobile/src/pages/auth/SignUp/index.tsx
+++ b/002_source/ionic_mobile/src/pages/auth/SignUp/index.tsx
@@ -9,36 +9,128 @@ import {
IonGrid,
IonHeader,
IonIcon,
- IonImg,
IonInput,
- IonInputPasswordToggle,
+ IonLabel,
IonPage,
- IonRouterLink,
IonRow,
IonText,
IonToolbar,
+ useIonRouter,
} from '@ionic/react';
import styles from './style.module.scss';
+import { Controller, useForm } from 'react-hook-form';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { orderBy, chunk, concat } from 'lodash';
+import _ from 'lodash';
import { arrowBack, shapesOutline } from 'ionicons/icons';
import { CustomField } from '../../../components/CustomField';
-import { useLoginFields, useSignupFields } from '../../../data/fields';
+import { useSignupFields } from '../../../data/fields';
import { Action } from '../../../components/Action';
import { Wave } from '../../../components/Wave';
-import { useEffect, useState } from 'react';
+import React, { useState } from 'react';
import { useParams } from 'react-router';
+import { useTranslation } from 'react-i18next';
+import { useFormInput } from '../../../data/utils';
+import { z as zod } from 'zod';
+import { pb } from '../../../lib/pb';
+import { ClientResponseError } from 'pocketbase';
+import { COL_USER_METAS, COL_USERS } from '../../../constants';
function AuthSignUp(): React.JSX.Element {
const params = useParams();
const fields = useSignupFields();
- const [errors, setErrors] = useState(false);
+ const router = useIonRouter();
+ const [fieldErrors, setFieldErrors] = useState(false);
+ const { t } = useTranslation();
+ const [isPending, setIsPending] = React.useState
(false);
+
+ const schema = zod.object({
+ name: zod.string().min(3, t('name-too-short')),
+ email: zod.string(),
+ password: zod.string().min(8, t('password-should-be-at-least-8-characters')),
+ });
+
+ type Values = zod.infer;
+
+ const defaultValues = {
+ name: 'new user',
+ email: 'test@123.com',
+ password: 'Aa1234567',
+ //
+ } satisfies Values;
const login = () => {};
function createAccount() {}
+ const {
+ control,
+ handleSubmit,
+ setError,
+ formState: { errors },
+ } = useForm({ defaultValues, resolver: zodResolver(schema) });
+
+ const onSubmit = React.useCallback(
+ async (values: Values): Promise => {
+ // setIsPending(true);
+
+ const user = {
+ password: values.password,
+ passwordConfirm: values.password,
+ email: values.email,
+ emailVisibility: true,
+ // verified: true,
+ name: values.name,
+ visible: '',
+ phone: '',
+ };
+
+ try {
+ const userRecord = await pb.collection(COL_USERS).create(user);
+
+ const userMeta = {
+ address: '',
+ meta: {},
+ user_id: userRecord.id,
+ state: '',
+ role: 'student',
+ name: values.name,
+ email: values.email,
+ phone: '',
+ company: '',
+ taxId: '',
+ timezone: '',
+ language: '',
+ currency: '',
+ billingAddress: [],
+ };
+ const userMetaRecord = await pb.collection(COL_USER_METAS).create(userMeta);
+ await pb.collection('users').requestVerification(user.email);
+ } catch (err: any) {
+ const res_err = err as unknown as ClientResponseError;
+ const {
+ originalError: {
+ data: { data },
+ },
+ } = res_err;
+
+ if (data?.email) {
+ const {
+ email: { code },
+ } = data;
+ console.log({ code });
+ if (code == 'validation_not_unique') {
+ setError('email', { message: t('email-is-not-unique') }, { shouldFocus: true });
+ }
+ }
+ }
+ },
+ [router, setError]
+ );
+
return (
@@ -56,35 +148,98 @@ function AuthSignUp(): React.JSX.Element {
{/* */}
-
-
-
- Sign up
- Lets get to know each other
-
-
+
+
+ {_.isEmpty(errors) ? null : JSON.stringify(errors)}
{/* */}
-
+
diff --git a/002_source/ionic_mobile/src/pages/auth/SignUpSuccess/index.tsx b/002_source/ionic_mobile/src/pages/auth/SignUpSuccess/index.tsx
new file mode 100644
index 0000000..3dcfbfd
--- /dev/null
+++ b/002_source/ionic_mobile/src/pages/auth/SignUpSuccess/index.tsx
@@ -0,0 +1,61 @@
+import {
+ IonBackButton,
+ IonButton,
+ IonButtons,
+ IonCardTitle,
+ IonCol,
+ IonContent,
+ IonFooter,
+ IonGrid,
+ IonHeader,
+ IonIcon,
+ IonInput,
+ IonLabel,
+ IonPage,
+ IonRow,
+ IonText,
+ IonToolbar,
+ useIonRouter,
+} from '@ionic/react';
+import styles from './style.module.scss';
+import _ from 'lodash';
+import { Router, useParams } from 'react-router';
+import { Wave } from '../../../components/Wave';
+import { Paths } from '../../../Paths';
+
+function SignUpSuccess(): React.JSX.Element {
+ const router = useIonRouter();
+ function handleBackToLogin() {
+ router.push(Paths.AuthLogin);
+ }
+ return (
+
+
+ {/* */}
+ {/* */}
+
+
+
+ {/* */}
+ {/* */}
+
+ SignUp Success
+
+ Back to login
+
+
+ {/* */}
+
+
+
+ {/* */}
+
+
+
+
+
+
+ );
+}
+
+export default SignUpSuccess;
diff --git a/002_source/ionic_mobile/src/pages/auth/SignUpSuccess/style.module.scss b/002_source/ionic_mobile/src/pages/auth/SignUpSuccess/style.module.scss
new file mode 100644
index 0000000..b66bd24
--- /dev/null
+++ b/002_source/ionic_mobile/src/pages/auth/SignUpSuccess/style.module.scss
@@ -0,0 +1,17 @@
+.loginPage {
+ ion-toolbar {
+ --border-style: none;
+ --border-color: transparent;
+ --padding-top: 1rem;
+ --padding-bottom: 1rem;
+ --padding-start: 1rem;
+ --padding-end: 1rem;
+ }
+}
+
+.headingText {
+ h5 {
+ margin-top: 0.2rem;
+ // color: #d3a6c7;
+ }
+}
diff --git a/002_source/ionic_mobile/src/types/user.d.ts b/002_source/ionic_mobile/src/types/user.d.ts
new file mode 100644
index 0000000..7fc158c
--- /dev/null
+++ b/002_source/ionic_mobile/src/types/user.d.ts
@@ -0,0 +1,10 @@
+export interface User {
+ id: string;
+ name?: string;
+ avatar: string;
+ email?: string;
+
+ collectionId: string;
+
+ [key: string]: unknown;
+}