almeira-web/dripzone-app/src/lib/data-service.ts

728 lines
22 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Product, City, PaymentMethod, Order, SupplierPost, StoreSettings, Supplier, MonitoredWhatsAppGroup, User } from '@/types';
export const INITIAL_SUPPLIERS: Supplier[] = [
{
"id": "sup-jovic",
"name": "💎 2️⃣ DIFUSIÓN JOVIC STORE COLOMBIA🍀",
"phone": "573167455877",
"contactPerson": "Asesor Jovic Store",
"address": "Centro / Bodega Cali",
"notes": "Proveedor oficial Nike, Jordan, Nocta y Vomero calidades Top.",
"isActive": true
},
{
"id": "sup-ccmio",
"name": "EXCLUSIVE CC MÍO 3B",
"phone": "573159876543",
"contactPerson": "Despachos CC MÍO 3B",
"address": "CC MÍO Local 3B, Cali",
"notes": "Especialista en Adidas, Coach, Timberland y Skatewear.",
"isActive": true
},
{
"id": "sup-central",
"name": "BODEGA CENTRAL MAYORISTA",
"phone": "573101234567",
"contactPerson": "Logística Despachos",
"address": "San Andresito / Cali",
"notes": "Despacho rápido en 24 horas para separación inmediata.",
"isActive": true
}
];
export const INITIAL_CITIES: City[] = [
{
id: 'city-cali',
name: 'Cali',
department: 'Valle del Cauca',
shippingCost: 0,
deliveryTime: 'Entrega en 24 Horas (Domicilio Local)',
allowsContraentrega: true,
firstExchangeFree: true,
exchangePolicyNote: '1er Cambio de Talla 100% GRATIS en Cali (posteriores con flete estándar)',
},
{
id: 'city-jamundi',
name: 'Jamundí',
department: 'Valle del Cauca',
shippingCost: 5000,
deliveryTime: 'Entrega en 24 Horas',
allowsContraentrega: true,
firstExchangeFree: true,
exchangePolicyNote: '1er Cambio de Talla 100% GRATIS en Jamundí (posteriores con flete estándar)',
},
{
id: 'city-palmira',
name: 'Palmira',
department: 'Valle del Cauca',
shippingCost: 7000,
deliveryTime: 'Entrega en 24 Horas',
allowsContraentrega: true,
firstExchangeFree: true,
exchangePolicyNote: '1er Cambio de Talla 100% GRATIS en Palmira (posteriores con flete estándar)',
},
{
id: 'city-yumbo',
name: 'Yumbo',
department: 'Valle del Cauca',
shippingCost: 5000,
deliveryTime: 'Entrega en 24 Horas',
allowsContraentrega: true,
firstExchangeFree: true,
exchangePolicyNote: '1er Cambio de Talla 100% GRATIS en Yumbo (posteriores con flete estándar)',
},
{
id: 'city-bogota',
name: 'Bogotá D.C.',
department: 'Cundinamarca',
shippingCost: 12000,
deliveryTime: '2 a 3 días hábiles',
allowsContraentrega: true,
firstExchangeFree: false,
exchangePolicyNote: 'Cambio de talla garantizado (flete logístico asumido por el cliente)',
},
{
id: 'city-medellin',
name: 'Medellín',
department: 'Antioquia',
shippingCost: 12000,
deliveryTime: '2 a 3 días hábiles',
allowsContraentrega: true,
firstExchangeFree: false,
exchangePolicyNote: 'Cambio de talla garantizado (flete logístico asumido por el cliente)',
},
{
id: 'city-barranquilla',
name: 'Barranquilla',
department: 'Atlántico',
shippingCost: 14000,
deliveryTime: '3 a 4 días hábiles',
allowsContraentrega: true,
firstExchangeFree: false,
exchangePolicyNote: 'Cambio de talla garantizado (flete logístico asumido por el cliente)',
},
{
id: 'city-nacional',
name: 'Otras Ciudades / Resto del País',
department: 'Colombia',
shippingCost: 15000,
deliveryTime: '2 a 5 días hábiles',
allowsContraentrega: false,
firstExchangeFree: false,
exchangePolicyNote: 'Cambio de talla garantizado (flete nacional asumido por el cliente)',
},
];
// Métodos de Pago configurables por el Admin
export const INITIAL_PAYMENT_METHODS: PaymentMethod[] = [
{
id: 'pay-bold-link',
name: 'Bold.co • PSE, Tarjetas Débito/Crédito, Nequi o QR (Oficial)',
type: 'bold',
description: 'Paga de forma rápida y 100% segura con tu cuenta Bold. Acepta PSE, Tarjetas Visa/Mastercard y QR de cualquier banco.',
requiresDeposit: false,
depositAmount: 0,
boldPaymentLink: 'https://bold.co/p/carlos-lasso',
accountInfo: 'Pasarela Oficial Bold.co • PSE / Tarjetas / QR',
isActive: true,
},
{
id: 'pay-deposit-10k',
name: 'Separación con $10.000 + Saldo Contraentrega',
type: 'contraentrega',
description: 'Asegura tu talla con solo $10.000 COP vía Bold/Nequi/Daviplata y cancelas el saldo restante en efectivo o transferencia cuando el mensajero llegue a tu casa.',
requiresDeposit: true,
depositAmount: 10000,
accountInfo: 'Nequi / Daviplata Oficial: 316 745 5877 (Carlos Andrés Lasso)',
boldPaymentLink: 'https://bold.co/p/carlos-lasso',
isActive: true,
},
{
id: 'pay-cod-full',
name: 'Pago 100% Contraentrega (Cali y Alrededores)',
type: 'contraentrega',
description: 'Pagas el 100% del valor total al recibir en tu puerta (válido para entregas urbanas en 24 horas).',
requiresDeposit: false,
depositAmount: 0,
isActive: true,
},
{
id: 'pay-nequi-full',
name: 'Transferencia Total Anticipada Nequi / Daviplata',
type: 'nequi',
description: 'Paga el 100% anticipado y recibe prioridad de despacho express en 24 horas.',
requiresDeposit: false,
depositAmount: 0,
accountInfo: 'Nequi / Daviplata: 316 745 5877 (Carlos Andrés Lasso)',
isActive: true,
},
];
export const INITIAL_PRODUCTS: Product[] = [];
export const INITIAL_SUPPLIER_POSTS: SupplierPost[] = [
{
id: 'post-1',
channelName: 'DIFUSION JOVIC STORE',
supplierName: 'DIFUSION JOVIC STORE',
supplierPhone: '573134848203',
rawMessage: `🔥 DISPONIBLE HOY 🔥\nNike Air Force 1 All White\nTallas: 37 al 43\nMayorista: $90.000 c/u\nDespacho inmediato Cali`,
rawImages: [
'https://images.unsplash.com/photo-1595950653106-6c9ebd614d3a?auto=format&fit=crop&w=800&q=80',
],
extractedProduct: {
name: 'Nike Air Force 1 Low 07 White Triple',
brand: 'Nike',
sizes: ['37', '38', '39', '40', '41', '42', '43'],
supplierPrice: 90000,
suggestedRetailPrice: 125000,
category: 'Sneakers / Urbano',
confidence: 0.96,
supplierName: 'DIFUSION JOVIC STORE',
supplierPhone: '573134848203',
},
status: 'published_store',
receivedAt: 'Hoy, 09:15 AM',
},
{
id: 'post-2',
channelName: 'EXCLUSIVE CC MIO 3B',
supplierName: 'EXCLUSIVE CC MIO 3B',
supplierPhone: '573159876543',
rawMessage: `👟 JORDAN 4 MILITARY BLACK 👟\nFull calidad AAA, caja original\nTallas 38 a 43\nPrecio: $95.000\nDomicilio pago contraentrega`,
rawImages: [
'https://images.unsplash.com/photo-1584735935682-2f2b69dff9d2?auto=format&fit=crop&w=800&q=80',
],
extractedProduct: {
name: 'Air Jordan 4 Retro Military Black',
brand: 'Jordan',
sizes: ['38', '39', '40', '41', '42', '43'],
supplierPrice: 95000,
suggestedRetailPrice: 130000,
category: 'Sneakers / Colección',
confidence: 0.94,
supplierName: 'EXCLUSIVE CC MIO 3B',
supplierPhone: '573159876543',
},
status: 'published_store',
receivedAt: 'Hoy, 10:40 AM',
},
];
export const INITIAL_MONITORED_GROUPS: MonitoredWhatsAppGroup[] = [
{
id: 'grp-jovic',
jid: '120363049363072784@g.us',
name: '💎 2️⃣ DIFUSIÓN JOVIC STORE COLOMBIA🍀',
isMonitored: true,
supplierId: 'sup-jovic',
supplierName: '💎 2️⃣ DIFUSIÓN JOVIC STORE COLOMBIA🍀',
profitMarginOverride: 35,
autoPublish: true,
participantsCount: 450,
notes: 'Proveedor oficial Nike, Jordan, Vomero, Nocta y AF1.',
},
{
id: 'grp-ccmio',
jid: '120363024823901923@g.us',
name: 'EXCLUSIVE CC MÍO 3B',
isMonitored: true,
supplierId: 'sup-ccmio',
supplierName: 'EXCLUSIVE CC MÍO 3B',
profitMarginOverride: 35,
autoPublish: true,
participantsCount: 380,
notes: 'Proveedor oficial Adidas, Coach, Timberland y Skatewear.',
},
];
export const INITIAL_ORDERS: Order[] = [
{
id: 'ORD-8921',
customerName: 'Mateo Valencia',
customerPhone: '3168945120',
address: 'Av 6N # 24N-32 Edificio Granada Real',
cityId: 'city-cali',
cityName: 'Cali (Norte - Granada)',
items: [
{
productId: 'snk-jordan4-1',
productName: 'Nike Air Jordan 4 Retro White Cement',
brand: 'Jordan',
size: '41',
quantity: 1,
price: 135000,
supplierPrice: 95000,
supplierName: '💎 2️⃣ DIFUSIÓN JOVIC STORE COLOMBIA🍀',
supplierPhone: '573134848203',
image: 'https://images.unsplash.com/photo-1584735935682-2f2b69dff9d2?auto=format&fit=crop&w=800&q=80',
},
],
subtotal: 135000,
shippingCost: 0,
totalAmount: 135000,
depositAmount: 10000,
balanceDue: 125000,
paymentMethodId: 'pay-contraentrega',
paymentMethodName: 'Contraentrega Efectivo / Nequi',
status: 'pending',
createdAt: 'Hoy, 06:45 AM',
notes: 'Timbrar en apto 302. Paga con billete de 100 y 50.',
},
{
id: 'ORD-8922',
customerName: 'Valentina Restrepo',
customerPhone: '3157829401',
address: 'Calle 52N # 4BN-15 Casa 4 La Flora',
cityId: 'city-cali',
cityName: 'Cali (Norte - La Flora)',
items: [
{
productId: 'snk-vomero5-1',
productName: 'Nike Zoom Vomero 5 Photon Dust Metallic Silver',
brand: 'Nike',
size: '39',
quantity: 1,
price: 130000,
supplierPrice: 90000,
supplierName: '💎 2️⃣ DIFUSIÓN JOVIC STORE COLOMBIA🍀',
supplierPhone: '573134848203',
image: 'https://images.unsplash.com/photo-1600185365926-3a2ce3cdb9eb?auto=format&fit=crop&w=800&q=80',
},
],
subtotal: 130000,
shippingCost: 0,
totalAmount: 130000,
depositAmount: 10000,
balanceDue: 120000,
paymentMethodId: 'pay-contraentrega',
paymentMethodName: 'Contraentrega Nequi',
status: 'pending',
createdAt: 'Hoy, 07:15 AM',
notes: 'Dejar en portería si no contesta.',
},
{
id: 'ORD-8923',
customerName: 'Santiago Henao',
customerPhone: '3186523910',
address: 'Cra 105 # 14-45 Condominio Portal de la Viga',
cityId: 'city-cali',
cityName: 'Cali (Sur - Ciudad Jardín)',
items: [
{
productId: 'snk-campus-1',
productName: 'Adidas Campus 00s Core Black White',
brand: 'Adidas',
size: '40',
quantity: 1,
price: 125000,
supplierPrice: 85000,
supplierName: 'EXCLUSIVE CC MÍO 3B',
supplierPhone: '573159876543',
image: 'https://images.unsplash.com/photo-1525966222134-fcfa99b8ae77?auto=format&fit=crop&w=800&q=80',
},
],
subtotal: 125000,
shippingCost: 0,
totalAmount: 125000,
depositAmount: 10000,
balanceDue: 115000,
paymentMethodId: 'pay-contraentrega',
paymentMethodName: 'Contraentrega',
status: 'pending',
createdAt: 'Hoy, 07:30 AM',
notes: 'Recibe en horas de la tarde después de las 2 PM.',
},
{
id: 'ORD-8924',
customerName: 'Camila Ospina',
customerPhone: '3114958203',
address: 'Cra 85E # 14-80 Apto 501 El Ingenio',
cityId: 'city-cali',
cityName: 'Cali (Sur - El Ingenio)',
items: [
{
productId: 'snk-coach-1',
productName: 'Coach Low Top Monogram Signature Brown',
brand: 'Coach',
size: '38',
quantity: 1,
price: 145000,
supplierPrice: 100000,
supplierName: 'EXCLUSIVE CC MÍO 3B',
supplierPhone: '573159876543',
image: 'https://images.unsplash.com/photo-1595950653106-6c9ebd614d3a?auto=format&fit=crop&w=800&q=80',
},
],
subtotal: 145000,
shippingCost: 0,
totalAmount: 145000,
depositAmount: 10000,
balanceDue: 135000,
paymentMethodId: 'pay-contraentrega',
paymentMethodName: 'Separación Pagada Bold',
status: 'deposit_received',
createdAt: 'Hoy, 08:00 AM',
notes: 'Cliente ya pagó $10.000 de anticipo.',
},
{
id: 'ORD-8925',
customerName: 'Daniel Caicedo',
customerPhone: '3174829105',
address: 'Cra 10 # 3-45 San Antonio',
cityId: 'city-cali',
cityName: 'Cali (Oeste - San Antonio)',
items: [
{
productId: 'snk-af1-1',
productName: 'Nike Air Force 1 07 Low Triple White',
brand: 'Nike',
size: '42',
quantity: 1,
price: 120000,
supplierPrice: 80000,
supplierName: '💎 2️⃣ DIFUSIÓN JOVIC STORE COLOMBIA🍀',
supplierPhone: '573134848203',
image: 'https://images.unsplash.com/photo-1595950653106-6c9ebd614d3a?auto=format&fit=crop&w=800&q=80',
},
],
subtotal: 120000,
shippingCost: 0,
totalAmount: 120000,
depositAmount: 10000,
balanceDue: 110000,
paymentMethodId: 'pay-contraentrega',
paymentMethodName: 'Contraentrega',
status: 'pending',
createdAt: 'Hoy, 08:20 AM',
},
];
class DataService {
private products: Product[] = [...INITIAL_PRODUCTS];
private cities: City[] = [...INITIAL_CITIES];
private paymentMethods: PaymentMethod[] = [...INITIAL_PAYMENT_METHODS];
private suppliers: Supplier[] = [...INITIAL_SUPPLIERS];
private orders: Order[] = [...INITIAL_ORDERS];
private supplierPosts: SupplierPost[] = [...INITIAL_SUPPLIER_POSTS];
getProducts(): Product[] {
return this.products;
}
getProductById(id: string): Product | undefined {
return this.products.find((p) => p.id === id);
}
addProduct(product: Product): Product {
this.products.unshift(product);
return product;
}
updateProduct(id: string, updates: Partial<Product>): Product | null {
const idx = this.products.findIndex((p) => p.id === id);
if (idx === -1) return null;
this.products[idx] = { ...this.products[idx], ...updates };
return this.products[idx];
}
deleteProduct(id: string): boolean {
const initialLen = this.products.length;
this.products = this.products.filter((p) => p.id !== id);
return this.products.length < initialLen;
}
getSuppliers(includeInactive: boolean = true): Supplier[] {
if (includeInactive) return this.suppliers;
return this.suppliers.filter((s) => s.isActive !== false);
}
getSupplierById(id: string): Supplier | undefined {
return this.suppliers.find((s) => s.id === id);
}
addSupplier(supplier: Partial<Supplier>): Supplier {
const newSupplier: Supplier = {
id: supplier.id || `sup-${Date.now()}`,
name: supplier.name || 'Nuevo Proveedor',
phone: supplier.phone || '573167455877',
contactPerson: supplier.contactPerson || '',
address: supplier.address || '',
notes: supplier.notes || '',
isActive: supplier.isActive !== undefined ? supplier.isActive : true,
};
this.suppliers.push(newSupplier);
return newSupplier;
}
updateSupplier(id: string, updates: Partial<Supplier>): Supplier | null {
const idx = this.suppliers.findIndex((s) => s.id === id);
if (idx === -1) return null;
this.suppliers[idx] = { ...this.suppliers[idx], ...updates };
return this.suppliers[idx];
}
deleteSupplier(id: string): boolean {
// Soft delete (desactivación segura para preservar 100% el historial de pedidos y productos)
const supplier = this.suppliers.find((s) => s.id === id);
if (!supplier) return false;
supplier.isActive = false;
return true;
}
getCities(): City[] {
return this.cities;
}
getCityById(id: string): City | undefined {
return this.cities.find((c) => c.id === id);
}
addCity(city: City): City {
this.cities.push(city);
return city;
}
updateCity(id: string, updates: Partial<City>): City | null {
const idx = this.cities.findIndex((c) => c.id === id);
if (idx === -1) return null;
this.cities[idx] = { ...this.cities[idx], ...updates };
return this.cities[idx];
}
getPaymentMethods(): PaymentMethod[] {
return this.paymentMethods;
}
updatePaymentMethod(id: string, updates: Partial<PaymentMethod>): PaymentMethod | null {
const idx = this.paymentMethods.findIndex((p) => p.id === id);
if (idx === -1) return null;
this.paymentMethods[idx] = { ...this.paymentMethods[idx], ...updates };
return this.paymentMethods[idx];
}
getOrders(): Order[] {
return this.orders;
}
getOrderById(id: string): Order | undefined {
return this.orders.find((o) => o.id === id);
}
addOrder(order: Order): Order {
this.orders.unshift(order);
return order;
}
createOrder(orderData: Partial<Order>): Order {
const newOrder: Order = {
id: orderData.id || `ord-${Date.now()}`,
customerName: orderData.customerName || 'Cliente',
customerPhone: orderData.customerPhone || '',
address: orderData.address || '',
cityId: orderData.cityId || 'city-cali',
cityName: orderData.cityName || 'Cali',
items: orderData.items || [],
subtotal: orderData.subtotal || 0,
shippingCost: orderData.shippingCost || 0,
totalAmount: orderData.totalAmount || 0,
depositAmount: orderData.depositAmount !== undefined ? orderData.depositAmount : 10000,
balanceDue: orderData.balanceDue !== undefined ? orderData.balanceDue : ((orderData.totalAmount || 0) - (orderData.depositAmount !== undefined ? orderData.depositAmount : 10000)),
paymentMethodId: orderData.paymentMethodId || 'pay-contraentrega',
paymentMethodName: orderData.paymentMethodName || 'Contraentrega',
status: orderData.status || 'pending',
notes: orderData.notes,
createdAt: orderData.createdAt || new Date().toISOString(),
};
this.orders.unshift(newOrder);
return newOrder;
}
updateOrder(id: string, updates: Partial<Order>): Order | null {
const idx = this.orders.findIndex((o) => o.id === id);
if (idx === -1) return null;
const current = this.orders[idx];
const total = updates.totalAmount !== undefined ? updates.totalAmount : current.totalAmount;
const deposit = updates.depositAmount !== undefined ? updates.depositAmount : current.depositAmount;
const balanceDue = updates.balanceDue !== undefined ? updates.balanceDue : (total - deposit);
this.orders[idx] = {
...current,
...updates,
totalAmount: total,
depositAmount: deposit,
balanceDue,
};
return this.orders[idx];
}
deleteOrder(id: string): boolean {
const initialLen = this.orders.length;
this.orders = this.orders.filter((o) => o.id !== id);
return this.orders.length < initialLen;
}
updateOrderStatus(orderId: string, status: Order['status']): Order | null {
const order = this.orders.find((o) => o.id === orderId);
if (!order) return null;
order.status = status;
return order;
}
getSupplierPosts(): SupplierPost[] {
return this.supplierPosts;
}
addSupplierPost(post: SupplierPost): SupplierPost {
this.supplierPosts.unshift(post);
return post;
}
saveSupplierPosts(posts: SupplierPost[]): SupplierPost[] {
posts.forEach((newP) => {
const exists = this.supplierPosts.some(
(p) => p.id === newP.id || (p.rawMessage && p.rawMessage === newP.rawMessage && (p as any).channelJid === (newP as any).channelJid)
);
if (!exists) {
this.supplierPosts.unshift(newP);
}
});
return this.supplierPosts;
}
updateSupplierPostStatus(id: string, status: SupplierPost['status']): boolean {
const post = this.supplierPosts.find((p) => p.id === id);
if (!post) return false;
post.status = status;
return true;
}
// Configuración de la Tienda
private settings: StoreSettings = {
storeName: 'DripZone',
slogan: 'Luxury Streetwear & Collectibles',
email: 'carlos.andres.lasso@gmail.com',
phone: '3167455877',
whatsappNumber: '573167455877',
instagramHandle: '@dripzone.co',
address: 'Bodega Central / Cali',
city: 'Cali, Colombia',
nequiAccount: '316 745 5877',
daviplataAccount: '316 745 5877',
accountHolder: 'Carlos Andrés Lasso',
boldPaymentLink: 'https://bold.co/p/carlos-lasso',
boldApiKey: '',
boldMerchantId: '',
boldQrUrl: '',
boldEnabled: true,
defaultProfitMargin: 35,
defaultDepositAmount: 10000,
};
getSettings(): StoreSettings {
return this.settings;
}
updateSettings(updates: Partial<StoreSettings>): StoreSettings {
this.settings = { ...this.settings, ...updates };
return this.settings;
}
// Control de Usuarios
private users: User[] = [
{
id: 'usr-admin-1',
name: 'Carlos Andrés Lasso',
email: 'carlos.andres.lasso@gmail.com',
phone: '3167455877',
city: 'Cali',
address: 'Centro / Bodega Principal',
role: 'admin',
isActive: true,
createdAt: '2026-01-10',
totalOrders: 0,
lastLogin: 'Hoy, 08:15 PM',
},
{
id: 'usr-operator-1',
name: 'Andrés Operador Despachos',
email: 'despachos@dripzone.co',
phone: '3159876543',
city: 'Cali',
role: 'operator',
isActive: true,
createdAt: '2026-02-01',
totalOrders: 0,
lastLogin: 'Hoy, 05:30 PM',
},
{
id: 'usr-cust-1',
name: 'Mateo Gómez (Cliente VIP)',
email: 'mateo.sneakers@gmail.com',
phone: '3112345678',
city: 'Cali',
address: 'Calle 5 # 34-12 Apto 402',
role: 'customer',
isActive: true,
createdAt: '2026-02-15',
totalOrders: 3,
lastLogin: 'Ayer, 08:20 PM',
},
];
getUsers(): User[] {
return this.users;
}
addUser(user: User): User {
this.users.unshift(user);
return user;
}
updateUser(id: string, updates: Partial<User>): User | null {
const idx = this.users.findIndex((u) => u.id === id);
if (idx === -1) return null;
this.users[idx] = { ...this.users[idx], ...updates };
return this.users[idx];
}
deleteUser(id: string): boolean {
const idx = this.users.findIndex((u) => u.id === id);
if (idx === -1) return false;
this.users.splice(idx, 1);
return true;
}
authenticate(emailOrPhone: string): User | null {
const q = emailOrPhone.trim().toLowerCase();
const user = this.users.find(
(u) => u.email.toLowerCase() === q || u.phone === q || u.phone.includes(q)
);
return user || null;
}
private monitoredGroups: MonitoredWhatsAppGroup[] = [...INITIAL_MONITORED_GROUPS];
getMonitoredGroups(): MonitoredWhatsAppGroup[] {
return this.monitoredGroups;
}
saveMonitoredGroups(groups: MonitoredWhatsAppGroup[]): MonitoredWhatsAppGroup[] {
this.monitoredGroups = groups;
return this.monitoredGroups;
}
toggleGroupMonitoring(idOrJid: string, isMonitored: boolean): MonitoredWhatsAppGroup | null {
const grp = this.monitoredGroups.find((g) => g.id === idOrJid || g.jid === idOrJid);
if (grp) {
grp.isMonitored = isMonitored;
return grp;
}
return null;
}
}
export const dataService = new DataService();