front-hub/src/stores/user.ts

320 lines
9.1 KiB
TypeScript
Raw Normal View History

2023-07-06 21:52:07 +00:00
import {
2023-11-05 23:33:40 +00:00
PatchUserRequest,
UserDocumentTypes,
UserDocuments,
UserDocumentsUrl,
UserSettingsFieldStatus,
UserSettingsField,
} 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 { UserAccountSettingsFieldStatus, VerificationStatus } from "@root/model/account"
import { patchCurrency, deleteCart, patchCart } from "@root/api/cart"
import { User, UserAccount, UserName, getInitials, patchUserAccount } from "@frontend/kitui"
import { setNotEnoughMoneyAmount } from "./cart";
2023-05-17 11:20:11 +00:00
interface UserStore {
2023-09-11 19:42:39 +00:00
userId: string | null;
user: User | null;
userAccount: UserAccount | null;
settingsFields: UserSettingsFieldStatus & UserAccountSettingsFieldStatus & { hasError: boolean };
verificationStatus: VerificationStatus;
verificationType: "juridical" | "nko";
isDocumentsDialogOpen: boolean;
2023-10-27 23:13:54 +00:00
dialogType: "juridical" | "nko" | "";
2023-09-11 19:42:39 +00:00
documents: UserDocuments;
documentsUrl: UserDocumentsUrl;
comment: string;
initials: string;
2023-05-17 11:20:11 +00:00
}
2023-05-30 18:34:41 +00:00
const defaultFieldValues = {
2023-11-05 23:33:40 +00:00
value: "",
error: null,
touched: false,
}
2023-05-30 18:34:41 +00:00
2023-06-24 18:17:43 +00:00
const defaultFields: UserStore["settingsFields"] = {
2023-11-05 23:33:40 +00:00
firstname: { ...defaultFieldValues },
secondname: { ...defaultFieldValues },
middlename: { ...defaultFieldValues },
orgname: { ...defaultFieldValues },
email: { ...defaultFieldValues },
phoneNumber: { ...defaultFieldValues },
password: { ...defaultFieldValues },
hasError: false,
}
2023-05-30 18:34:41 +00:00
2023-07-06 21:52:07 +00:00
export const defaultDocument = {
2023-11-05 23:33:40 +00:00
file: null,
uploadedFileName: null,
imageSrc: null,
}
2023-06-02 08:22:14 +00:00
2023-05-17 11:20:11 +00:00
const initialState: UserStore = {
2023-11-05 23:33:40 +00:00
userId: null,
user: null,
userAccount: null,
settingsFields: { ...defaultFields },
verificationStatus: VerificationStatus.NOT_VERIFICATED,
verificationType: "juridical",
isDocumentsDialogOpen: false,
dialogType: "",
comment: "",
documents: {
ИНН: { ...defaultDocument },
Устав: { ...defaultDocument },
"Свидетельство о регистрации НКО": { ...defaultDocument },
},
documentsUrl: {
ИНН: "",
Устав: "",
"Свидетельство о регистрации НКО": "",
},
initials: "AA",
}
2023-05-17 11:20:11 +00:00
export const useUserStore = create<UserStore>()(
2023-11-05 23:33:40 +00:00
persist(
devtools((set, get) => initialState, {
name: "User",
enabled: process.env.NODE_ENV === "development",
trace: true,
}),
{
version: 2,
name: "user",
storage: createJSONStorage(() => localStorage),
partialize: (state) => ({ // список полей для хранения в ЛС
userId: state.userId,
user: state.user,
}),
migrate: (persistedState, version) => ({
...(persistedState as UserStore),
user: null,
}),
}
)
)
2023-05-17 11:20:11 +00:00
2023-07-06 21:52:07 +00:00
export const setVerificationStatus = (verificationStatus: VerificationStatus) =>
2023-11-05 23:33:40 +00:00
useUserStore.setState({ verificationStatus })
2023-07-06 21:52:07 +00:00
2023-07-25 22:31:04 +00:00
export const setVerificationType = (verificationType: "nko" | "org") =>
2023-11-05 23:33:40 +00:00
useUserStore.setState({
verificationType: verificationType === "org" ? "juridical" : "nko",
})
2023-07-25 22:31:04 +00:00
2023-11-05 23:33:40 +00:00
export const setUserId = (userId: string | null) => useUserStore.setState({ userId })
2023-07-06 21:52:07 +00:00
export const setUser = (user: User) =>
2023-11-05 23:33:40 +00:00
useUserStore.setState(
produce<UserStore>((state) => {
state.user = user
2023-06-24 18:17:43 +00:00
2023-11-05 23:33:40 +00:00
state.settingsFields.email.value = user?.email ?? ""
state.settingsFields.phoneNumber.value = user?.phoneNumber ?? ""
state.settingsFields.password.value = ""
})
)
2023-06-24 18:17:43 +00:00
2023-07-06 21:52:07 +00:00
export const setUserAccount = (user: UserAccount) =>
2023-11-05 23:33:40 +00:00
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 ?? ""
state.initials = getInitials(state.settingsFields.firstname.value, state.settingsFields.secondname.value)
}),
false,
{
type: "setUserAccount",
payload: user,
}
)
2023-06-30 15:35:31 +00:00
2023-07-06 21:52:07 +00:00
export const setCart = (cart: string[]) =>
2023-11-05 23:33:40 +00:00
useUserStore.setState(
produce<UserStore>((state) => {
if (state.userAccount) state.userAccount.cart = cart
})
)
2023-07-06 21:52:07 +00:00
2023-11-05 23:33:40 +00:00
export const setComment = (comment: string) => useUserStore.setState({ comment })
2023-06-24 18:17:43 +00:00
2023-11-05 23:33:40 +00:00
export const clearUserData = () => useUserStore.setState({ ...initialState })
2023-06-24 18:17:43 +00:00
2023-07-06 21:52:07 +00:00
export const openDocumentsDialog = (type: UserStore["dialogType"]) =>
2023-11-05 23:33:40 +00:00
useUserStore.setState(
produce<UserStore>((state) => {
state.isDocumentsDialogOpen = true
state.dialogType = type
})
)
2023-06-02 08:22:14 +00:00
2023-07-06 21:52:07 +00:00
export const closeDocumentsDialog = () =>
2023-11-05 23:33:40 +00:00
useUserStore.setState(
produce<UserStore>((state) => {
state.isDocumentsDialogOpen = false
state.dialogType = ""
})
)
2023-07-06 21:52:07 +00:00
export const setDocument = (type: UserDocumentTypes, file: File | null) =>
2023-11-05 23:33:40 +00:00
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,
}
})
)
2023-07-06 21:52:07 +00:00
2023-07-18 10:47:14 +00:00
export const setDocumentUrl = (type: UserDocumentTypes, url: string) =>
2023-11-05 23:33:40 +00:00
useUserStore.setState(
produce<UserStore>((state) => {
if (!url) {
state.documentsUrl[type] = ""
return
}
2023-09-11 19:42:39 +00:00
2023-11-05 23:33:40 +00:00
state.documentsUrl[type] = url
})
)
2023-09-11 19:42:39 +00:00
export const setUploadedDocument = (type: UserDocumentTypes, fileName: string, url: string) =>
2023-11-05 23:33:40 +00:00
useUserStore.setState(
produce<UserStore>((state) => {
state.documents[type] = {
file: null,
uploadedFileName: fileName,
imageSrc: url,
}
})
)
2023-09-11 19:42:39 +00:00
2023-10-27 23:13:54 +00:00
export const setSettingsField = (fieldName: UserSettingsField | keyof UserName, value: string) =>
2023-11-05 23:33:40 +00:00
useUserStore.setState(
produce<UserStore>((state) => {
if (!state.settingsFields) return
2023-09-11 19:42:39 +00:00
2023-11-05 23:33:40 +00:00
let errorMessage: string | null = null
2023-09-11 19:42:39 +00:00
2023-11-05 23:33:40 +00:00
try {
if (value) validators[fieldName].validateSync(value)
} catch (error: any) {
errorMessage = error.message
}
2023-09-11 19:42:39 +00:00
2023-11-05 23:33:40 +00:00
state.settingsFields[fieldName].value = value || ""
state.settingsFields[fieldName].touched = true
state.settingsFields[fieldName].error = errorMessage
2023-09-11 19:42:39 +00:00
2023-11-05 23:33:40 +00:00
state.settingsFields.hasError = Object.values(state.settingsFields).reduce((acc: boolean, field) => {
if (typeof field === "boolean") return acc
2023-09-11 19:42:39 +00:00
2023-11-05 23:33:40 +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 () => {
2023-11-05 23:33:40 +00:00
const state = useUserStore.getState()
if (!state.settingsFields) return
2023-09-11 19:42:39 +00:00
2023-11-05 23:33:40 +00:00
const isPatchingUser =
2023-09-11 19:42:39 +00:00
state.settingsFields.email.touched ||
state.settingsFields.password.touched ||
2023-11-05 23:33:40 +00:00
state.settingsFields.phoneNumber.touched
2023-09-11 19:42:39 +00:00
2023-11-05 23:33:40 +00:00
const isPatchingUserAccount =
2023-09-11 19:42:39 +00:00
state.settingsFields.firstname.touched ||
state.settingsFields.secondname.touched ||
state.settingsFields.middlename.touched ||
2023-11-05 23:33:40 +00:00
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
const userAccountPayload: UserName = {
firstname: state.settingsFields.firstname.value,
secondname: state.settingsFields.secondname.value,
middlename: state.settingsFields.middlename.value,
orgname: state.settingsFields.orgname.value,
}
await Promise.all([
isPatchingUser && patchUser(userPayload).then(([user]) => user && setUser(user)),
isPatchingUserAccount && patchUserAccount(userAccountPayload).then(setUserAccount),
])
}
2023-06-30 15:35:31 +00:00
export const addTariffToCart = async (tariffId: string) => {
2023-11-05 23:33:40 +00:00
const [patchCartResponse, patchCartError] = await patchCart(tariffId)
2023-08-30 09:56:14 +00:00
2023-11-05 23:33:40 +00:00
if (patchCartError === undefined) {
setCart(patchCartResponse)
}
return({patchCartResponse, patchCartError})
}
2023-06-24 18:17:43 +00:00
2023-06-30 15:35:31 +00:00
export const removeTariffFromCart = async (tariffId: string) => {
setNotEnoughMoneyAmount(0);
2023-11-05 23:33:40 +00:00
const [deleteCartResponse, deleteCartError] = await deleteCart(tariffId)
2023-08-30 09:56:14 +00:00
2023-11-05 23:33:40 +00:00
if (!deleteCartError) {
setCart(deleteCartResponse)
}
}
2023-05-17 11:20:11 +00:00
2023-07-07 13:53:08 +00:00
export const changeUserCurrency = async (currency: string) => {
2023-11-05 23:33:40 +00:00
const [patchCurrencyResponse, patchCurrencyError] = await patchCurrency(currency)
2023-08-30 09:56:14 +00:00
2023-11-05 23:33:40 +00:00
if (!patchCurrencyError && patchCurrencyResponse) {
setUserAccount(patchCurrencyResponse)
}
}
2023-07-07 13:53:08 +00:00
2023-06-24 18:17:43 +00:00
const validators: Record<UserSettingsField | keyof UserName, StringSchema> = {
2023-11-05 23:33:40 +00:00
email: string().email("Неверный email"),
phoneNumber: string()
.matches(/^[+\d|\d]*$/, "Неверный номер телефона")
.min(6, "Номер телефона должен содержать минимум 6 символов"),
password: string()
.min(8, "Минимум 8 символов")
2024-04-16 09:29:28 +00:00
.matches(/^[.,:;\-_+!&()*<>\[\]\{\}`@"#$\%\^\=?\d\w]+$/, "Некорректные символы в пароле")
2023-11-05 23:33:40 +00:00
.optional(),
firstname: string(),
secondname: string(),
middlename: string(),
orgname: string(),
}