feat: implement automatic shop creation for barbers and add error handling to data mutation methods

This commit is contained in:
2026-05-12 17:15:05 +01:00
parent 8058e5835e
commit af1f79ec7b
2 changed files with 73 additions and 23 deletions

View File

@@ -91,22 +91,39 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => {
const applySupabaseUser = async (authUser: any): Promise<User | undefined> => {
if (!authUser) return undefined;
const { data: prof } = await supabase
const { data: prof, error: profErr } = await supabase
.from('profiles')
.select('shop_id, role, name, fcm_token')
.select('shop_id, role, name, fcm_token, shop_name')
.eq('id', authUser.id)
.single();
const role = (prof?.role as any) || authUser.user_metadata?.role || 'cliente';
const shopId = prof?.shop_id || (role === 'barbearia' ? authUser.id : undefined);
const nextUser: User = {
id: authUser.id,
name: prof?.name || authUser.user_metadata?.name || authUser.email?.split('@')[0] || 'Utilizador',
email: authUser.email || '',
password: '',
role: (prof?.role as any) || authUser.user_metadata?.role || 'cliente',
shopId: prof?.shop_id || undefined,
role,
shopId,
fcmToken: prof?.fcm_token || undefined,
};
// If it's a barber and the shop record doesn't exist, create it (matching web logic)
if (role === 'barbearia' && shopId) {
const { data: existingShop } = await supabase.from('shops').select('id').eq('id', shopId).single();
if (!existingShop) {
const shopName = prof?.shop_name || authUser.user_metadata?.shopName || `Barbearia de ${nextUser.name}`;
await supabase.from('shops').insert([{
id: shopId,
name: shopName,
address: 'Endereço a definir',
rating: 0,
}]);
}
}
setUser(nextUser);
registerForPushNotificationsAsync().then((token) => {
@@ -366,13 +383,17 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => {
const clearCart = () => setCart([]);
const addService = async (shopId: string, service: Omit<Service, 'id'>) => {
await supabase.from('services').insert([{
const { error } = await supabase.from('services').insert([{
shop_id: shopId,
name: service.name,
price: service.price,
duration: service.duration,
barber_ids: service.barberIds || [],
}]);
if (error) {
console.error('Erro addService:', error);
throw error;
}
await refreshShops();
};
@@ -392,7 +413,16 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => {
};
const addProduct = async (shopId: string, product: Omit<Product, 'id'>) => {
await supabase.from('products').insert([{ shop_id: shopId, ...product }]);
const { error } = await supabase.from('products').insert([{
shop_id: shopId,
name: product.name,
price: product.price,
stock: product.stock
}]);
if (error) {
console.error('Erro addProduct:', error);
throw error;
}
await refreshShops();
};
@@ -408,13 +438,17 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => {
};
const addBarber = async (shopId: string, barber: Omit<Barber, 'id'>) => {
await supabase.from('barbers').insert([{
const { error } = await supabase.from('barbers').insert([{
shop_id: shopId,
name: barber.name,
specialties: barber.specialties,
schedule: barber.schedule,
schedule: barber.schedule || [],
image_url: barber.imageUrl,
}]);
if (error) {
console.error('Erro addBarber:', error);
throw error;
}
await refreshShops();
};
@@ -436,6 +470,7 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => {
const updateShopDetails = async (shopId: string, payload: Partial<BarberShop>) => {
const { services, products, barbers, id, imageUrl, paymentMethods, socialNetworks, contacts, schedule, ...rest } = payload;
const updateData: Record<string, any> = { ...rest };
if (imageUrl !== undefined) updateData.image_url = imageUrl;
if (paymentMethods !== undefined) updateData.payment_methods = paymentMethods;
if (socialNetworks !== undefined) updateData.social_networks = socialNetworks;
@@ -443,13 +478,16 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => {
if (schedule !== undefined) updateData.schedule = schedule;
const { error } = await supabase.from('shops').update(updateData).eq('id', shopId);
if (error) throw error;
if (error) {
console.error('Erro updateShopDetails:', error);
throw error;
}
if (payload.name) {
await supabase.from('profiles').update({ shop_name: payload.name }).eq('shop_id', shopId);
}
setShops((prev) => prev.map((shop) => (shop.id === shopId ? { ...shop, ...payload } : shop)));
await refreshShops();
};
const submitReview = async (shopId: string, appointmentId: string, rating: number, comment: string) => {

View File

@@ -262,9 +262,13 @@ export default function Dashboard() {
<TextInput style={[styles.input, {flex: 1}]} placeholder="Duração (min)" placeholderTextColor="#475569" keyboardType="numeric" value={formSvc.duration} onChangeText={t => setFormSvc({...formSvc, duration: t})} />
</View>
<Button size="sm" onPress={async () => {
await addService(shop.id, { name: formSvc.name, price: Number(formSvc.price), duration: Number(formSvc.duration), barberIds: [] });
setFormSvc({ name: '', price: '', duration: '' });
Alert.alert('Sucesso', 'Serviço adicionado.');
try {
await addService(shop.id, { name: formSvc.name, price: Number(formSvc.price), duration: Number(formSvc.duration), barberIds: [] });
setFormSvc({ name: '', price: '', duration: '' });
Alert.alert('Sucesso', 'Serviço adicionado.');
} catch (e: any) {
Alert.alert('Erro', e.message || 'Erro ao adicionar serviço.');
}
}}>Adicionar Serviço</Button>
</Card>
</View>
@@ -293,9 +297,13 @@ export default function Dashboard() {
<TextInput style={[styles.input, {flex: 1}]} placeholder="Stock" placeholderTextColor="#475569" keyboardType="numeric" value={formProd.stock} onChangeText={t => setFormProd({...formProd, stock: t})} />
</View>
<Button size="sm" onPress={async () => {
await addProduct(shop.id, { name: formProd.name, price: Number(formProd.price), stock: Number(formProd.stock) });
setFormProd({ name: '', price: '', stock: '' });
Alert.alert('Sucesso', 'Produto adicionado.');
try {
await addProduct(shop.id, { name: formProd.name, price: Number(formProd.price), stock: Number(formProd.stock) });
setFormProd({ name: '', price: '', stock: '' });
Alert.alert('Sucesso', 'Produto adicionado.');
} catch (e: any) {
Alert.alert('Erro', e.message || 'Erro ao adicionar produto.');
}
}}>Adicionar Produto</Button>
</Card>
</View>
@@ -324,13 +332,17 @@ export default function Dashboard() {
<TextInput style={styles.input} placeholder="Nome do profissional" placeholderTextColor="#475569" value={formBarb.name} onChangeText={t => setFormBarb({...formBarb, name: t})} />
<TextInput style={styles.input} placeholder="Especialidades (separadas por vírgula)" placeholderTextColor="#475569" value={formBarb.specialties} onChangeText={t => setFormBarb({...formBarb, specialties: t})} />
<Button size="sm" onPress={async () => {
await addBarber(shop.id, {
name: formBarb.name,
specialties: formBarb.specialties.split(',').map(s => s.trim()).filter(Boolean),
schedule: []
});
setFormBarb({ name: '', specialties: '' });
Alert.alert('Sucesso', 'Membro adicionado.');
try {
await addBarber(shop.id, {
name: formBarb.name,
specialties: formBarb.specialties.split(',').map(s => s.trim()).filter(Boolean),
schedule: []
});
setFormBarb({ name: '', specialties: '' });
Alert.alert('Sucesso', 'Membro adicionado.');
} catch (e: any) {
Alert.alert('Erro', e.message || 'Erro ao adicionar membro.');
}
}}>Adicionar Membro</Button>
</Card>
</View>