feat: implement state with effector instead of zustand

This commit is contained in:
2025-03-12 11:44:49 +05:00
parent 815eb9081a
commit 18930e1426
6 changed files with 99 additions and 30 deletions
BIN
View File
Binary file not shown.
+2
View File
@@ -20,6 +20,8 @@
"@tinymce/tinymce-react": "^5.1.1",
"countries-phone-masks": "^1.1.0",
"date-fns": "^3.6.0",
"effector": "^23.3.0",
"effector-react": "^23.3.0",
"framer-motion": "^11.17.0",
"html-react-parser": "^5.1.18",
"jose": "^5.9.3",
+3 -2
View File
@@ -1,14 +1,15 @@
import { categories } from '@/consts/categories';
import PlusIcon from '../../../public/icons/plus.svg';
import { useConfigurationStore } from '@/stores/useConfigurationStore';
import { imagesCategories } from '@/consts/categories';
import { $configurationStore } from '@/stores/configurator-store/configurationStore';
import { useUnit } from 'effector-react';
function CategoryCounter({
titleCategory,
}: {
titleCategory: keyof typeof categories;
}) {
const { configuration, setConfiguration } = useConfigurationStore();
const configuration = useUnit($configurationStore);
const arrayCounters = categories[titleCategory];
const isAdvertisementMaterials =
Array.isArray(arrayCounters) &&
@@ -0,0 +1,66 @@
import {
Ads,
Design,
Details,
Equipment,
ExtraSeasons,
OptionFeatures,
Remote,
} from '../useConfigurationStore';
import { combine, createStore, createEvent } from 'effector';
interface OptionObjectEffector<T> {
allowMultiple: boolean;
opts: T;
}
export const setEquipment = createEvent<Equipment>();
export const setDesign = createEvent<Design>();
export const toggleOption = createEvent<OptionFeatures>();
export const toggleSeason = createEvent<ExtraSeasons>();
const $equipment = createStore<OptionObjectEffector<Equipment>>({
allowMultiple: false,
opts: 'Настенная панель',
}).on(setEquipment, (state, payload) => ({ ...state, opts: payload }));
const $details = createStore<Details>(300);
const $design = createStore<OptionObjectEffector<Design>>({
allowMultiple: false,
opts: 'WhiteBox.Квартиры без интерьеров',
}).on(setDesign, (state, payload) => ({ ...state, opts: payload }));
const $options = createStore<OptionObjectEffector<OptionFeatures[]>>({
allowMultiple: true,
opts: ['Аватар клиента', 'Интерактивное окно'],
}).on(toggleOption, (state, payload) => ({
...state,
opts: state.opts.includes(payload)
? state.opts.filter((opt) => opt !== payload)
: [...state.opts, payload],
}));
const $seasons = createStore<OptionObjectEffector<ExtraSeasons[]>>({
allowMultiple: true,
opts: [],
}).on(toggleSeason, (state, payload) => ({
...state,
opts: state.opts.includes(payload)
? state.opts.filter((opt) => opt !== payload)
: [...state.opts, payload],
}));
const $ads = createStore<Ads>([0, 1]);
const $remote = createStore<Remote>(0);
export const $configurationStore = combine({
Оборудование: $equipment,
'Детальная проработка окружения': $details,
'Дизайн интерьеров': $design,
Опции: $options,
Сезонность: $seasons,
'Рекламные материалы': $ads,
'Удаленная демонстрация': $remote,
});
+9 -3
View File
@@ -36,12 +36,18 @@ export type OptionFeatures =
export type ExtraSeasons = 'Лето' | 'Зима' | 'Весна' | 'Осень';
export type Details = 300 | 500 | 700 | 1000;
export type Ads = [number, number];
export type Remote = number;
export interface IConfiguration {
Оборудование: {
allowMultiple: false;
opts: Equipment;
};
'Детальная проработка окружения': 300 | 500 | 700 | 1000;
'Детальная проработка окружения': Details;
'Дизайн интерьеров': {
allowMultiple: false;
opts: Design;
@@ -54,8 +60,8 @@ export interface IConfiguration {
allowMultiple: true;
opts: ExtraSeasons[];
};
'Рекламные материалы': [number, number];
'Удаленная демонстрация': number;
'Рекламные материалы': Ads;
'Удаленная демонстрация': Remote;
}
export const useConfigurationStore = create<{
+19 -25
View File
@@ -3,11 +3,17 @@ import {
Equipment,
ExtraSeasons,
OptionFeatures,
OptionObject,
OptionTitles,
useConfigurationStore,
} from '@/stores/useConfigurationStore';
import { PropsWithChildren } from 'react';
import { useUnit } from 'effector-react';
import {
$configurationStore,
setEquipment,
setDesign,
toggleOption,
toggleSeason,
} from '@/stores/configurator-store/configurationStore';
function CheckboxItem<T extends keyof OptionTitles, V extends OptionTitles[T]>({
titleCategory,
@@ -21,36 +27,24 @@ function CheckboxItem<T extends keyof OptionTitles, V extends OptionTitles[T]>({
item: Equipment | Design | OptionFeatures | ExtraSeasons;
className?: string;
}>) {
const { configuration, setConfiguration } = useConfigurationStore();
const { allowMultiple, opts } = configuration[titleCategory] as OptionObject;
const configurator = useUnit($configurationStore);
const { allowMultiple, opts } = configurator[titleCategory];
function handleCheck(item: V[number]) {
if (typeof opts === 'number') {
return;
}
if (!Array.isArray(opts)) {
setConfiguration({
...configuration,
[titleCategory]: { allowMultiple, opts: item },
});
} else {
if (opts.includes(item as OptionFeatures & ExtraSeasons)) {
setConfiguration({
...configuration,
[titleCategory]: {
allowMultiple,
opts: opts.filter((i) => i !== item),
},
});
} else {
setConfiguration({
...configuration,
[titleCategory]: { allowMultiple, opts: [...opts, item] },
});
}
if (titleCategory === 'Оборудование') {
setEquipment(item as Equipment);
} else if (titleCategory === 'Дизайн интерьеров') {
setDesign(item as Design);
} else if (titleCategory === 'Опции') {
toggleOption(item as OptionFeatures);
} else if (titleCategory === 'Сезонность') {
toggleSeason(item as ExtraSeasons);
}
}
return (
<label
className={`relative p-3 bg-[#37393B99] rounded-2xl flex-shrink-0 flex flex-col items-start justify-between snap-always ${className} ${