feat: Add edit pages with cache

This commit is contained in:
2025-06-08 08:33:43 +03:00
parent e37f9e14bc
commit b09c1b3214
37 changed files with 2223 additions and 772 deletions

View File

@ -1,4 +1,4 @@
import { authInstance } from "@shared";
import { authInstance, languageStore } from "@shared";
import { makeAutoObservable, runInAction } from "mobx";
export type Carrier = {
@ -14,14 +14,19 @@ export type Carrier = {
right_color: string;
};
type Carriers = Carrier[];
type CashedCarrier = Record<number, Carrier>;
class CarrierStore {
carriers: Carrier[] = [];
carrier: Carrier | null = null;
carriers: Carriers = [];
carrier: CashedCarrier = {};
constructor() {
makeAutoObservable(this);
}
getCarriers = async () => {
if (this.carriers.length > 0) return;
const response = await authInstance.get("/carrier");
runInAction(() => {
@ -34,13 +39,30 @@ class CarrierStore {
runInAction(() => {
this.carriers = this.carriers.filter((carrier) => carrier.id !== id);
delete this.carrier[id];
});
};
getCarrier = async (id: number) => {
if (this.carrier[id]) return this.carrier[id];
const response = await authInstance.get(`/carrier/${id}`);
runInAction(() => {
this.carrier = response.data;
if (!this.carrier[id]) {
this.carrier[id] = {
id: 0,
short_name: "",
full_name: "",
slogan: "",
city: "",
city_id: 0,
logo: "",
main_color: "",
left_color: "",
right_color: "",
};
}
this.carrier[id] = response.data;
});
return response.data;
};
@ -50,9 +72,9 @@ class CarrierStore {
shortName: string,
city: string,
cityId: number,
primaryColor: string,
secondaryColor: string,
accentColor: string,
main_color: string,
left_color: string,
right_color: string,
slogan: string,
logoId: string
) => {
@ -61,9 +83,9 @@ class CarrierStore {
short_name: shortName,
city,
city_id: cityId,
primary_color: primaryColor,
secondary_color: secondaryColor,
accent_color: accentColor,
main_color,
left_color,
right_color,
slogan,
logo: logoId,
});
@ -71,6 +93,57 @@ class CarrierStore {
this.carriers.push(response.data);
});
};
editCarrierData = {
full_name: "",
short_name: "",
city: "",
city_id: 0,
main_color: "",
left_color: "",
right_color: "",
slogan: "",
logo: "",
};
setEditCarrierData = (
fullName: string,
shortName: string,
city: string,
cityId: number,
main_color: string,
left_color: string,
right_color: string,
slogan: string,
logoId: string
) => {
this.editCarrierData = {
full_name: fullName,
short_name: shortName,
city,
city_id: cityId,
main_color: main_color,
left_color: left_color,
right_color: right_color,
slogan: slogan,
logo: logoId,
};
};
editCarrier = async (id: number) => {
const response = await authInstance.patch(
`/carrier/${id}`,
this.editCarrierData
);
runInAction(() => {
this.carriers = this.carriers.map((carrier) =>
carrier.id === id ? { ...carrier, ...response.data } : carrier
);
this.carrier[id] = response.data;
});
};
}
export const carrierStore = new CarrierStore();

View File

@ -70,4 +70,4 @@ class CityStore {
};
}
export const cityStore = new CityStore();
// export const cityStore = new CityStore();

View File

@ -0,0 +1,266 @@
import {
authInstance,
languageInstance,
Language,
languageStore,
countryStore,
} from "@shared";
import { makeAutoObservable, runInAction } from "mobx";
export type City = {
id?: number;
name: string;
country: string;
country_code: string;
arms: string;
};
export type CashedCities = {
ru: City[];
en: City[];
zh: City[];
};
export type CashedCity = {
ru: City | null;
en: City | null;
zh: City | null;
};
class CityStore {
cities: CashedCities = {
ru: [],
en: [],
zh: [],
};
city: Record<string, CashedCity> = {};
constructor() {
makeAutoObservable(this);
}
getCities = async (language: keyof CashedCities) => {
if (this.cities[language] && this.cities[language].length > 0) {
return;
}
const response = await authInstance.get(`/city`);
runInAction(() => {
this.cities[language] = response.data;
});
};
getCity = async (code: string, language: keyof CashedCities) => {
if (this.city[code]?.[language] && this.city[code][language] !== null) {
return;
}
const response = await authInstance.get(`/city/${code}`);
runInAction(() => {
if (!this.city[code]) {
this.city[code] = {
ru: null,
en: null,
zh: null,
};
}
this.city[code][language] = response.data;
});
return response.data;
};
deleteCity = async (code: string, language: keyof CashedCities) => {
await authInstance.delete(`/city/${code}`);
runInAction(() => {
this.cities[language] = this.cities[language].filter(
(city) => city.country_code !== code
);
this.city[code][language] = null;
});
};
createCityData = {
country: "",
country_code: "",
arms: "",
ru: {
name: "",
},
en: {
name: "",
},
zh: {
name: "",
},
};
setCreateCityData = (
name: string,
country: string,
country_code: string,
arms: string,
language: keyof CashedCities
) => {
this.createCityData = {
...this.createCityData,
country: country,
country_code: country_code,
arms: arms,
[language]: {
name: name,
},
};
};
createCity = async () => {
const { language } = languageStore;
const { country, country_code, arms } = this.createCityData;
const { name } = this.createCityData[language as keyof CashedCities];
if (name && country && country_code && arms) {
const cityResponse = await languageInstance(language as Language).post(
"/city",
{
name: name,
country: country,
country_code: country_code,
arms: arms,
}
);
runInAction(() => {
this.cities[language as keyof CashedCities] = [
...this.cities[language as keyof CashedCities],
cityResponse.data,
];
});
for (const secondaryLanguage of ["ru", "en", "zh"].filter(
(l) => l !== language
)) {
const { name } =
this.createCityData[secondaryLanguage as keyof CashedCities];
const patchResponse = await languageInstance(
secondaryLanguage as Language
).patch(`/city/${cityResponse.data.id}`, {
name: name,
country: country,
country_code: country_code,
arms: arms,
});
runInAction(() => {
this.cities[secondaryLanguage as keyof CashedCities] = [
...this.cities[secondaryLanguage as keyof CashedCities],
patchResponse.data,
];
});
}
}
runInAction(() => {
this.createCityData = {
country: "",
country_code: "",
arms: "",
ru: {
name: "",
},
en: {
name: "",
},
zh: {
name: "",
},
};
});
};
editCityData = {
country: "",
country_code: "",
arms: "",
ru: {
name: "",
},
en: {
name: "",
},
zh: {
name: "",
},
};
setEditCityData = (
name: string,
country: string,
country_code: string,
arms: string,
language: keyof CashedCities
) => {
this.editCityData = {
...this.editCityData,
country: country,
country_code: country_code,
arms: arms,
[language]: {
name: name,
},
};
};
editCity = async (code: string) => {
for (const language of ["ru", "en", "zh"]) {
const { country_code, arms } = this.editCityData;
const { name } = this.editCityData[language as keyof CashedCities];
const { countries } = countryStore;
const country = countries[language as keyof CashedCities].find(
(country) => country.code === country_code
);
await languageInstance(language as Language).patch(`/city/${code}`, {
name,
country: country?.name || "",
country_code: country_code,
arms,
});
runInAction(() => {
if (this.city[code]) {
this.city[code][language as keyof CashedCities] = {
name,
country: country?.name || "",
country_code: country_code,
arms,
};
}
if (this.cities[language as keyof CashedCities]) {
this.cities[language as keyof CashedCities] = this.cities[
language as keyof CashedCities
].map((city) =>
city.id === Number(code)
? {
id: city.id,
name,
country: country?.name || "",
country_code: country_code,
arms,
}
: city
);
}
});
}
};
}
export const cityStore = new CityStore();

View File

@ -1,4 +1,9 @@
import { authInstance } from "@shared";
import {
authInstance,
languageInstance,
Language,
languageStore,
} from "@shared";
import { makeAutoObservable, runInAction } from "mobx";
export type Country = {
@ -6,43 +11,208 @@ export type Country = {
name: string;
};
export type CashedCountries = {
ru: Country[];
en: Country[];
zh: Country[];
};
export type CashedCountry = {
ru: Country | null;
en: Country | null;
zh: Country | null;
};
class CountryStore {
countries: Country[] = [];
country: Country | null = null;
countries: CashedCountries = {
ru: [],
en: [],
zh: [],
};
country: Record<string, CashedCountry> = {};
constructor() {
makeAutoObservable(this);
}
getCountries = async () => {
const response = await authInstance.get("/country");
getCountries = async (language: keyof CashedCountries) => {
if (this.countries[language] && this.countries[language].length > 0) {
return;
}
const response = await authInstance.get(`/country`);
runInAction(() => {
this.countries = response.data;
this.countries[language] = response.data;
});
};
getCountry = async (code: string) => {
getCountry = async (code: string, language: keyof CashedCountries) => {
if (
this.country[code]?.[language] &&
this.country[code][language] !== null
) {
return;
}
const response = await authInstance.get(`/country/${code}`);
runInAction(() => {
this.country = response.data;
if (!this.country[code]) {
this.country[code] = {
ru: null,
en: null,
zh: null,
};
}
this.country[code][language] = response.data;
});
return response.data;
};
deleteCountry = async (code: string) => {
deleteCountry = async (code: string, language: keyof CashedCountries) => {
await authInstance.delete(`/country/${code}`);
runInAction(() => {
this.countries = this.countries.filter(
this.countries[language] = this.countries[language].filter(
(country) => country.code !== code
);
this.country[code][language] = null;
});
};
createCountry = async (code: string, name: string) => {
await authInstance.post("/country", { code: code, name: name });
await this.getCountries();
createCountryData = {
code: "",
ru: {
name: "",
},
en: {
name: "",
},
zh: {
name: "",
},
};
setCountryData = (
code: string,
name: string,
language: keyof CashedCountries
) => {
this.createCountryData = {
...this.createCountryData,
code: code,
[language]: {
name: name,
},
};
};
createCountry = async () => {
const { code } = this.createCountryData;
const { language } = languageStore;
const { name } = this.createCountryData[language as keyof CashedCountries];
if (code && this.createCountryData[language].name) {
await languageInstance(language as Language).post("/country", {
code: code,
name: name,
});
runInAction(() => {
this.countries[language as keyof CashedCountries] = [
...this.countries[language as keyof CashedCountries],
{ code: code, name: name },
];
});
for (const secondaryLanguage of ["ru", "en", "zh"].filter(
(l) => l !== language
)) {
const { name } =
this.createCountryData[secondaryLanguage as keyof CashedCountries];
if (name) {
await languageInstance(secondaryLanguage as Language).patch(
`/country/${code}`,
{
name: name,
}
);
}
runInAction(() => {
this.countries[secondaryLanguage as keyof CashedCountries] = [
...this.countries[secondaryLanguage as keyof CashedCountries],
{ code: code, name: name },
];
});
}
}
runInAction(() => {
this.createCountryData = {
code: "",
ru: {
name: "",
},
en: {
name: "",
},
zh: {
name: "",
},
};
});
};
editCountryData = {
ru: {
name: "",
},
en: {
name: "",
},
zh: {
name: "",
},
};
setEditCountryData = (name: string, language: keyof CashedCountries) => {
this.editCountryData = {
...this.editCountryData,
[language]: {
name: name,
},
};
};
editCountry = async (code: string) => {
for (const language of ["ru", "en", "zh"]) {
const { name } = this.editCountryData[language as keyof CashedCountries];
if (name) {
await languageInstance(language as Language).patch(`/country/${code}`, {
name: name,
});
runInAction(() => {
if (this.country[code]) {
this.country[code][language as keyof CashedCountries] = {
code,
name,
};
}
if (this.countries[language as keyof CashedCountries]) {
this.countries[language as keyof CashedCountries] = this.countries[
language as keyof CashedCountries
].map((country) =>
country.code === code ? { code, name } : country
);
}
});
}
}
};
}

View File

@ -6,17 +6,20 @@ export type User = {
email: string;
is_admin: boolean;
name: string;
password?: string;
};
class UserStore {
users: User[] = [];
user: User | null = null;
user: Record<string, User> = {};
constructor() {
makeAutoObservable(this);
}
getUsers = async () => {
if (this.users.length > 0) return;
const response = await authInstance.get("/user");
runInAction(() => {
@ -25,18 +28,77 @@ class UserStore {
};
getUser = async (id: number) => {
if (this.user[id]) return;
const response = await authInstance.get(`/user/${id}`);
runInAction(() => {
this.user = response.data as User;
this.user[id] = response.data as User;
});
return response.data;
};
deleteUser = async (id: number) => {
await authInstance.delete(`/users/${id}`);
await authInstance.delete(`/user/${id}`);
runInAction(() => {
this.users = this.users.filter((user) => user.id !== id);
delete this.user[id];
});
};
createUserData: Partial<User> = {
name: "",
email: "",
password: "",
is_admin: false,
};
setCreateUserData = (
name: string,
email: string,
password: string,
is_admin: boolean
) => {
this.createUserData = { name, email, password, is_admin };
};
createUser = async () => {
const id = this.users[this.users.length - 1].id + 1;
const response = await authInstance.post("/user", this.createUserData);
runInAction(() => {
this.users.push({
id,
...response.data,
});
});
};
editUserData: Partial<User> = {
name: "",
email: "",
password: "",
is_admin: false,
};
setEditUserData = (
name: string,
email: string,
password: string,
is_admin: boolean
) => {
this.editUserData = { name, email, password, is_admin };
};
editUser = async (id: number) => {
const response = await authInstance.patch(`/user/${id}`, this.editUserData);
runInAction(() => {
this.users = this.users.map((user) =>
user.id === id ? { ...user, ...response.data } : user
);
this.user[id] = { ...this.user[id], ...response.data };
});
};
}

View File

@ -1,5 +1,5 @@
import { authInstance } from "@shared";
import { makeAutoObservable } from "mobx";
import { authInstance, languageStore, languageInstance } from "@shared";
import { makeAutoObservable, runInAction } from "mobx";
export type Vehicle = {
vehicle: {
@ -22,42 +22,121 @@ export type Vehicle = {
class VehicleStore {
vehicles: Vehicle[] = [];
vehicle: Vehicle | null = null;
vehicle: Record<string, Vehicle> = {};
constructor() {
makeAutoObservable(this);
}
getVehicles = async () => {
const response = await authInstance.get(`/vehicle`);
this.vehicles = response.data;
const response = await languageInstance("ru").get(`/vehicle`);
runInAction(() => {
this.vehicles = response.data;
});
};
deleteVehicle = async (id: number) => {
await authInstance.delete(`/vehicle/${id}`);
this.vehicles = this.vehicles.filter(
(vehicle) => vehicle.vehicle.id !== id
);
await languageInstance("ru").delete(`/vehicle/${id}`);
runInAction(() => {
this.vehicles = this.vehicles.filter(
(vehicle) => vehicle.vehicle.id !== id
);
});
};
getVehicle = async (id: number) => {
const response = await authInstance.get(`/vehicle/${id}`);
this.vehicle = response.data;
const response = await languageInstance("ru").get(`/vehicle/${id}`);
runInAction(() => {
this.vehicle[id] = response.data;
});
};
createVehicle = async (
tailNumber: number,
type: string,
type: number,
carrier: string,
carrierId: number
) => {
await authInstance.post("/vehicle", {
const response = await languageInstance("ru").post("/vehicle", {
tail_number: tailNumber,
type,
carrier,
carrier_id: carrierId,
});
await this.getVehicles();
runInAction(() => {
this.vehicles.push({
vehicle: {
id: response.data.id,
tail_number: response.data.tail_number,
type: response.data.type,
carrier_id: response.data.carrier_id,
carrier: response.data.carrier,
uuid: response.data.uuid,
},
});
});
};
editVehicleData: {
tail_number: number;
type: number;
carrier: string;
carrier_id: number;
} = {
tail_number: 0,
type: 0,
carrier: "",
carrier_id: 0,
};
setEditVehicleData = (data: {
tail_number: number;
type: number;
carrier: string;
carrier_id: number;
}) => {
this.editVehicleData = {
...this.editVehicleData,
...data,
};
};
editVehicle = async (
id: number,
data: {
tail_number: number;
type: number;
carrier: string;
carrier_id: number;
}
) => {
const response = await languageInstance("ru").patch(`/vehicle/${id}`, {
tail_number: data.tail_number,
type: data.type,
carrier: data.carrier,
carrier_id: data.carrier_id,
});
runInAction(() => {
this.vehicle[id] = {
vehicle: {
...this.vehicle[id].vehicle,
...response.data,
},
};
this.vehicles = this.vehicles.map((vehicle) =>
vehicle.vehicle.id === id
? {
...vehicle,
...response.data,
}
: vehicle
);
});
};
}