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