import { authInstance, languageInstance, languageStore } from "@shared"; import { makeAutoObservable, runInAction } from "mobx"; type Language = "ru" | "en" | "zh"; type StationLanguageData = { name: string; system_name: string; address: string; loaded: boolean; // Indicates if this language's data has been loaded/modified }; type StationCommonData = { city_id: number; direction: boolean; description: string; icon: string; latitude: number; longitude: number; offset_x: number; offset_y: number; transfers: { bus: string; metro_blue: string; metro_green: string; metro_orange: string; metro_purple: string; metro_red: string; train: string; tram: string; trolleybus: string; }; city: string; }; type EditStationData = { [key in Language]: StationLanguageData; } & { common: StationCommonData }; type Station = { id: number; address: string; city: string; city_id: number; description: string; direction: boolean; icon: string; latitude: number; longitude: number; name: string; offset_x: number; offset_y: number; system_name: string; transfers: { bus: string; metro_blue: string; metro_green: string; metro_orange: string; metro_purple: string; metro_red: string; train: string; tram: string; trolleybus: string; }; }; type CreateStationData = { [key in Language]: StationLanguageData; } & { common: StationCommonData }; class StationsStore { stations: Station[] = []; station: Station | null = null; stationLists: { [key in Language]: { data: Station[]; loaded: boolean; }; } = { ru: { data: [], loaded: false, }, en: { data: [], loaded: false, }, zh: { data: [], loaded: false, }, }; // This will store the full station data, keyed by ID and then by language stationPreview: Record< string, Record > = {}; editStationData: EditStationData = { ru: { name: "", system_name: "", address: "", loaded: false, }, en: { name: "", system_name: "", address: "", loaded: false, }, zh: { name: "", system_name: "", address: "", loaded: false, }, common: { city: "", city_id: 0, direction: false, description: "", icon: "", latitude: 0, longitude: 0, offset_x: 0, offset_y: 0, transfers: { bus: "", metro_blue: "", metro_green: "", metro_orange: "", metro_purple: "", metro_red: "", train: "", tram: "", trolleybus: "", }, }, }; createStationData: CreateStationData = { ru: { name: "", system_name: "", address: "", loaded: false, }, en: { name: "", system_name: "", address: "", loaded: false, }, zh: { name: "", system_name: "", address: "", loaded: false, }, common: { city: "", city_id: 0, direction: false, description: "", icon: "", latitude: 0, longitude: 0, offset_x: 0, offset_y: 0, transfers: { bus: "", metro_blue: "", metro_green: "", metro_orange: "", metro_purple: "", metro_red: "", train: "", tram: "", trolleybus: "", }, }, }; constructor() { makeAutoObservable(this); } getStations = async () => { const response = await authInstance.get("/station"); runInAction(() => { this.stations = response.data; }); }; getStationList = async () => { const { language } = languageStore; if (this.stationLists[language].loaded) { return; } const response = await authInstance.get("/station"); runInAction(() => { this.stationLists[language].data = response.data; this.stationLists[language].loaded = true; }); }; setEditCommonData = (data: Partial) => { this.editStationData.common = { ...this.editStationData.common, ...data, }; }; getEditStation = async (id: number) => { const ruResponse = await languageInstance("ru").get(`/station/${id}`); const enResponse = await languageInstance("en").get(`/station/${id}`); const zhResponse = await languageInstance("zh").get(`/station/${id}`); this.editStationData = { ru: { name: ruResponse.data.name, system_name: ruResponse.data.system_name, address: ruResponse.data.address, loaded: true, }, en: { name: enResponse.data.name, system_name: enResponse.data.system_name, address: enResponse.data.address, loaded: true, }, zh: { name: zhResponse.data.name, system_name: zhResponse.data.system_name, address: zhResponse.data.address, loaded: true, }, common: { city: ruResponse.data.city, city_id: ruResponse.data.city_id, direction: ruResponse.data.direction, description: ruResponse.data.description, icon: ruResponse.data.icon, latitude: ruResponse.data.latitude, longitude: ruResponse.data.longitude, offset_x: ruResponse.data.offset_x, offset_y: ruResponse.data.offset_y, transfers: ruResponse.data.transfers, }, }; }; // Sets language-specific station data setLanguageEditStationData = ( language: Language, data: Partial ) => { this.editStationData[language] = { ...this.editStationData[language], ...data, }; }; editStation = async (id: number) => { const commonDataPayload = { city_id: this.editStationData.common.city_id, direction: this.editStationData.common.direction, icon: this.editStationData.common.icon, latitude: this.editStationData.common.latitude, longitude: this.editStationData.common.longitude, offset_x: this.editStationData.common.offset_x, offset_y: this.editStationData.common.offset_y, transfers: this.editStationData.common.transfers, city: this.editStationData.common.city, }; for (const language of ["ru", "en", "zh"] as const) { const { name, address } = this.editStationData[language]; const description = this.editStationData.common.description; const response = await languageInstance(language).patch( `/station/${id}`, { name: name || "", system_name: name || "", // system_name is often derived from name description: description || "", address: address || "", ...commonDataPayload, } ); runInAction(() => { // Update the cached preview data and station lists after successful patch if (this.stationPreview[id]) { this.stationPreview[id][language] = { loaded: true, data: { ...this.stationPreview[id][language].data, id: response.data.id, name: response.data.name, system_name: response.data.system_name, description: response.data.description, address: response.data.address, ...commonDataPayload, } as Station, }; } if (this.stationLists[language].data) { this.stationLists[language].data = this.stationLists[ language ].data.map((station: Station) => station.id === id ? ({ ...station, name: response.data.name, system_name: response.data.system_name, description: description || "", address: response.data.address, ...commonDataPayload, } as Station) : station ); } }); } }; deleteStation = async (id: number) => { await authInstance.delete(`/station/${id}`); runInAction(() => { this.stations = this.stations.filter((station) => station.id !== id); // Also clear from stationPreview cache if (this.stationPreview[id]) { delete this.stationPreview[id]; } // Clear from stationLists as well for all languages for (const lang of ["ru", "en", "zh"] as const) { if (this.stationLists[lang].data) { this.stationLists[lang].data = this.stationLists[lang].data.filter( (station) => station.id !== id ); } } }); }; getStation = async (id: number) => { const response = await authInstance.get(`/station/${id}`); this.station = response.data; }; getStationPreview = async (id: number) => { const { language } = languageStore; if (this.stationPreview[id]?.[language]?.loaded) { return; } const response = await languageInstance(language).get(`/station/${id}`); runInAction(() => { if (!this.stationPreview[id]) { this.stationPreview[id] = { ru: { loaded: false, data: {} as Station }, en: { loaded: false, data: {} as Station }, zh: { loaded: false, data: {} as Station }, }; } this.stationPreview[id][language] = { loaded: true, data: response.data as Station, }; }); }; setCreateCommonData = (data: Partial) => { this.createStationData.common = { ...this.createStationData.common, ...data, }; }; setLanguageCreateStationData = ( language: Language, data: Partial ) => { this.createStationData[language] = { ...this.createStationData[language], ...data, }; }; createStation = async () => { const { language } = languageStore; let commonDataPayload: Partial = { city_id: this.createStationData.common.city_id, direction: this.createStationData.common.direction, icon: this.createStationData.common.icon, latitude: this.createStationData.common.latitude, longitude: this.createStationData.common.longitude, offset_x: this.createStationData.common.offset_x, offset_y: this.createStationData.common.offset_y, transfers: this.createStationData.common.transfers, city: this.createStationData.common.city, }; if (this.createStationData.common.icon === "") { delete commonDataPayload.icon; } // First create station in Russian const { name, address } = this.createStationData[language]; const description = this.createStationData.common.description; const response = await languageInstance(language).post("/station", { name: name || "", system_name: name || "", // system_name is often derived from name description: description || "", address: address || "", ...commonDataPayload, }); runInAction(() => { this.stationLists[language].data.push(response.data); }); const stationId = response.data.id; // Then update for other languages for (const lang of ["ru", "en", "zh"].filter( (lang) => lang !== language ) as Language[]) { const { name, address } = this.createStationData[lang]; const description = this.createStationData.common.description; const response = await languageInstance(lang).patch( `/station/${stationId}`, { name: name || "", system_name: name || "", // system_name is often derived from name description: description || "", address: address || "", ...commonDataPayload, } ); runInAction(() => { this.stationLists[lang].data.push(response.data); }); } runInAction(() => { this.createStationData = { ru: { name: "", system_name: "", address: "", loaded: false, }, en: { name: "", system_name: "", address: "", loaded: false, }, zh: { name: "", system_name: "", address: "", loaded: false, }, common: { city: "", city_id: 0, direction: false, icon: "", latitude: 0, description: "", longitude: 0, offset_x: 0, offset_y: 0, transfers: { bus: "", metro_blue: "", metro_green: "", metro_orange: "", metro_purple: "", metro_red: "", train: "", tram: "", trolleybus: "", }, }, }; }); return response.data; }; // Reset editStationData when navigating away or after saving resetEditStationData = () => { this.editStationData = { ru: { name: "", system_name: "", address: "", loaded: false, }, en: { name: "", system_name: "", address: "", loaded: false, }, zh: { name: "", system_name: "", address: "", loaded: false, }, common: { city: "", city_id: 0, direction: false, description: "", icon: "", latitude: 0, longitude: 0, offset_x: 0, offset_y: 0, transfers: { bus: "", metro_blue: "", metro_green: "", metro_orange: "", metro_purple: "", metro_red: "", train: "", tram: "", trolleybus: "", }, }, }; }; } export const stationsStore = new StationsStore();