front-hub/src/stores/user.ts

279 lines
8.8 KiB
TypeScript
Raw Normal View History

2023-06-24 18:17:43 +00:00
import { PatchUserRequest, UserDocumentTypes, UserDocuments, UserSettingsFieldStatus, UserSettingsField, User } from "@root/model/user";
2023-05-30 18:34:41 +00:00
import { produce } from "immer";
2023-05-17 11:20:11 +00:00
import { create } from "zustand";
import { createJSONStorage, devtools, persist } from "zustand/middleware";
2023-05-30 18:34:41 +00:00
import { StringSchema, string } from "yup";
import { patchUser } from "@root/api/user";
2023-06-24 18:17:43 +00:00
import { UserAccount, UserAccountSettingsFieldStatus, UserName, VerificationStatus } from "@root/model/account";
import { patchUserAccount } from "@root/api/account";
2023-06-30 15:35:31 +00:00
import { deleteCart, patchCart } from "@root/api/cart";
2023-05-17 11:20:11 +00:00
interface UserStore {
userId: string | null;
2023-06-24 18:17:43 +00:00
user: User | null;
userAccount: UserAccount | null;
settingsFields: (
UserSettingsFieldStatus &
UserAccountSettingsFieldStatus &
{ hasError: boolean; }
);
2023-06-02 08:22:14 +00:00
verificationStatus: VerificationStatus;
verificationType: "juridical" | "nko";
isDocumentsDialogOpen: boolean;
dialogType: "juridical" | "nko";
documents: UserDocuments;
2023-05-17 11:20:11 +00:00
}
2023-05-30 18:34:41 +00:00
const defaultFieldValues = {
value: "",
error: null,
touched: false,
};
2023-06-24 18:17:43 +00:00
const defaultFields: UserStore["settingsFields"] = {
firstname: { ...defaultFieldValues },
secondname: { ...defaultFieldValues },
middlename: { ...defaultFieldValues },
orgname: { ...defaultFieldValues },
2023-05-30 18:34:41 +00:00
email: { ...defaultFieldValues },
phoneNumber: { ...defaultFieldValues },
password: { ...defaultFieldValues },
2023-06-24 18:17:43 +00:00
hasError: false,
2023-05-30 18:34:41 +00:00
};
2023-06-02 08:22:14 +00:00
const defaultDocument = {
file: null,
uploadedFileName: null,
imageSrc: null,
};
2023-05-17 11:20:11 +00:00
const initialState: UserStore = {
userId: null,
user: null,
2023-06-24 18:17:43 +00:00
userAccount: null,
2023-05-30 18:34:41 +00:00
settingsFields: { ...defaultFields },
2023-06-02 08:22:14 +00:00
verificationStatus: "notVerificated",
verificationType: "juridical",
isDocumentsDialogOpen: false,
dialogType: "juridical",
documents: {
"ИНН": { ...defaultDocument },
"Устав": { ...defaultDocument },
"Свидетельство о регистрации НКО": { ...defaultDocument },
2023-06-30 15:35:31 +00:00
},
2023-05-17 11:20:11 +00:00
};
export const useUserStore = create<UserStore>()(
persist(
devtools(
(set, get) => initialState,
{
2023-06-30 15:35:31 +00:00
name: "User",
2023-05-30 18:34:41 +00:00
enabled: process.env.NODE_ENV === "development",
2023-06-30 15:35:31 +00:00
trace: true,
2023-05-17 11:20:11 +00:00
}
),
{
2023-06-24 18:17:43 +00:00
version: 2,
2023-05-17 11:20:11 +00:00
name: "user",
storage: createJSONStorage(() => localStorage),
2023-05-30 18:34:41 +00:00
partialize: state => ({
userId: state.userId,
user: state.user,
2023-06-24 18:17:43 +00:00
}),
migrate: (persistedState, version) => ({
...persistedState as UserStore,
user: null,
}),
2023-05-17 11:20:11 +00:00
}
)
);
export const setUserId = (userId: string | null) => useUserStore.setState({ userId });
2023-06-02 08:22:14 +00:00
2023-06-24 18:17:43 +00:00
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 ?? "";
2023-06-30 15:35:31 +00:00
}),
false,
{
type: "setUserAccount",
payload: user,
}
);
export const setCart = (cart: string[]) => useUserStore.setState(
produce<UserStore>(state => {
if (state.userAccount) state.userAccount.cart = cart;
2023-06-24 18:17:43 +00:00
})
);
export const clearUserData = () => useUserStore.setState({ ...initialState });
2023-06-02 08:22:14 +00:00
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) {
2023-06-24 18:17:43 +00:00
console.log("Error creating object url", error);
2023-06-02 08:22:14 +00:00
}
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 = (
2023-06-24 18:17:43 +00:00
fieldName: UserSettingsField | keyof UserName,
2023-05-30 18:34:41 +00:00
value: string,
2023-06-02 08:22:14 +00:00
) => useUserStore.setState(
produce<UserStore>(state => {
if (!state.settingsFields) return;
2023-05-30 18:34:41 +00:00
2023-06-02 08:22:14 +00:00
let errorMessage: string | null = null;
2023-05-30 18:34:41 +00:00
2023-06-02 08:22:14 +00:00
try {
2023-07-05 02:40:48 +00:00
if (value) validators[fieldName].validateSync(value);
2023-06-02 08:22:14 +00:00
} catch (error: any) {
errorMessage = error.message;
}
2023-05-30 18:34:41 +00:00
state.settingsFields[fieldName].value = value || "";
state.settingsFields[fieldName].touched = true;
state.settingsFields[fieldName].error = errorMessage;
2023-06-24 18:17:43 +00:00
state.settingsFields.hasError = Object.values(state.settingsFields).reduce((acc: boolean, field) => {
2023-06-30 15:35:31 +00:00
if (typeof field === "boolean") return acc;
2023-06-24 18:17:43 +00:00
if (field.error !== null) return true;
return acc;
}, false);
2023-06-02 08:22:14 +00:00
})
);
2023-05-30 18:34:41 +00:00
export const sendUserData = async () => {
const state = useUserStore.getState();
if (!state.settingsFields) return;
2023-06-24 18:17:43 +00:00
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 = {};
if (state.settingsFields.email.value.length !== 0) userPayload.email = state.settingsFields.email.value;
if (state.settingsFields.password.value.length !== 0) userPayload.password = state.settingsFields.password.value;
if (state.settingsFields.phoneNumber.value.length !== 0) userPayload.phoneNumber = state.settingsFields.phoneNumber.value;
2023-06-24 18:17:43 +00:00
const userAccountPayload: UserName = {
firstname: state.settingsFields.firstname.value,
secondname: state.settingsFields.secondname.value,
middlename: state.settingsFields.middlename.value,
orgname: state.settingsFields.orgname.value,
};
2023-06-30 15:35:31 +00:00
await Promise.all([
2023-06-24 18:17:43 +00:00
isPatchingUser && patchUser(userPayload),
isPatchingUserAccount && patchUserAccount(userAccountPayload),
]);
2023-06-30 15:35:31 +00:00
};
export const addTariffToCart = async (tariffId: string) => {
const result = await patchCart(tariffId);
setCart(result);
};
2023-06-24 18:17:43 +00:00
2023-06-30 15:35:31 +00:00
export const removeTariffFromCart = async (tariffId: string) => {
const result = await deleteCart(tariffId);
setCart(result);
2023-05-30 18:34:41 +00:00
};
2023-05-17 11:20:11 +00:00
2023-06-24 18:17:43 +00:00
const validators: Record<UserSettingsField | keyof UserName, StringSchema> = {
2023-05-30 18:34:41 +00:00
email: string().email("Неверный email"),
phoneNumber: string().matches(/^[+\d|\d]*$/, "Неверный номер телефона").min(6, "Номер телефона должен содержать минимум 6 символов"),
2023-07-05 02:40:48 +00:00
password: string().min(8, "Минимум 8 символов").matches(/^[.,:;-_+\d\w]+$/, "Некорректные символы в пароле").optional(),
2023-06-24 18:17:43 +00:00
firstname: string(),
secondname: string(),
middlename: string(),
orgname: string(),
2023-05-30 18:34:41 +00:00
};