@digilogiclabs/create-saas-app 1.14.0 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +134 -29
- package/bin/index.js +1 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/cli/prompts/project-setup.d.ts.map +1 -1
- package/dist/cli/prompts/project-setup.js +45 -12
- package/dist/cli/prompts/project-setup.js.map +1 -1
- package/dist/generators/template-generator.d.ts.map +1 -1
- package/dist/generators/template-generator.js +27 -4
- package/dist/generators/template-generator.js.map +1 -1
- package/dist/templates/mobile/ui-auth-payments/template/.env.example +20 -0
- package/dist/templates/mobile/ui-auth-payments/template/README.md +218 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/(tabs)/_layout.tsx +153 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/(tabs)/analytics.tsx +668 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/(tabs)/billing.tsx +743 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/(tabs)/index.tsx +676 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/(tabs)/orders.tsx +402 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/(tabs)/profile.tsx +580 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/_layout.tsx +125 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/auth/login.tsx +246 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/auth/signup.tsx +362 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/onboarding/index.tsx +193 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/tour/index.tsx +272 -0
- package/dist/templates/mobile/ui-auth-payments/template/app.json +93 -0
- package/dist/templates/mobile/ui-auth-payments/template/babel.config.js +23 -0
- package/dist/templates/mobile/ui-auth-payments/template/eas.json +45 -0
- package/dist/templates/mobile/ui-auth-payments/template/expo-env.d.ts +3 -0
- package/dist/templates/mobile/ui-auth-payments/template/jest-setup.ts +74 -0
- package/dist/templates/mobile/ui-auth-payments/template/metro.config.js +11 -0
- package/dist/templates/mobile/ui-auth-payments/template/package.json +106 -0
- package/dist/templates/mobile/ui-auth-payments/template/tsconfig.json +31 -0
- package/dist/templates/web/base/template/src/app/dashboard/page.tsx +62 -20
- package/dist/templates/web/ui-auth/template/package.json +1 -1
- package/dist/templates/web/ui-auth-payments/template/package.json +1 -1
- package/dist/templates/web/ui-auth-payments/template/src/app/dashboard/page.tsx +69 -17
- package/dist/templates/web/ui-auth-payments-ai/template/package.json +1 -1
- package/dist/templates/web/ui-auth-payments-ai/template/src/app/billing/page.tsx +218 -7
- package/dist/templates/web/ui-auth-payments-ai/template/src/app/dashboard/page.tsx +62 -9
- package/dist/templates/web/ui-auth-payments-ai/template/src/app/onboarding/page.tsx +364 -0
- package/dist/templates/web/ui-auth-payments-ai/template/src/app/settings/page.tsx +532 -0
- package/dist/templates/web/ui-auth-payments-ai/template/src/components/client/login-form.tsx +70 -51
- package/dist/templates/web/ui-auth-payments-ai/template/src/components/client/signup-form.tsx +76 -60
- package/dist/templates/web/ui-auth-payments-ai/template/src/components/shared/header.tsx +1 -1
- package/dist/templates/web/ui-auth-payments-audio/template/package.json +1 -1
- package/dist/templates/web/ui-auth-payments-audio/template/src/app/dashboard/page.tsx +71 -17
- package/dist/templates/web/ui-auth-payments-audio/template/src/components/shared/header.tsx +1 -1
- package/dist/templates/web/ui-auth-payments-video/template/package.json +1 -1
- package/package.json +1 -1
- package/src/templates/mobile/ui-auth-payments/template/.env.example +20 -0
- package/src/templates/mobile/ui-auth-payments/template/README.md +218 -0
- package/src/templates/mobile/ui-auth-payments/template/app/(tabs)/_layout.tsx +153 -0
- package/src/templates/mobile/ui-auth-payments/template/app/(tabs)/analytics.tsx +668 -0
- package/src/templates/mobile/ui-auth-payments/template/app/(tabs)/billing.tsx +743 -0
- package/src/templates/mobile/ui-auth-payments/template/app/(tabs)/index.tsx +676 -0
- package/src/templates/mobile/ui-auth-payments/template/app/(tabs)/orders.tsx +402 -0
- package/src/templates/mobile/ui-auth-payments/template/app/(tabs)/profile.tsx +580 -0
- package/src/templates/mobile/ui-auth-payments/template/app/_layout.tsx +125 -0
- package/src/templates/mobile/ui-auth-payments/template/app/auth/login.tsx +246 -0
- package/src/templates/mobile/ui-auth-payments/template/app/auth/signup.tsx +362 -0
- package/src/templates/mobile/ui-auth-payments/template/app/onboarding/index.tsx +193 -0
- package/src/templates/mobile/ui-auth-payments/template/app/tour/index.tsx +272 -0
- package/src/templates/mobile/ui-auth-payments/template/app.json +93 -0
- package/src/templates/mobile/ui-auth-payments/template/babel.config.js +23 -0
- package/src/templates/mobile/ui-auth-payments/template/eas.json +45 -0
- package/src/templates/mobile/ui-auth-payments/template/expo-env.d.ts +3 -0
- package/src/templates/mobile/ui-auth-payments/template/jest-setup.ts +74 -0
- package/src/templates/mobile/ui-auth-payments/template/metro.config.js +11 -0
- package/src/templates/mobile/ui-auth-payments/template/package.json +106 -0
- package/src/templates/mobile/ui-auth-payments/template/tsconfig.json +31 -0
- package/src/templates/web/base/template/src/app/dashboard/page.tsx +62 -20
- package/src/templates/web/ui-auth/template/package.json +1 -1
- package/src/templates/web/ui-auth-payments/template/package.json +1 -1
- package/src/templates/web/ui-auth-payments/template/src/app/dashboard/page.tsx +69 -17
- package/src/templates/web/ui-auth-payments-ai/template/package.json +1 -1
- package/src/templates/web/ui-auth-payments-ai/template/src/app/billing/page.tsx +218 -7
- package/src/templates/web/ui-auth-payments-ai/template/src/app/dashboard/page.tsx +62 -9
- package/src/templates/web/ui-auth-payments-ai/template/src/app/onboarding/page.tsx +364 -0
- package/src/templates/web/ui-auth-payments-ai/template/src/app/settings/page.tsx +532 -0
- package/src/templates/web/ui-auth-payments-ai/template/src/components/client/login-form.tsx +70 -51
- package/src/templates/web/ui-auth-payments-ai/template/src/components/client/signup-form.tsx +76 -60
- package/src/templates/web/ui-auth-payments-ai/template/src/components/shared/header.tsx +1 -1
- package/src/templates/web/ui-auth-payments-audio/template/package.json +1 -1
- package/src/templates/web/ui-auth-payments-audio/template/src/app/dashboard/page.tsx +71 -17
- package/src/templates/web/ui-auth-payments-audio/template/src/components/shared/header.tsx +1 -1
- package/src/templates/web/ui-auth-payments-video/template/package.json +1 -1
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { View, Text, StyleSheet, Image } from 'react-native';
|
|
3
|
+
import { router } from 'expo-router';
|
|
4
|
+
import { LinearGradient } from 'expo-linear-gradient';
|
|
5
|
+
import * as Haptics from 'expo-haptics';
|
|
6
|
+
|
|
7
|
+
// UI Components - v0.22.0
|
|
8
|
+
import {
|
|
9
|
+
NativeOnboarding,
|
|
10
|
+
NativeWelcomeModal,
|
|
11
|
+
PageTransition,
|
|
12
|
+
Button,
|
|
13
|
+
useTheme
|
|
14
|
+
} from '@digilogiclabs/saas-factory-ui/native';
|
|
15
|
+
|
|
16
|
+
// Icons for onboarding steps
|
|
17
|
+
import {
|
|
18
|
+
Zap,
|
|
19
|
+
Shield,
|
|
20
|
+
Users,
|
|
21
|
+
Rocket,
|
|
22
|
+
CheckCircle,
|
|
23
|
+
ArrowRight
|
|
24
|
+
} from 'react-native-heroicons/outline';
|
|
25
|
+
|
|
26
|
+
export default function OnboardingScreen() {
|
|
27
|
+
const [currentStep, setCurrentStep] = useState(0);
|
|
28
|
+
const [showWelcome, setShowWelcome] = useState(true);
|
|
29
|
+
const { theme, isDark } = useTheme();
|
|
30
|
+
|
|
31
|
+
const onboardingSteps = [
|
|
32
|
+
{
|
|
33
|
+
id: 'welcome',
|
|
34
|
+
title: 'Welcome to {{titleCaseName}}',
|
|
35
|
+
description: 'Your all-in-one platform for managing your business with powerful analytics and seamless payments.',
|
|
36
|
+
icon: <Rocket width={64} height={64} color="#3b82f6" />,
|
|
37
|
+
primaryColor: '#3b82f6',
|
|
38
|
+
backgroundGradient: ['#dbeafe', '#bfdbfe']
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: 'analytics',
|
|
42
|
+
title: 'Powerful Analytics',
|
|
43
|
+
description: 'Track your performance with real-time insights, detailed reports, and actionable business intelligence.',
|
|
44
|
+
icon: <Zap width={64} height={64} color="#f59e0b" />,
|
|
45
|
+
primaryColor: '#f59e0b',
|
|
46
|
+
backgroundGradient: ['#fef3c7', '#fed7aa']
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: 'payments',
|
|
50
|
+
title: 'Secure Payments',
|
|
51
|
+
description: 'Accept payments safely with Stripe integration, manage subscriptions, and track billing seamlessly.',
|
|
52
|
+
icon: <Shield width={64} height={64} color="#10b981" />,
|
|
53
|
+
primaryColor: '#10b981',
|
|
54
|
+
backgroundGradient: ['#dcfce7', '#bbf7d0']
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: 'community',
|
|
58
|
+
title: 'Join the Community',
|
|
59
|
+
description: 'Connect with other entrepreneurs, share insights, and grow your business with our vibrant community.',
|
|
60
|
+
icon: <Users width={64} height={64} color="#8b5cf6" />,
|
|
61
|
+
primaryColor: '#8b5cf6',
|
|
62
|
+
backgroundGradient: ['#ede9fe', '#ddd6fe']
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 'ready',
|
|
66
|
+
title: "You're All Set!",
|
|
67
|
+
description: "Everything is ready for you to start building your success. Let's create something amazing together.",
|
|
68
|
+
icon: <CheckCircle width={64} height={64} color="#059669" />,
|
|
69
|
+
primaryColor: '#059669',
|
|
70
|
+
backgroundGradient: ['#dcfce7', '#a7f3d0']
|
|
71
|
+
}
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
const handleWelcomeComplete = () => {
|
|
75
|
+
setShowWelcome(false);
|
|
76
|
+
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const handleOnboardingComplete = () => {
|
|
80
|
+
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
|
|
81
|
+
// Mark onboarding as completed in storage
|
|
82
|
+
router.replace('/(tabs)');
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const handleSkip = () => {
|
|
86
|
+
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
|
87
|
+
router.replace('/(tabs)');
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
if (showWelcome) {
|
|
91
|
+
return (
|
|
92
|
+
<PageTransition type="fade">
|
|
93
|
+
<NativeWelcomeModal
|
|
94
|
+
title="Welcome to {{titleCaseName}}!"
|
|
95
|
+
subtitle="Let's get you started with a quick tour"
|
|
96
|
+
features={[
|
|
97
|
+
{
|
|
98
|
+
icon: <Zap width={24} height={24} color="#3b82f6" />,
|
|
99
|
+
title: "Real-time Analytics",
|
|
100
|
+
description: "Track your business performance instantly"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
icon: <Shield width={24} height={24} color="#10b981" />,
|
|
104
|
+
title: "Secure Payments",
|
|
105
|
+
description: "Accept payments with confidence"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
icon: <Users width={24} height={24} color="#8b5cf6" />,
|
|
109
|
+
title: "Team Collaboration",
|
|
110
|
+
description: "Work together seamlessly"
|
|
111
|
+
}
|
|
112
|
+
]}
|
|
113
|
+
primaryAction={{
|
|
114
|
+
label: "Get Started",
|
|
115
|
+
onPress: handleWelcomeComplete,
|
|
116
|
+
icon: ArrowRight
|
|
117
|
+
}}
|
|
118
|
+
secondaryAction={{
|
|
119
|
+
label: "Skip Tour",
|
|
120
|
+
onPress: handleSkip
|
|
121
|
+
}}
|
|
122
|
+
backgroundImage={{
|
|
123
|
+
uri: "https://images.unsplash.com/photo-1557804506-669a67965ba0?auto=format&fit=crop&w=1000&q=80"
|
|
124
|
+
}}
|
|
125
|
+
showProgress={true}
|
|
126
|
+
enableHaptics={true}
|
|
127
|
+
/>
|
|
128
|
+
</PageTransition>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return (
|
|
133
|
+
<PageTransition type="slide" direction="horizontal">
|
|
134
|
+
<View style={styles.container}>
|
|
135
|
+
{/* Dynamic gradient background based on current step */}
|
|
136
|
+
<LinearGradient
|
|
137
|
+
colors={isDark
|
|
138
|
+
? ['#1e293b', '#334155']
|
|
139
|
+
: onboardingSteps[currentStep]?.backgroundGradient || ['#f8fafc', '#e2e8f0']
|
|
140
|
+
}
|
|
141
|
+
style={styles.gradientBackground}
|
|
142
|
+
/>
|
|
143
|
+
|
|
144
|
+
<NativeOnboarding
|
|
145
|
+
steps={onboardingSteps}
|
|
146
|
+
currentStep={currentStep}
|
|
147
|
+
onStepChange={(stepIndex) => {
|
|
148
|
+
setCurrentStep(stepIndex);
|
|
149
|
+
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
|
150
|
+
}}
|
|
151
|
+
onComplete={handleOnboardingComplete}
|
|
152
|
+
onSkip={handleSkip}
|
|
153
|
+
showSkip={true}
|
|
154
|
+
showProgress={true}
|
|
155
|
+
nextButtonText="Continue"
|
|
156
|
+
skipButtonText="Skip Tour"
|
|
157
|
+
doneButtonText="Get Started"
|
|
158
|
+
dotStyle={{
|
|
159
|
+
backgroundColor: 'rgba(255, 255, 255, 0.3)'
|
|
160
|
+
}}
|
|
161
|
+
activeDotStyle={{
|
|
162
|
+
backgroundColor: onboardingSteps[currentStep]?.primaryColor || '#3b82f6'
|
|
163
|
+
}}
|
|
164
|
+
style={styles.onboarding}
|
|
165
|
+
enableSwipeGestures={true}
|
|
166
|
+
enableHaptics={true}
|
|
167
|
+
autoPlay={false}
|
|
168
|
+
showStepIndicator={true}
|
|
169
|
+
stepIndicatorStyle="dots"
|
|
170
|
+
/>
|
|
171
|
+
</View>
|
|
172
|
+
</PageTransition>
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const styles = StyleSheet.create({
|
|
177
|
+
container: {
|
|
178
|
+
flex: 1,
|
|
179
|
+
backgroundColor: 'transparent',
|
|
180
|
+
},
|
|
181
|
+
gradientBackground: {
|
|
182
|
+
position: 'absolute',
|
|
183
|
+
left: 0,
|
|
184
|
+
right: 0,
|
|
185
|
+
top: 0,
|
|
186
|
+
bottom: 0,
|
|
187
|
+
},
|
|
188
|
+
onboarding: {
|
|
189
|
+
flex: 1,
|
|
190
|
+
paddingHorizontal: 20,
|
|
191
|
+
paddingVertical: 40,
|
|
192
|
+
},
|
|
193
|
+
});
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { View, Text, StyleSheet } from 'react-native';
|
|
3
|
+
import { router } from 'expo-router';
|
|
4
|
+
import { LinearGradient } from 'expo-linear-gradient';
|
|
5
|
+
import * as Haptics from 'expo-haptics';
|
|
6
|
+
|
|
7
|
+
// UI Components - v0.22.0
|
|
8
|
+
import {
|
|
9
|
+
NativeTour,
|
|
10
|
+
PageTransition,
|
|
11
|
+
Button,
|
|
12
|
+
useTheme
|
|
13
|
+
} from '@digilogiclabs/saas-factory-ui/native';
|
|
14
|
+
|
|
15
|
+
// Icons for tour steps
|
|
16
|
+
import {
|
|
17
|
+
Home,
|
|
18
|
+
ShoppingBag,
|
|
19
|
+
BarChart3,
|
|
20
|
+
CreditCard,
|
|
21
|
+
User,
|
|
22
|
+
Zap,
|
|
23
|
+
Target,
|
|
24
|
+
CheckCircle
|
|
25
|
+
} from 'react-native-heroicons/outline';
|
|
26
|
+
|
|
27
|
+
export default function TourScreen() {
|
|
28
|
+
const [currentStep, setCurrentStep] = useState(0);
|
|
29
|
+
const { theme, isDark } = useTheme();
|
|
30
|
+
|
|
31
|
+
// Comprehensive tour steps for the mobile app
|
|
32
|
+
const tourSteps = [
|
|
33
|
+
{
|
|
34
|
+
id: 'welcome',
|
|
35
|
+
target: null, // Full screen welcome
|
|
36
|
+
title: 'Welcome to Your Dashboard',
|
|
37
|
+
content: 'Let me show you around your new mobile business dashboard. This tour will help you discover all the powerful features available.',
|
|
38
|
+
icon: <Home width={48} height={48} color="#3b82f6" />,
|
|
39
|
+
placement: 'center',
|
|
40
|
+
showSkip: true,
|
|
41
|
+
actionButton: {
|
|
42
|
+
text: 'Start Tour',
|
|
43
|
+
variant: 'primary'
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 'dashboard',
|
|
48
|
+
target: 'stats-section',
|
|
49
|
+
title: 'Business Statistics',
|
|
50
|
+
content: 'Monitor your key business metrics at a glance. Track orders, revenue, customers, and conversion rates in real-time.',
|
|
51
|
+
icon: <BarChart3 width={24} height={24} color="#10b981" />,
|
|
52
|
+
placement: 'bottom',
|
|
53
|
+
highlight: {
|
|
54
|
+
type: 'rectangle',
|
|
55
|
+
padding: 16
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'charts',
|
|
60
|
+
target: 'chart-section',
|
|
61
|
+
title: 'Visual Analytics',
|
|
62
|
+
content: 'Dive deeper into your data with interactive charts. Switch between different metrics to analyze trends.',
|
|
63
|
+
icon: <Target width={24} height={24} color="#f59e0b" />,
|
|
64
|
+
placement: 'top',
|
|
65
|
+
highlight: {
|
|
66
|
+
type: 'rectangle',
|
|
67
|
+
padding: 12
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: 'orders',
|
|
72
|
+
target: 'orders-tab',
|
|
73
|
+
title: 'Order Management',
|
|
74
|
+
content: 'View and manage all your orders in one place. Use filters to find specific orders quickly.',
|
|
75
|
+
icon: <ShoppingBag width={24} height={24} color="#8b5cf6" />,
|
|
76
|
+
placement: 'top',
|
|
77
|
+
highlight: {
|
|
78
|
+
type: 'circle',
|
|
79
|
+
padding: 8
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: 'analytics',
|
|
84
|
+
target: 'analytics-tab',
|
|
85
|
+
title: 'Advanced Analytics',
|
|
86
|
+
content: 'Access detailed analytics and reporting. Track performance over different time periods.',
|
|
87
|
+
icon: <BarChart3 width={24} height={24} color="#06b6d4" />,
|
|
88
|
+
placement: 'top',
|
|
89
|
+
highlight: {
|
|
90
|
+
type: 'circle',
|
|
91
|
+
padding: 8
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: 'billing',
|
|
96
|
+
target: 'billing-tab',
|
|
97
|
+
title: 'Payment Management',
|
|
98
|
+
content: 'Manage your subscriptions, payment methods, and billing history securely.',
|
|
99
|
+
icon: <CreditCard width={24} height={24} color="#ef4444" />,
|
|
100
|
+
placement: 'top',
|
|
101
|
+
highlight: {
|
|
102
|
+
type: 'circle',
|
|
103
|
+
padding: 8
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
id: 'profile',
|
|
108
|
+
target: 'profile-tab',
|
|
109
|
+
title: 'Account Settings',
|
|
110
|
+
content: 'Customize your profile, manage preferences, and access security settings.',
|
|
111
|
+
icon: <User width={24} height={24} color="#84cc16" />,
|
|
112
|
+
placement: 'top',
|
|
113
|
+
highlight: {
|
|
114
|
+
type: 'circle',
|
|
115
|
+
padding: 8
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
id: 'navigation',
|
|
120
|
+
target: 'bottom-navigation',
|
|
121
|
+
title: 'Quick Navigation',
|
|
122
|
+
content: 'Use the bottom navigation to quickly switch between different sections of your dashboard.',
|
|
123
|
+
icon: <Zap width={24} height={24} color="#f97316" />,
|
|
124
|
+
placement: 'top',
|
|
125
|
+
highlight: {
|
|
126
|
+
type: 'rectangle',
|
|
127
|
+
padding: 16
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
id: 'complete',
|
|
132
|
+
target: null,
|
|
133
|
+
title: 'Tour Complete!',
|
|
134
|
+
content: "You're all set! You now know how to navigate and use your mobile dashboard. Start managing your business with confidence.",
|
|
135
|
+
icon: <CheckCircle width={48} height={48} color="#10b981" />,
|
|
136
|
+
placement: 'center',
|
|
137
|
+
actionButton: {
|
|
138
|
+
text: 'Get Started',
|
|
139
|
+
variant: 'primary'
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
];
|
|
143
|
+
|
|
144
|
+
const handleTourComplete = () => {
|
|
145
|
+
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
|
|
146
|
+
// Mark tour as completed in storage
|
|
147
|
+
router.replace('/(tabs)');
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const handleSkipTour = () => {
|
|
151
|
+
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
|
152
|
+
router.replace('/(tabs)');
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const handleStepChange = (stepIndex: number) => {
|
|
156
|
+
setCurrentStep(stepIndex);
|
|
157
|
+
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<PageTransition type="fade" duration={300}>
|
|
162
|
+
<View style={styles.container}>
|
|
163
|
+
{/* Dynamic gradient background */}
|
|
164
|
+
<LinearGradient
|
|
165
|
+
colors={isDark
|
|
166
|
+
? ['#1e293b', '#334155', '#475569']
|
|
167
|
+
: ['#f1f5f9', '#e2e8f0', '#cbd5e1']
|
|
168
|
+
}
|
|
169
|
+
style={styles.gradientBackground}
|
|
170
|
+
/>
|
|
171
|
+
|
|
172
|
+
<NativeTour
|
|
173
|
+
steps={tourSteps}
|
|
174
|
+
currentStep={currentStep}
|
|
175
|
+
onStepChange={handleStepChange}
|
|
176
|
+
onComplete={handleTourComplete}
|
|
177
|
+
onSkip={handleSkipTour}
|
|
178
|
+
|
|
179
|
+
// Tour configuration
|
|
180
|
+
isActive={true}
|
|
181
|
+
animated={true}
|
|
182
|
+
animationDuration={300}
|
|
183
|
+
|
|
184
|
+
// UI customization
|
|
185
|
+
maskColor="rgba(0, 0, 0, 0.7)"
|
|
186
|
+
borderRadius={12}
|
|
187
|
+
arrowSize={16}
|
|
188
|
+
|
|
189
|
+
// Navigation
|
|
190
|
+
showPrevious={true}
|
|
191
|
+
showNext={true}
|
|
192
|
+
showSkip={true}
|
|
193
|
+
showClose={false}
|
|
194
|
+
|
|
195
|
+
// Button labels
|
|
196
|
+
previousText="Back"
|
|
197
|
+
nextText="Next"
|
|
198
|
+
skipText="Skip Tour"
|
|
199
|
+
doneText="Finish"
|
|
200
|
+
|
|
201
|
+
// Interaction
|
|
202
|
+
backdropPressToNext={false}
|
|
203
|
+
stopOnOutsideClick={false}
|
|
204
|
+
|
|
205
|
+
// Haptic feedback
|
|
206
|
+
enableHaptics={true}
|
|
207
|
+
|
|
208
|
+
// Custom styling
|
|
209
|
+
tooltipStyle={styles.tooltip}
|
|
210
|
+
titleStyle={styles.tooltipTitle}
|
|
211
|
+
contentStyle={styles.tooltipContent}
|
|
212
|
+
buttonStyle={styles.tourButton}
|
|
213
|
+
|
|
214
|
+
// Auto-progression (optional)
|
|
215
|
+
autoPlay={false}
|
|
216
|
+
autoPlayDelay={5000}
|
|
217
|
+
|
|
218
|
+
// Step indicators
|
|
219
|
+
showStepNumber={true}
|
|
220
|
+
showProgress={true}
|
|
221
|
+
progressBarColor="#3b82f6"
|
|
222
|
+
|
|
223
|
+
// Accessibility
|
|
224
|
+
accessible={true}
|
|
225
|
+
accessibilityLabel="Product tour"
|
|
226
|
+
/>
|
|
227
|
+
</View>
|
|
228
|
+
</PageTransition>
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const styles = StyleSheet.create({
|
|
233
|
+
container: {
|
|
234
|
+
flex: 1,
|
|
235
|
+
backgroundColor: 'transparent',
|
|
236
|
+
},
|
|
237
|
+
gradientBackground: {
|
|
238
|
+
position: 'absolute',
|
|
239
|
+
left: 0,
|
|
240
|
+
right: 0,
|
|
241
|
+
top: 0,
|
|
242
|
+
bottom: 0,
|
|
243
|
+
},
|
|
244
|
+
tooltip: {
|
|
245
|
+
backgroundColor: 'rgba(255, 255, 255, 0.95)',
|
|
246
|
+
borderRadius: 16,
|
|
247
|
+
padding: 20,
|
|
248
|
+
shadowColor: '#000',
|
|
249
|
+
shadowOffset: { width: 0, height: 8 },
|
|
250
|
+
shadowOpacity: 0.15,
|
|
251
|
+
shadowRadius: 20,
|
|
252
|
+
elevation: 10,
|
|
253
|
+
},
|
|
254
|
+
tooltipTitle: {
|
|
255
|
+
fontSize: 18,
|
|
256
|
+
fontWeight: '700',
|
|
257
|
+
color: '#1e293b',
|
|
258
|
+
marginBottom: 8,
|
|
259
|
+
},
|
|
260
|
+
tooltipContent: {
|
|
261
|
+
fontSize: 14,
|
|
262
|
+
color: '#64748b',
|
|
263
|
+
lineHeight: 20,
|
|
264
|
+
marginBottom: 16,
|
|
265
|
+
},
|
|
266
|
+
tourButton: {
|
|
267
|
+
borderRadius: 12,
|
|
268
|
+
paddingHorizontal: 20,
|
|
269
|
+
paddingVertical: 12,
|
|
270
|
+
backgroundColor: '#3b82f6',
|
|
271
|
+
},
|
|
272
|
+
});
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
{
|
|
2
|
+
"expo": {
|
|
3
|
+
"name": "{{titleCaseName}}",
|
|
4
|
+
"slug": "{{kebabCaseName}}",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"orientation": "portrait",
|
|
7
|
+
"icon": "./assets/icon.png",
|
|
8
|
+
"userInterfaceStyle": "automatic",
|
|
9
|
+
"scheme": "{{kebabCaseName}}",
|
|
10
|
+
"splash": {
|
|
11
|
+
"image": "./assets/splash.png",
|
|
12
|
+
"resizeMode": "contain",
|
|
13
|
+
"backgroundColor": "#ffffff"
|
|
14
|
+
},
|
|
15
|
+
"assetBundlePatterns": [
|
|
16
|
+
"**/*"
|
|
17
|
+
],
|
|
18
|
+
"ios": {
|
|
19
|
+
"supportsTablet": true,
|
|
20
|
+
"bundleIdentifier": "com.{{packageName}}.app",
|
|
21
|
+
"config": {
|
|
22
|
+
"usesNonExemptEncryption": false
|
|
23
|
+
},
|
|
24
|
+
"infoPlist": {
|
|
25
|
+
"NSCameraUsageDescription": "This app uses the camera to scan QR codes and take photos",
|
|
26
|
+
"NSLocationWhenInUseUsageDescription": "This app uses location to provide location-based features",
|
|
27
|
+
"NSLocationAlwaysAndWhenInUseUsageDescription": "This app uses location to provide location-based features"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"android": {
|
|
31
|
+
"adaptiveIcon": {
|
|
32
|
+
"foregroundImage": "./assets/adaptive-icon.png",
|
|
33
|
+
"backgroundColor": "#ffffff"
|
|
34
|
+
},
|
|
35
|
+
"package": "com.{{packageName}}.app",
|
|
36
|
+
"permissions": [
|
|
37
|
+
"CAMERA",
|
|
38
|
+
"ACCESS_FINE_LOCATION",
|
|
39
|
+
"ACCESS_COARSE_LOCATION",
|
|
40
|
+
"RECEIVE_BOOT_COMPLETED",
|
|
41
|
+
"VIBRATE"
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
"web": {
|
|
45
|
+
"favicon": "./assets/favicon.png",
|
|
46
|
+
"bundler": "metro"
|
|
47
|
+
},
|
|
48
|
+
"plugins": [
|
|
49
|
+
"expo-router",
|
|
50
|
+
[
|
|
51
|
+
"expo-notifications",
|
|
52
|
+
{
|
|
53
|
+
"icon": "./assets/notification-icon.png",
|
|
54
|
+
"color": "#ffffff",
|
|
55
|
+
"sounds": [
|
|
56
|
+
"./assets/notification-sound.wav"
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
[
|
|
61
|
+
"expo-location",
|
|
62
|
+
{
|
|
63
|
+
"locationAlwaysAndWhenInUsePermission": "Allow {{titleCaseName}} to use your location to provide location-based features."
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
[
|
|
67
|
+
"expo-camera",
|
|
68
|
+
{
|
|
69
|
+
"cameraPermission": "Allow {{titleCaseName}} to access your camera to scan QR codes and take photos."
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
[
|
|
73
|
+
"@stripe/stripe-react-native",
|
|
74
|
+
{
|
|
75
|
+
"merchantIdentifier": "merchant.com.{{packageName}}.app",
|
|
76
|
+
"enableGooglePay": true
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
],
|
|
80
|
+
"experiments": {
|
|
81
|
+
"typedRoutes": true,
|
|
82
|
+
"tsconfigPaths": true
|
|
83
|
+
},
|
|
84
|
+
"extra": {
|
|
85
|
+
"router": {
|
|
86
|
+
"origin": false
|
|
87
|
+
},
|
|
88
|
+
"eas": {
|
|
89
|
+
"projectId": "{{easProjectId}}"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module.exports = function (api) {
|
|
2
|
+
api.cache(true);
|
|
3
|
+
return {
|
|
4
|
+
presets: ['babel-preset-expo'],
|
|
5
|
+
plugins: [
|
|
6
|
+
[
|
|
7
|
+
'module-resolver',
|
|
8
|
+
{
|
|
9
|
+
root: ['./'],
|
|
10
|
+
alias: {
|
|
11
|
+
'@': './',
|
|
12
|
+
'@/components': './components',
|
|
13
|
+
'@/hooks': './hooks',
|
|
14
|
+
'@/utils': './utils',
|
|
15
|
+
'@/types': './types',
|
|
16
|
+
'@/constants': './constants',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
'react-native-reanimated/plugin', // Must be last
|
|
21
|
+
],
|
|
22
|
+
};
|
|
23
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cli": {
|
|
3
|
+
"version": ">= 5.9.0"
|
|
4
|
+
},
|
|
5
|
+
"build": {
|
|
6
|
+
"development": {
|
|
7
|
+
"developmentClient": true,
|
|
8
|
+
"distribution": "internal",
|
|
9
|
+
"ios": {
|
|
10
|
+
"resourceClass": "m-medium"
|
|
11
|
+
},
|
|
12
|
+
"android": {
|
|
13
|
+
"buildType": "apk"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"preview": {
|
|
17
|
+
"distribution": "internal",
|
|
18
|
+
"ios": {
|
|
19
|
+
"simulator": true,
|
|
20
|
+
"resourceClass": "m-medium"
|
|
21
|
+
},
|
|
22
|
+
"android": {
|
|
23
|
+
"buildType": "apk"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"production": {
|
|
27
|
+
"ios": {
|
|
28
|
+
"resourceClass": "m-medium"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"submit": {
|
|
33
|
+
"production": {
|
|
34
|
+
"ios": {
|
|
35
|
+
"appleId": "{{appleId}}",
|
|
36
|
+
"ascAppId": "{{ascAppId}}",
|
|
37
|
+
"appleTeamId": "{{appleTeamId}}"
|
|
38
|
+
},
|
|
39
|
+
"android": {
|
|
40
|
+
"serviceAccountKeyPath": "./android-service-account.json",
|
|
41
|
+
"track": "internal"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import '@testing-library/jest-native/extend-expect';
|
|
2
|
+
|
|
3
|
+
// Mock reanimated
|
|
4
|
+
jest.mock('react-native-reanimated', () => {
|
|
5
|
+
const Reanimated = require('react-native-reanimated/mock');
|
|
6
|
+
|
|
7
|
+
// The mock for `call` immediately calls the callback which is incorrect
|
|
8
|
+
// So we override it with a no-op
|
|
9
|
+
Reanimated.default.call = () => {};
|
|
10
|
+
|
|
11
|
+
return Reanimated;
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// Silence the warning: Animated: `useNativeDriver` is not supported
|
|
15
|
+
jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper');
|
|
16
|
+
|
|
17
|
+
// Mock Expo modules
|
|
18
|
+
jest.mock('expo-haptics', () => ({
|
|
19
|
+
impactAsync: jest.fn(),
|
|
20
|
+
notificationAsync: jest.fn(),
|
|
21
|
+
selectionAsync: jest.fn(),
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
jest.mock('expo-constants', () => ({
|
|
25
|
+
default: {
|
|
26
|
+
expoConfig: {
|
|
27
|
+
name: 'Test App',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
jest.mock('expo-router', () => ({
|
|
33
|
+
router: {
|
|
34
|
+
push: jest.fn(),
|
|
35
|
+
replace: jest.fn(),
|
|
36
|
+
back: jest.fn(),
|
|
37
|
+
},
|
|
38
|
+
useRouter: () => ({
|
|
39
|
+
push: jest.fn(),
|
|
40
|
+
replace: jest.fn(),
|
|
41
|
+
back: jest.fn(),
|
|
42
|
+
}),
|
|
43
|
+
Link: 'View',
|
|
44
|
+
Stack: {
|
|
45
|
+
Screen: 'View',
|
|
46
|
+
},
|
|
47
|
+
Tabs: {
|
|
48
|
+
Screen: 'View',
|
|
49
|
+
},
|
|
50
|
+
}));
|
|
51
|
+
|
|
52
|
+
// Mock Stripe
|
|
53
|
+
jest.mock('@stripe/stripe-react-native', () => ({
|
|
54
|
+
useStripe: () => ({
|
|
55
|
+
initPaymentSheet: jest.fn(),
|
|
56
|
+
presentPaymentSheet: jest.fn(),
|
|
57
|
+
}),
|
|
58
|
+
StripeProvider: ({ children }: any) => children,
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
// Mock Supabase
|
|
62
|
+
jest.mock('@supabase/supabase-js', () => ({
|
|
63
|
+
createClient: jest.fn(() => ({
|
|
64
|
+
auth: {
|
|
65
|
+
signUp: jest.fn(),
|
|
66
|
+
signInWithPassword: jest.fn(),
|
|
67
|
+
signOut: jest.fn(),
|
|
68
|
+
getUser: jest.fn(),
|
|
69
|
+
onAuthStateChange: jest.fn(() => ({
|
|
70
|
+
unsubscribe: jest.fn(),
|
|
71
|
+
})),
|
|
72
|
+
},
|
|
73
|
+
})),
|
|
74
|
+
}));
|