Skip to content

Commit

Permalink
feat/updated form composable
Browse files Browse the repository at this point in the history
  • Loading branch information
serikovlearning committed May 9, 2024
1 parent b8c9c31 commit 4d6e944
Show file tree
Hide file tree
Showing 9 changed files with 56 additions and 77 deletions.
35 changes: 3 additions & 32 deletions frontend-admin/src/lib/components/auth-form/consts.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,4 @@
type FormState = {
fields: {
password: InputParams<string>;
username: InputParams<string>;
};
isLoading: boolean;
hasChanges: boolean;
error?: string;
};

type InputParams<T> = {
value: T;
isValid: boolean;
hasChanges: boolean;
};

export const initialFormState: FormState = {
fields: {
password: {
isValid: true,
value: '',
hasChanges: false
},
username: {
isValid: true,
value: '',
hasChanges: false
}
},
hasChanges: false,
isLoading: false,
error: undefined
export const initialValues = {
password: '',
username: ''
};
18 changes: 12 additions & 6 deletions frontend-admin/src/lib/components/auth-form/index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,31 @@
import Card from '$lib/components/card/index.svelte';
import { onMount } from 'svelte';
import { formComposable } from './store';
import { store } from './store';
import { handleInputChange } from './utils';
import { checkIsEmpty } from '$lib/utils/validations';
let isLoading = false;
let errorMessage: string | undefined;
let username = '';
let password = '';
let isUsernameValid = true;
let isPasswordValid = true;
let isFormHasChanges = false;
const { setUsername, setPassword, handleSubmit, formState, abortController } = formComposable();
const { setUsername, setPassword, handleSubmit, formState, abortController } = store();
const handleUsernameChange = handleInputChange(setUsername);
const handlePasswordChange = handleInputChange(setPassword);
onMount(() => {
const unsubscribeFormState = formState.subscribe((value) => {
isLoading = value.isLoading;
errorMessage = value.error;
isUsernameValid = !value.username.hasChanges ? true : value.username.isValid;
isPasswordValid = !value.password.hasChanges ? true : value.password.isValid;
errorMessage = value.errorMessage;
username = value.fields.username.value;
password = value.fields.password.value;
isUsernameValid = !value.fields.username.hasChanges ? true : value.fields.username.isValid;
isPasswordValid = !value.fields.password.hasChanges ? true : value.fields.password.isValid;
isFormHasChanges = value.hasChanges;
});
Expand All @@ -44,6 +48,7 @@
labelText="Username"
id="username"
invalid={!isUsernameValid}
value={username}
on:change={(e) => handleUsernameChange(e.detail)}
invalidText="This field is required"
placeholder="Enter username"
Expand All @@ -54,13 +59,14 @@
labelText="Password"
id="password"
type="password"
value={password}
invalid={!isPasswordValid}
invalidText="This field is required"
placeholder="Enter password"
on:change={(e) => handlePasswordChange(e.detail)}
/>
{#if !checkIsEmpty(errorMessage)}
<InlineNotification kind="error" subtitle={errorMessage} />
<InlineNotification kind="error" subtitle={errorMessage} hideCloseButton />
{/if}
<Button
type="submit"
Expand Down
46 changes: 14 additions & 32 deletions frontend-admin/src/lib/components/auth-form/store.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import { get } from 'svelte/store';
import { goto } from '$app/navigation';
import { writable } from 'svelte/store';

import { initialFormState } from './consts';
import { authRequest } from '$lib/utils/requests/auth-request';
import { requestsWrapper } from '$lib/utils/requests/request-wrapper';
import { initialValues } from './consts';
import { authRequest, type TAuthParams } from '$lib/utils/requests/auth-request';
import { checkIsEmpty } from '$lib/utils/validations';
import { formComposable } from '$lib/composable';

export const formComposable = () => {
const formState = writable(initialFormState);
export const store = () => {
const { formState, abortController, handleSubmit } = formComposable<string, TAuthParams>({
initialValues,
onSuccess: (data) => {
localStorage.setItem('token', data);
goto('/animals');
},
request: authRequest
});

const setUsername = (value: string) => {
formState.update((state) => ({
...state,
// hasChanges: true && state.fields.hasChanges
hasChanges: true && state.fields.password.hasChanges,
fields: {
...state.fields,
username: {
Expand All @@ -27,7 +32,7 @@ export const formComposable = () => {
const setPassword = (value: string) => {
formState.update((state) => ({
...state,
// hasChanges: true && state.username.hasChanges,
hasChanges: true && state.fields.username.hasChanges,
fields: {
...state.fields,
password: {
Expand All @@ -39,29 +44,6 @@ export const formComposable = () => {
}));
};

const setError = (value?: string) => {
formState.update((state) => ({ ...state, error: value }));
};

const setIsLoading = (loading: boolean) =>
formState.update((state) => ({ ...state, isLoading: loading }));

const abortController = new AbortController();
const handleSubmit = async () => {
const { password, username } = get(formState).fields;
await requestsWrapper({
setLoadingState: setIsLoading,
onError: setError,
requestParams: { username: username.value, password: password.value },
onSuccess: (data: string) => {
localStorage.setItem('token', data);
goto('/animals');
},
request: authRequest,
abortController
});
};

return {
setUsername,
setPassword,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,43 @@ import { requestsWrapper } from '$lib/utils/requests/request-wrapper';
import { extendValuesWithMeta } from './utils';
import type { TFormComposableParams } from './types';

export const formComposable = ({ initialValues, request, onSuccess }: TFormComposableParams) => {
export const formComposable = <
TResponseParams = unknown,
TFields extends object = Record<string, unknown>
// TRequestParams extends object = Record<string, any>,
>({
initialValues,
request,
onSuccess
}: TFormComposableParams<TResponseParams, TFields, TFields>) => {
const extendedValues = extendValuesWithMeta(initialValues);
const formState = writable(extendedValues);

const setError = (value?: string) => {
formState.update((state) => ({ ...state, error: value }));
formState.set(extendedValues);
formState.update((state) => ({ ...state, errorMessage: value }));
};

const setIsLoading = (loading: boolean) =>
formState.update((state) => ({ ...state, isLoading: loading }));

const abortController = new AbortController();
const handleSubmit = async () => {
const { password, username } = get(formState).fields;
const requestParams: TFields = {} as TFields;

const fields = get(formState).fields;
(
Object.entries(fields) as [
[keyof typeof fields, (typeof extendedValues)['fields'][keyof typeof fields]]
]
).forEach(([key, value]) => {
requestParams[key] = value.value;
});

await requestsWrapper({
setLoadingState: setIsLoading,
onError: setError,
requestParams: { username: username.value, password: password.value },
requestParams,
onSuccess,
request,
abortController
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ export type ValuesWithMeta<TFields extends object = Record<string, unknown>> = {
};

export type TFormComposableParams<
TFields extends object = Record<string, unknown>,
TResponseParams = unknown,
TRequestParams = unknown
TRequestParams = unknown,
TFields extends object = Record<string, unknown>
> = {
initialValues: TFields;
request: (requestParams: TRequestParams, abortController: AbortController) => Promise<Response>;
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion frontend-admin/src/lib/utils/requests/auth-request.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
type TAuthParams = {
export type TAuthParams = {
username: string;
password: string;
};
Expand Down
1 change: 1 addition & 0 deletions frontend-admin/src/lib/utils/requests/request-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const requestsWrapper = async <TRequestParams, TResponseParams>({
throw new Error(response.status.toString());
}
onSuccess(data);
onError('');
} catch (error: unknown) {
onError(requestErrorHandler(response?.status, data.detail));
}
Expand Down

0 comments on commit 4d6e944

Please sign in to comment.