front-hub/src/stores/user.ts
2023-06-24 21:17:43 +03:00

259 lines
8.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { PatchUserRequest, UserDocumentTypes, UserDocuments, UserSettingsFieldStatus, UserSettingsField, User } from "@root/model/user";
import { produce } from "immer";
import { create } from "zustand";
import { createJSONStorage, devtools, persist } from "zustand/middleware";
import { StringSchema, string } from "yup";
import { patchUser } from "@root/api/user";
import { UserAccount, UserAccountSettingsFieldStatus, UserName, VerificationStatus } from "@root/model/account";
import { patchUserAccount } from "@root/api/account";
interface UserStore {
userId: string | null;
user: User | null;
userAccount: UserAccount | null;
settingsFields: (
UserSettingsFieldStatus &
UserAccountSettingsFieldStatus &
{ hasError: boolean; }
);
verificationStatus: VerificationStatus;
verificationType: "juridical" | "nko";
isDocumentsDialogOpen: boolean;
dialogType: "juridical" | "nko";
documents: UserDocuments;
}
const defaultFieldValues = {
value: "",
error: null,
touched: false,
};
const defaultFields: UserStore["settingsFields"] = {
firstname: { ...defaultFieldValues },
secondname: { ...defaultFieldValues },
middlename: { ...defaultFieldValues },
orgname: { ...defaultFieldValues },
email: { ...defaultFieldValues },
phoneNumber: { ...defaultFieldValues },
password: { ...defaultFieldValues },
hasError: false,
};
const defaultDocument = {
file: null,
uploadedFileName: null,
imageSrc: null,
};
const initialState: UserStore = {
userId: null,
user: null,
userAccount: null,
settingsFields: { ...defaultFields },
verificationStatus: "notVerificated",
verificationType: "juridical",
isDocumentsDialogOpen: false,
dialogType: "juridical",
documents: {
"ИНН": { ...defaultDocument },
"Устав": { ...defaultDocument },
"Свидетельство о регистрации НКО": { ...defaultDocument },
}
};
export const useUserStore = create<UserStore>()(
persist(
devtools(
(set, get) => initialState,
{
name: "User store",
enabled: process.env.NODE_ENV === "development",
}
),
{
version: 2,
name: "user",
storage: createJSONStorage(() => localStorage),
partialize: state => ({
userId: state.userId,
user: state.user,
}),
migrate: (persistedState, version) => ({
...persistedState as UserStore,
user: null,
}),
}
)
);
export const setUserId = (userId: string | null) => useUserStore.setState({ userId });
export const setUser = (user: User) => useUserStore.setState(
produce<UserStore>(state => {
state.user = user;
state.settingsFields.email.value = user?.email ?? "";
state.settingsFields.phoneNumber.value = user?.phoneNumber ?? "";
state.settingsFields.password.value = "";
})
);
export const setUserAccount = (user: UserAccount) => useUserStore.setState(
produce<UserStore>(state => {
state.userAccount = user;
state.settingsFields.firstname.value = user?.name.firstname ?? "";
state.settingsFields.secondname.value = user?.name.secondname ?? "";
state.settingsFields.middlename.value = user?.name.middlename ?? "";
state.settingsFields.orgname.value = user?.name.orgname ?? "";
})
);
export const clearUserData = () => useUserStore.setState({ ...initialState });
export const openDocumentsDialog = (type: UserStore["dialogType"]) => useUserStore.setState(
produce<UserStore>(state => {
state.isDocumentsDialogOpen = true;
state.dialogType = type;
})
);
export const closeDocumentsDialog = () => useUserStore.setState(
produce<UserStore>(state => {
state.isDocumentsDialogOpen = false;
})
);
export const setDocument = (type: UserDocumentTypes, file: File | undefined) => useUserStore.setState(
produce<UserStore>(state => {
if (!file) {
state.documents[type] = { ...defaultDocument };
return;
}
let imageSrc: string | null = null;
try {
const src = state.documents[type].imageSrc;
if (src) URL.revokeObjectURL(src);
imageSrc = URL.createObjectURL(file);
} catch (error) {
console.log("Error creating object url", error);
}
state.documents[type] = {
file,
uploadedFileName: null,
imageSrc,
};
})
);
export const setUploadedDocument = (type: UserDocumentTypes, fileName: string, url: string) => useUserStore.setState(
produce<UserStore>(state => {
state.documents[type] = {
file: null,
uploadedFileName: fileName,
imageSrc: url,
};
})
);
export const sendDocuments = () => {
const state = useUserStore.getState();
const type = state.dialogType;
const documents = state.documents;
// const formData = new FormData();
// formData.append("file1", file1);
// formData.append("file2", file2);
// revoke on success
// Object.values(documents).map(document => document?.imageSrc).forEach(src => {
// if (src) URL.revokeObjectURL(src);
// });
// useUserStore.setState(produce<UserStore>(state => {
// state.isDocumentsDialogOpen = false;
// }));
};
export const setSettingsField = (
fieldName: UserSettingsField | keyof UserName,
value: string,
) => useUserStore.setState(
produce<UserStore>(state => {
if (!state.settingsFields) return;
let errorMessage: string | null = null;
try {
validators[fieldName].validateSync(value);
} catch (error: any) {
errorMessage = error.message;
}
state.settingsFields[fieldName].value = value || "";
state.settingsFields[fieldName].touched = true;
state.settingsFields[fieldName].error = errorMessage;
state.settingsFields.hasError = Object.values(state.settingsFields).reduce((acc: boolean, field) => {
if (typeof field == "boolean") return acc;
if (field.error !== null) return true;
return acc;
}, false);
})
);
export const sendUserData = async () => {
const state = useUserStore.getState();
if (!state.settingsFields) return;
const isPatchingUser =
state.settingsFields.email.touched ||
state.settingsFields.password.touched ||
state.settingsFields.phoneNumber.touched;
const isPatchingUserAccount =
state.settingsFields.firstname.touched ||
state.settingsFields.secondname.touched ||
state.settingsFields.middlename.touched ||
state.settingsFields.orgname.touched;
const userPayload: PatchUserRequest = {
email: state.settingsFields.email.value,
password: state.settingsFields.password.value,
phoneNumber: state.settingsFields.phoneNumber.value,
};
const userAccountPayload: UserName = {
firstname: state.settingsFields.firstname.value,
secondname: state.settingsFields.secondname.value,
middlename: state.settingsFields.middlename.value,
orgname: state.settingsFields.orgname.value,
};
const [user, userAccount] = await Promise.all([
isPatchingUser && patchUser(userPayload),
isPatchingUserAccount && patchUserAccount(userAccountPayload),
]);
// if (user) setUser(user);
// if (userAccount) setUserAccount(userAccount);
};
const validators: Record<UserSettingsField | keyof UserName, StringSchema> = {
email: string().email("Неверный email"),
phoneNumber: string().matches(/^[+\d|\d]*$/, "Неверный номер телефона").min(6, "Номер телефона должен содержать минимум 6 символов"),
password: string().min(8, "Минимум 8 символов").matches(/^[.,:;-_+\d\w]+$/, "Некорректные символы в пароле"),
firstname: string(),
secondname: string(),
middlename: string(),
orgname: string(),
};