BarberFlow/barber-flow/app/admin/config.tsx

623 lines
31 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import {
View,
Text,
StyleSheet,
TextInput,
ScrollView,
TouchableOpacity,
Alert,
Linking,
Platform,
Image
} from 'react-native';
import { router } from 'expo-router';
import Animated, { FadeIn, FadeOut, FadeInUp } from 'react-native-reanimated';
import * as ImagePicker from 'expo-image-picker';
import { useBarbearia } from '../../stores/BarbeariaContext';
import { useLanguage } from '../../stores/LanguageContext';
import { Card } from '../../components/ui/Card';
import { Button } from '../../components/ui/Button';
import { COLORS, SPACING, TYPOGRAPHY, BORDER_RADIUS, SHADOWS } from '../../constants/theme';
import {
Trash2,
Pencil,
ChevronRight,
ChevronLeft,
CheckCircle2,
Globe,
Scissors,
Layout,
MapPin,
Users,
Camera,
CreditCard,
Wallet,
Smartphone,
Check
} from 'lucide-react-native';
const DEFAULT_COLORS = {
primary: '#EAB308',
secondary: '#1A1A1A',
accent: '#8B4513',
background: '#0F0F0F',
card: '#1E1E1E',
text: '#FFFFFF',
textMuted: '#A0A0A0',
};
export default function ConfigPage() {
const { barbearia, updateBarbearia, addService, updateService, removeService, addBarber, updateBarber, removeBarber, isLoading } = useBarbearia();
const { t, language, formatPrice } = useLanguage();
// Use colors do context ou theme default
const themeColors = barbearia?.colors || COLORS;
const [currentStep, setCurrentStep] = useState(1);
// Form estados
const [nome, setNome] = useState('');
const [slug, setSlug] = useState('');
const [logo, setLogo] = useState('');
const [endereco, setEndereco] = useState('');
const [cidade, setCidade] = useState('');
const [numero, setNumero] = useState('');
const [paymentMethods, setPaymentMethods] = useState<string[]>(['money', 'pix', 'card', 'alias']);
const [primaryColor, setPrimaryColor] = useState(themeColors.primary);
// Novo/Editar serviço estado
const [editingServiceId, setEditingServiceId] = useState<string | null>(null);
const [newServiceNamePt, setNewServiceNamePt] = useState('');
const [newServiceNameEs, setNewServiceNameEs] = useState('');
const [newServicePricePt, setNewServicePricePt] = useState('');
const [newServicePriceEs, setNewServicePriceEs] = useState('');
const [newServiceDuration, setNewServiceDuration] = useState('');
// Novo/Editar barbeiro estado
const [editingBarberId, setEditingBarberId] = useState<string | null>(null);
const [newBarberName, setNewBarberName] = useState('');
const [newBarberPhoto, setNewBarberPhoto] = useState('');
const [newBarberCommission, setNewBarberCommission] = useState('50');
const [newBarberEmail, setNewBarberEmail] = useState('');
const [newBarberPassword, setNewBarberPassword] = useState('');
const [canViewFinance, setCanViewFinance] = useState(false);
const [canEditConfig, setCanEditConfig] = useState(false);
useEffect(() => {
if (barbearia) {
setNome(barbearia.nome || '');
setSlug(barbearia.slug || '');
setLogo(barbearia.logo || '');
setEndereco(barbearia.endereco || '');
setCidade(barbearia.cidade || '');
setNumero(barbearia.numero || '');
if (barbearia.paymentMethods && barbearia.paymentMethods.length > 0) {
setPaymentMethods(barbearia.paymentMethods);
}
if (barbearia.colors && barbearia.colors.primary) {
setPrimaryColor(barbearia.colors.primary);
}
}
}, [barbearia]);
const togglePaymentMethod = (method: string) => {
setPaymentMethods(prev =>
prev.includes(method)
? prev.filter(m => m !== method)
: [...prev, method]
);
};
const pickImage = async (setter: (uri: string) => void) => {
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== 'granted') {
Alert.alert('Permissão necessária', 'Precisamos de acesso à sua galeria para escolher a foto.');
return;
}
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [1, 1],
quality: 0.5,
base64: true,
});
if (!result.canceled && result.assets[0].base64) {
setter(`data:image/jpeg;base64,${result.assets[0].base64}`);
}
};
const handleSave = async () => {
try {
const colors = { ...DEFAULT_COLORS, primary: primaryColor };
await updateBarbearia({ nome, slug, logo, endereco, cidade, numero, paymentMethods, colors });
} catch (err) {
console.error(err);
}
};
const nextStep = async () => {
await handleSave();
setCurrentStep(prev => Math.min(prev + 1, 7));
};
const prevStep = () => {
setCurrentStep(prev => Math.max(prev - 1, 1));
};
const handleSaveService = async () => {
if (!newServiceNamePt || !newServiceNameEs || !newServicePricePt || !newServicePriceEs || !newServiceDuration) {
if(Platform.OS === 'web') window.alert(t('admin.config.fill_all') || 'Preencha todos os campos');
return;
}
try {
const serviceData = {
nomePt: newServiceNamePt,
nomeEs: newServiceNameEs,
precoPt: Number(newServicePricePt),
precoEs: Number(newServicePriceEs),
duracao: Number(newServiceDuration),
};
if (editingServiceId) {
await updateService(editingServiceId, serviceData);
} else {
await addService(serviceData);
}
setEditingServiceId(null);
setNewServiceNamePt('');
setNewServiceNameEs('');
setNewServicePricePt('');
setNewServicePriceEs('');
setNewServiceDuration('');
} catch (err) {
console.error(err);
}
};
const handleEditService = (service: any) => {
setEditingServiceId(service.id);
setNewServiceNamePt(service.nomePt);
setNewServiceNameEs(service.nomeEs);
setNewServicePricePt(String(service.precoPt));
setNewServicePriceEs(String(service.precoEs));
setNewServiceDuration(String(service.duracao));
};
const cancelEditService = () => {
setEditingServiceId(null);
setNewServiceNamePt('');
setNewServiceNameEs('');
setNewServicePricePt('');
setNewServicePriceEs('');
setNewServiceDuration('');
};
const handleSaveBarber = async () => {
if (!newBarberName || !newBarberCommission || !newBarberEmail || !newBarberPassword) {
if(Platform.OS === 'web') window.alert('Preencha nome, e-mail, senha e comissão');
return;
}
try {
const barberData = {
nome: newBarberName,
foto: newBarberPhoto || 'https://images.unsplash.com/photo-1503443207922-dff7d543fd0e?w=400',
commission: Number(newBarberCommission) || 0,
email: newBarberEmail,
password: newBarberPassword,
permissions: {
canViewFinance,
canEditConfig,
canEditAgenda: true
}
};
if (editingBarberId) {
await updateBarber(editingBarberId, barberData);
} else {
await addBarber(barberData);
}
setEditingBarberId(null);
setNewBarberName('');
setNewBarberPhoto('');
setNewBarberCommission('50');
setNewBarberEmail('');
setNewBarberPassword('');
setCanViewFinance(false);
setCanEditConfig(false);
} catch (err) {
console.error(err);
}
};
const handleEditBarber = (barber: any) => {
setEditingBarberId(barber.id);
setNewBarberName(barber.nome);
setNewBarberPhoto(barber.foto);
setNewBarberCommission(String(barber.commission || 50));
setNewBarberEmail(barber.email || '');
setNewBarberPassword(barber.password || '');
setCanViewFinance(barber.permissions?.canViewFinance || false);
setCanEditConfig(barber.permissions?.canEditConfig || false);
};
const cancelEditBarber = () => {
setEditingBarberId(null);
setNewBarberName('');
setNewBarberPhoto('');
setNewBarberCommission('50');
setNewBarberEmail('');
setNewBarberPassword('');
setCanViewFinance(false);
setCanEditConfig(false);
};
const handleViewApp = () => {
const url = `${window.location.origin}/${slug}`;
if (Platform.OS === 'web') {
window.open(url, '_blank');
} else {
Linking.openURL(url);
}
};
if (isLoading) return <View style={[styles.center, { backgroundColor: themeColors.background }]}><Text style={{color: themeColors.text}}>Carregando...</Text></View>;
const renderStepIndicator = () => (
<View style={styles.indicatorContainer}>
{[1, 2, 3, 4, 5, 6, 7].map((step) => (
<View
key={step}
style={[
styles.indicator,
{ backgroundColor: step <= currentStep ? primaryColor : themeColors.divider }
]}
/>
))}
</View>
);
return (
<View style={[styles.container, { backgroundColor: themeColors.background }]}>
<Animated.View entering={FadeInUp} style={[styles.header, { backgroundColor: themeColors.surface }]}>
<Text style={[styles.headerTitle, { color: themeColors.text }]}>{t('profile.settings')}</Text>
{renderStepIndicator()}
</Animated.View>
<ScrollView contentContainerStyle={styles.content} showsVerticalScrollIndicator={false}>
<Text style={[styles.stepTitle, { color: primaryColor }]}>
{currentStep === 1 ? t('admin.config.identity') :
currentStep === 2 ? t('admin.config.location') :
currentStep === 3 ? t('admin.config.services') :
currentStep === 4 ? t('admin.config.barbers') :
currentStep === 5 ? (t('admin.config.payments') || 'Formas de Recebimento') :
currentStep === 6 ? (t('admin.config.colors') || 'Cores do App') :
t('admin.config.ready')}
</Text>
{currentStep === 1 && (
<Animated.View entering={FadeIn} exiting={FadeOut}>
<Card style={[styles.stepCard, { backgroundColor: themeColors.surface }]}>
<View style={styles.inputGroup}>
<Text style={[styles.label, { color: themeColors.textMuted }]}>Nome da Barbearia</Text>
<TextInput style={[styles.input, { backgroundColor: themeColors.surfaceLight, color: themeColors.text, borderColor: themeColors.divider }]} value={nome} onChangeText={setNome} placeholder="Ex: Barber Shop VIP" placeholderTextColor={themeColors.textMuted} />
</View>
<View style={styles.inputGroup}>
<Text style={[styles.label, { color: themeColors.textMuted }]}>Slug da URL</Text>
<TextInput style={[styles.input, { backgroundColor: themeColors.surfaceLight, color: themeColors.text, borderColor: themeColors.divider }]} value={slug} onChangeText={setSlug} placeholder="Ex: minha-barbearia" placeholderTextColor={themeColors.textMuted} />
</View>
<Text style={[styles.label, { color: themeColors.textMuted }]}>Logo da Barbearia</Text>
<TouchableOpacity style={[styles.imagePicker, { backgroundColor: themeColors.surfaceLight, borderColor: themeColors.divider }]} onPress={() => pickImage(setLogo)}>
{logo ? (
<Image source={{ uri: logo }} style={styles.pickedLogo} />
) : (
<View style={styles.imagePlaceholder}>
<Camera color={themeColors.textMuted} size={32} />
<Text style={[styles.imagePlaceholderText, { color: themeColors.textMuted }]}>Selecionar Logo</Text>
</View>
)}
</TouchableOpacity>
</Card>
</Animated.View>
)}
{currentStep === 2 && (
<Animated.View entering={FadeIn} exiting={FadeOut}>
<Card style={[styles.stepCard, { backgroundColor: themeColors.surface }]}>
<View style={styles.inputGroup}>
<Text style={[styles.label, { color: themeColors.textMuted }]}>Cidade</Text>
<TextInput style={[styles.input, { backgroundColor: themeColors.surfaceLight, color: themeColors.text, borderColor: themeColors.divider }]} value={cidade} onChangeText={setCidade} placeholder="Ex: São Paulo" placeholderTextColor={themeColors.textMuted} />
</View>
<View style={styles.inputGroup}>
<Text style={[styles.label, { color: themeColors.textMuted }]}>Endereço</Text>
<TextInput style={[styles.input, { backgroundColor: themeColors.surfaceLight, color: themeColors.text, borderColor: themeColors.divider }]} value={endereco} onChangeText={setEndereco} placeholder="Rua..." placeholderTextColor={themeColors.textMuted} />
</View>
<View style={styles.inputGroup}>
<Text style={[styles.label, { color: themeColors.textMuted }]}>Número</Text>
<TextInput style={[styles.input, { backgroundColor: themeColors.surfaceLight, color: themeColors.text, borderColor: themeColors.divider }]} value={numero} onChangeText={setNumero} placeholder="123" placeholderTextColor={themeColors.textMuted} />
</View>
</Card>
</Animated.View>
)}
{currentStep === 3 && (
<Animated.View entering={FadeIn} exiting={FadeOut}>
<Card style={[styles.stepCard, { backgroundColor: themeColors.surface }]}>
{barbearia?.services.map((service) => (
<View key={service.id} style={[styles.listItem, { borderBottomColor: themeColors.divider }]}>
<View style={{flex:1}}>
<Text style={[styles.itemName, { color: themeColors.text }]}>{language === 'pt' ? service.nomePt : service.nomeEs}</Text>
<Text style={[styles.itemMeta, { color: themeColors.textMuted }]}>
{`${formatPrice(service.precoPt, service.precoEs)}${service.duracao} min`}
</Text>
</View>
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity onPress={() => handleEditService(service)} style={styles.actionIconBtn}>
<Pencil color="#3B82F6" size={20} />
</TouchableOpacity>
<TouchableOpacity onPress={() => removeService(service.id)} style={styles.actionIconBtn}>
<Trash2 color="#FF4444" size={20} />
</TouchableOpacity>
</View>
</View>
))}
<View style={[styles.addBox, { backgroundColor: `${primaryColor}10`, borderColor: primaryColor }]}>
{editingServiceId && <Text style={[styles.label, {color: primaryColor, marginBottom: 10}]}>Editando Serviço...</Text>}
<TextInput style={[styles.inputSmall, { backgroundColor: themeColors.surface, color: themeColors.text, borderColor: themeColors.divider }]} value={newServiceNamePt} onChangeText={setNewServiceNamePt} placeholder="Nome em Português" placeholderTextColor={themeColors.textMuted} />
<TextInput style={[styles.inputSmall, { backgroundColor: themeColors.surface, color: themeColors.text, borderColor: themeColors.divider }]} value={newServiceNameEs} onChangeText={setNewServiceNameEs} placeholder="Nombre en Español" placeholderTextColor={themeColors.textMuted} />
<View style={styles.row}>
<TextInput style={[styles.inputSmall, { flex: 1, marginRight: 8, backgroundColor: themeColors.surface, color: themeColors.text, borderColor: themeColors.divider }]} value={newServicePricePt} onChangeText={setNewServicePricePt} placeholder="Preço (R$)" keyboardType="numeric" placeholderTextColor={themeColors.textMuted} />
<TextInput style={[styles.inputSmall, { flex: 1, backgroundColor: themeColors.surface, color: themeColors.text, borderColor: themeColors.divider }]} value={newServicePriceEs} onChangeText={setNewServicePriceEs} placeholder="Preço (GS)" keyboardType="numeric" placeholderTextColor={themeColors.textMuted} />
</View>
<TextInput style={[styles.inputSmall, { backgroundColor: themeColors.surface, color: themeColors.text, borderColor: themeColors.divider }]} value={newServiceDuration} onChangeText={setNewServiceDuration} placeholder="Minutos de Duração" keyboardType="numeric" placeholderTextColor={themeColors.textMuted} />
<View style={{ flexDirection: 'row', gap: 10, marginTop: 8 }}>
{editingServiceId && (
<Button title="Cancelar" onPress={cancelEditService} variant="outline" style={{ flex: 1, borderColor: themeColors.textMuted }} textStyle={{ color: themeColors.textMuted }} />
)}
<Button title={editingServiceId ? "Salvar" : "Adicionar"} onPress={handleSaveService} variant="outline" style={{ flex: editingServiceId ? 1 : undefined, width: editingServiceId ? undefined : '100%', borderColor: primaryColor }} textStyle={{ color: primaryColor }} />
</View>
</View>
</Card>
</Animated.View>
)}
{currentStep === 4 && (
<Animated.View entering={FadeIn} exiting={FadeOut}>
<Card style={[styles.stepCard, { backgroundColor: themeColors.surface }]}>
<View style={styles.list}>
{barbearia?.barbers?.map((barber) => (
<View key={barber.id} style={[styles.listItem, { borderBottomColor: themeColors.divider }]}>
<Image source={{ uri: barber.foto }} style={styles.avatar} />
<View style={{flex:1, marginLeft: 12}}>
<Text style={[styles.itemName, { color: themeColors.text }]}>{barber.nome}</Text>
<Text style={[styles.itemMeta, { color: themeColors.textMuted }]}>{`${barber.commission}% de Comissão`}</Text>
</View>
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity onPress={() => handleEditBarber(barber)} style={styles.actionIconBtn}>
<Pencil color="#3B82F6" size={20} />
</TouchableOpacity>
<TouchableOpacity onPress={() => removeBarber(barber.id)} style={styles.actionIconBtn}>
<Trash2 color="#FF4444" size={20} />
</TouchableOpacity>
</View>
</View>
))}
</View>
<View style={[styles.addBox, { backgroundColor: `${primaryColor}10`, borderColor: primaryColor }]}>
{editingBarberId && <Text style={[styles.label, {color: primaryColor, marginBottom: 10}]}>Editando Barbeiro...</Text>}
<TextInput style={[styles.inputSmall, { backgroundColor: themeColors.surface, color: themeColors.text, borderColor: themeColors.divider }]} value={newBarberName} onChangeText={setNewBarberName} placeholder="Nome do Barbeiro" placeholderTextColor={themeColors.textMuted} />
<TextInput style={[styles.inputSmall, { backgroundColor: themeColors.surface, color: themeColors.text, borderColor: themeColors.divider }]} value={newBarberCommission} onChangeText={setNewBarberCommission} placeholder="% de Comissão (Ex: 50)" keyboardType="numeric" placeholderTextColor={themeColors.textMuted} />
<TextInput style={[styles.inputSmall, { backgroundColor: themeColors.surface, color: themeColors.text, borderColor: themeColors.divider }]} value={newBarberEmail} onChangeText={setNewBarberEmail} placeholder="E-mail de Login" keyboardType="email-address" autoCapitalize="none" placeholderTextColor={themeColors.textMuted} />
<TextInput style={[styles.inputSmall, { backgroundColor: themeColors.surface, color: themeColors.text, borderColor: themeColors.divider }]} value={newBarberPassword} onChangeText={setNewBarberPassword} placeholder="Senha de Acesso" secureTextEntry placeholderTextColor={themeColors.textMuted} />
<Text style={[styles.label, {marginTop: 10, color: themeColors.textMuted}]}>Permissões Extras (Além da Agenda):</Text>
<View style={{ flexDirection: 'row', gap: 10, marginBottom: 15, flexWrap: 'wrap' }}>
<TouchableOpacity
style={[styles.permissionBtn, canViewFinance && { backgroundColor: primaryColor, borderColor: primaryColor }]}
onPress={() => setCanViewFinance(!canViewFinance)}
>
<Text style={[styles.permissionText, canViewFinance && { color: themeColors.background }]}>Ver Financeiro</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.permissionBtn, canEditConfig && { backgroundColor: primaryColor, borderColor: primaryColor }]}
onPress={() => setCanEditConfig(!canEditConfig)}
>
<Text style={[styles.permissionText, canEditConfig && { color: themeColors.background }]}>Alterar Configurações</Text>
</TouchableOpacity>
</View>
<Text style={[styles.label, {marginTop: 10, color: themeColors.textMuted}]}>Foto do Barbeiro</Text>
<TouchableOpacity style={[styles.imagePickerSmall, { backgroundColor: themeColors.surface, borderColor: themeColors.divider }]} onPress={() => pickImage(setNewBarberPhoto)}>
{newBarberPhoto ? (
<Image source={{ uri: newBarberPhoto }} style={styles.pickedAvatar} />
) : (
<View style={styles.imagePlaceholderSmall}>
<Users color={themeColors.textMuted} size={24} />
<Text style={[styles.imagePlaceholderTextSmall, { color: themeColors.textMuted }]}>Escolher Foto</Text>
</View>
)}
</TouchableOpacity>
<View style={{ flexDirection: 'row', gap: 10, marginTop: 15 }}>
{editingBarberId && (
<Button title="Cancelar" onPress={cancelEditBarber} variant="outline" style={{ flex: 1, borderColor: themeColors.textMuted }} textStyle={{ color: themeColors.textMuted }} />
)}
<Button title={editingBarberId ? "Salvar" : "Adicionar Barbeiro"} onPress={handleSaveBarber} variant="outline" style={{ flex: editingBarberId ? 1 : undefined, width: editingBarberId ? undefined : '100%', borderColor: primaryColor }} textStyle={{ color: primaryColor }} />
</View>
</View>
</Card>
</Animated.View>
)}
{currentStep === 5 && (
<Animated.View entering={FadeIn} exiting={FadeOut}>
<Card style={[styles.stepCard, { backgroundColor: themeColors.surface }]}>
<Text style={[styles.cardInfo, { color: themeColors.textMuted }]}>{t('admin.config.payments_desc') || 'Selecione quais formas de pagamento sua barbearia aceita.'}</Text>
<View style={styles.paymentGrid}>
{[
{ id: 'pix', label: 'PIX (Brasil)', icon: <Smartphone size={24} color={primaryColor} /> },
{ id: 'card', label: 'Cartão / Tarjeta', icon: <CreditCard size={24} color={primaryColor} /> },
{ id: 'money', label: 'Dinheiro / Efectivo', icon: <Wallet size={24} color={primaryColor} /> },
{ id: 'alias', label: 'Alias (Paraguay)', icon: <Smartphone size={24} color={primaryColor} /> },
].map((method) => {
const isSelected = paymentMethods.includes(method.id);
return (
<TouchableOpacity
key={method.id}
style={[
styles.paymentMethodCard,
{ backgroundColor: themeColors.surfaceLight, borderColor: themeColors.divider },
isSelected && { borderColor: primaryColor, backgroundColor: `${primaryColor}10` }
]}
onPress={() => togglePaymentMethod(method.id)}
>
<View style={styles.paymentMethodHeader}>
{method.icon}
{isSelected && <Check size={16} color={primaryColor} />}
</View>
<Text style={[styles.paymentMethodLabel, { color: themeColors.text }, isSelected && { color: primaryColor }]}>{method.label}</Text>
</TouchableOpacity>
);
})}
</View>
</Card>
</Animated.View>
)}
{currentStep === 6 && (
<Animated.View entering={FadeIn} exiting={FadeOut}>
<Card style={[styles.stepCard, { backgroundColor: themeColors.surface }]}>
<Text style={[styles.cardInfo, { color: themeColors.textMuted }]}>{t('admin.config.colors_desc') || 'Selecione a cor principal da sua barbearia para personalizar o aplicativo.'}</Text>
<View style={styles.paymentGrid}>
{[
{ id: '#EAB308', label: 'Gold Premium' },
{ id: '#3B82F6', label: 'Azul Moderno' },
{ id: '#EF4444', label: 'Vermelho Forte' },
{ id: '#22C55E', label: 'Verde Natural' },
{ id: '#A855F7', label: 'Roxo Royal' },
{ id: '#F97316', label: 'Laranja Vivo' },
].map((colorOpt) => {
const isSelected = primaryColor === colorOpt.id;
return (
<TouchableOpacity
key={colorOpt.id}
style={[
styles.paymentMethodCard,
{ backgroundColor: themeColors.surfaceLight, borderColor: themeColors.divider },
isSelected && { borderColor: colorOpt.id, backgroundColor: `${colorOpt.id}10` }
]}
onPress={() => setPrimaryColor(colorOpt.id)}
>
<View style={styles.paymentMethodHeader}>
<View style={[styles.colorPreview, { backgroundColor: colorOpt.id }]} />
{isSelected && <Check size={16} color={colorOpt.id} />}
</View>
<Text style={[styles.paymentMethodLabel, { color: themeColors.text }, isSelected && { color: colorOpt.id }]}>{colorOpt.label}</Text>
</TouchableOpacity>
);
})}
</View>
</Card>
</Animated.View>
)}
{currentStep === 7 && (
<Animated.View entering={FadeIn} exiting={FadeOut} style={styles.finishContainer}>
<CheckCircle2 color={primaryColor} size={100} />
<Text style={[styles.finishTitle, { color: themeColors.text }]}>{t('admin.config.ready')}</Text>
<TouchableOpacity style={[styles.linkCard, { backgroundColor: themeColors.surface, borderColor: primaryColor }]} onPress={handleViewApp}>
<Globe color={primaryColor} size={24} />
<Text style={[styles.linkText, { color: primaryColor }]}>{`${window.location.origin}/${slug}`}</Text>
</TouchableOpacity>
<Button title="Dashboard" onPress={() => router.replace('/admin/dashboard')} style={{width: '100%', marginTop: 40, backgroundColor: primaryColor}} textStyle={{color: themeColors.background}} />
</Animated.View>
)}
</ScrollView>
<View style={[styles.footerNav, { backgroundColor: themeColors.background, borderTopColor: themeColors.divider }]}>
{currentStep > 1 && currentStep < 7 && (
<Button title={t('admin.config.back')} variant="ghost" onPress={prevStep} style={{flex: 1}} textStyle={{color: themeColors.textMuted}} />
)}
{currentStep < 7 && (
<Button title={t('admin.config.next')} onPress={nextStep} style={{flex: 2, backgroundColor: primaryColor}} textStyle={{color: themeColors.background}} />
)}
</View>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1 },
center: { flex: 1, justifyContent: 'center', alignItems: 'center' },
header: {
padding: SPACING.xl,
paddingTop: 60,
borderBottomLeftRadius: BORDER_RADIUS.xl,
borderBottomRightRadius: BORDER_RADIUS.xl,
...(SHADOWS.medium as any),
},
headerTitle: { ...TYPOGRAPHY.h3, marginBottom: SPACING.md },
indicatorContainer: { flexDirection: 'row', gap: 6 },
indicator: { flex: 1, height: 4, borderRadius: 2 },
content: { padding: SPACING.xl, paddingBottom: 120 },
stepTitle: { ...TYPOGRAPHY.h2, marginBottom: SPACING.xl },
stepCard: { padding: SPACING.lg },
cardInfo: { ...TYPOGRAPHY.bodySmall, marginBottom: SPACING.lg },
inputGroup: { marginBottom: SPACING.lg },
label: { ...TYPOGRAPHY.caption, marginBottom: 8 },
input: {
borderRadius: BORDER_RADIUS.md,
padding: SPACING.md,
borderWidth: 1,
...TYPOGRAPHY.body
},
inputSmall: {
borderRadius: BORDER_RADIUS.sm,
padding: 12,
borderWidth: 1,
marginBottom: 10,
...TYPOGRAPHY.bodySmall
},
row: { flexDirection: 'row' },
imagePicker: { width: '100%', height: 150, borderRadius: BORDER_RADIUS.lg, borderWidth: 1, borderStyle: 'dashed', justifyContent: 'center', alignItems: 'center', marginBottom: SPACING.lg, overflow: 'hidden' },
pickedLogo: { width: '100%', height: '100%', resizeMode: 'contain' },
imagePlaceholder: { alignItems: 'center', gap: 8 },
imagePlaceholderText: { ...TYPOGRAPHY.caption },
imagePickerSmall: { width: 100, height: 100, borderRadius: 50, borderWidth: 1, borderStyle: 'dashed', justifyContent: 'center', alignItems: 'center', overflow: 'hidden' },
pickedAvatar: { width: '100%', height: '100%' },
imagePlaceholderSmall: { alignItems: 'center', gap: 4 },
imagePlaceholderTextSmall: { fontSize: 10, textAlign: 'center' },
permissionBtn: { paddingHorizontal: 12, paddingVertical: 8, borderRadius: BORDER_RADIUS.sm, borderWidth: 1, borderColor: COLORS.textMuted },
permissionText: { ...TYPOGRAPHY.caption, color: COLORS.textMuted },
addBox: { marginTop: 20, padding: 15, borderRadius: BORDER_RADIUS.lg, borderStyle: 'dashed', borderWidth: 1 },
listItem: { flexDirection: 'row', alignItems: 'center', paddingVertical: 15, borderBottomWidth: 1 },
itemName: { ...TYPOGRAPHY.body, fontWeight: '700' },
itemMeta: { ...TYPOGRAPHY.caption, marginTop: 4 },
actionIconBtn: { padding: 8, marginLeft: 4 },
avatar: { width: 50, height: 50, borderRadius: 25 },
list: { marginBottom: 10 },
paymentGrid: { flexDirection: 'row', flexWrap: 'wrap', gap: SPACING.md, justifyContent: 'space-between' },
paymentMethodCard: { width: '47%', padding: SPACING.lg, borderRadius: BORDER_RADIUS.lg, borderWidth: 1 },
paymentMethodHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: SPACING.md },
paymentMethodLabel: { ...TYPOGRAPHY.bodySmall, fontWeight: '700', marginTop: SPACING.xs },
colorPreview: { width: 24, height: 24, borderRadius: 12 },
finishContainer: { alignItems: 'center', marginTop: 40 },
finishTitle: { ...TYPOGRAPHY.h1, marginTop: 20 },
linkCard: { flexDirection: 'row', alignItems: 'center', gap: 12, padding: 20, borderRadius: BORDER_RADIUS.xl, marginTop: 40, borderWidth: 1, ...(SHADOWS.medium as any) },
linkText: { fontWeight: 'bold', ...TYPOGRAPHY.body },
footerNav: { position: 'absolute', bottom: 0, left: 0, right: 0, padding: SPACING.xl, flexDirection: 'row', gap: SPACING.md, borderTopWidth: 1 }
});