Expose mobile More tools
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
import { router } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import { ScrollView, StyleSheet, Text, View } from "react-native";
|
||||
|
||||
import { AppBackground } from "@/components/AppBackground";
|
||||
import { Button } from "@/components/ui/Button";
|
||||
import { Input } from "@/components/ui/Input";
|
||||
import { fonts, spacing } from "@/constants/theme";
|
||||
import { useAppTheme } from "@/contexts/ThemeContext";
|
||||
import { api } from "@/lib/trpc";
|
||||
|
||||
export default function OnboardingScreen() {
|
||||
const { colors } = useAppTheme();
|
||||
const utils = api.useUtils();
|
||||
const statusQuery = api.settings.getOnboardingStatus.useQuery();
|
||||
|
||||
const [businessName, setBusinessName] = useState("");
|
||||
const [clientName, setClientName] = useState("");
|
||||
const [step, setStep] = useState(0);
|
||||
|
||||
const createBusiness = api.businesses.create.useMutation();
|
||||
const createClient = api.clients.create.useMutation();
|
||||
const complete = api.settings.completeOnboarding.useMutation({
|
||||
onSuccess: async () => {
|
||||
await utils.settings.getOnboardingStatus.invalidate();
|
||||
await utils.settings.getProfile.invalidate();
|
||||
router.replace("/(app)");
|
||||
},
|
||||
});
|
||||
|
||||
async function finish() {
|
||||
if (businessName.trim()) {
|
||||
await createBusiness.mutateAsync({
|
||||
name: businessName.trim(),
|
||||
isDefault: true,
|
||||
});
|
||||
}
|
||||
if (clientName.trim()) {
|
||||
await createClient.mutateAsync({
|
||||
name: clientName.trim(),
|
||||
currency: "USD",
|
||||
});
|
||||
}
|
||||
await complete.mutateAsync();
|
||||
}
|
||||
|
||||
const steps = [
|
||||
{
|
||||
title: "Welcome to beenvoice",
|
||||
body: "Set up your workspace in a minute — business profile and first client.",
|
||||
},
|
||||
{
|
||||
title: "Your business",
|
||||
body: "This appears on invoices you send to clients.",
|
||||
},
|
||||
{
|
||||
title: "First client",
|
||||
body: "Add someone you bill. You can skip and add clients later.",
|
||||
},
|
||||
];
|
||||
|
||||
const current = steps[step]!;
|
||||
|
||||
return (
|
||||
<AppBackground>
|
||||
<ScrollView contentContainerStyle={styles.body}>
|
||||
<Text style={[styles.kicker, { color: colors.mutedForeground }]}>
|
||||
Step {step + 1} of {steps.length}
|
||||
</Text>
|
||||
<Text style={[styles.title, { color: colors.foreground }]}>{current.title}</Text>
|
||||
<Text style={[styles.bodyText, { color: colors.mutedForeground }]}>{current.body}</Text>
|
||||
|
||||
{step === 1 ? (
|
||||
<Input
|
||||
label="Business name"
|
||||
value={businessName}
|
||||
onChangeText={setBusinessName}
|
||||
placeholder="Your studio or company"
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{step === 2 ? (
|
||||
<Input
|
||||
label="Client name"
|
||||
value={clientName}
|
||||
onChangeText={setClientName}
|
||||
placeholder="Acme Corp"
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<View style={styles.actions}>
|
||||
{step > 0 ? (
|
||||
<Button title="Back" variant="secondary" onPress={() => setStep((s) => s - 1)} />
|
||||
) : null}
|
||||
{step < steps.length - 1 ? (
|
||||
<Button title="Continue" onPress={() => setStep((s) => s + 1)} />
|
||||
) : (
|
||||
<Button
|
||||
title={complete.isPending ? "Finishing…" : "Go to dashboard"}
|
||||
loading={complete.isPending}
|
||||
onPress={() => void finish()}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{statusQuery.data && !statusQuery.data.completed ? (
|
||||
<Button title="Skip for now" variant="secondary" onPress={() => void complete.mutateAsync()} />
|
||||
) : null}
|
||||
</ScrollView>
|
||||
</AppBackground>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
body: {
|
||||
padding: spacing.lg,
|
||||
gap: spacing.md,
|
||||
minHeight: "100%",
|
||||
justifyContent: "center",
|
||||
},
|
||||
kicker: {
|
||||
fontFamily: fonts.bodyMedium,
|
||||
fontSize: 13,
|
||||
},
|
||||
title: {
|
||||
fontFamily: fonts.heading,
|
||||
fontSize: 32,
|
||||
lineHeight: 36,
|
||||
},
|
||||
bodyText: {
|
||||
fontFamily: fonts.body,
|
||||
fontSize: 16,
|
||||
lineHeight: 24,
|
||||
},
|
||||
actions: {
|
||||
gap: spacing.sm,
|
||||
marginTop: spacing.lg,
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user