fixing login, ganti icon, add delete account
|
Before Width: | Height: | Size: 582 KiB After Width: | Height: | Size: 934 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 582 KiB After Width: | Height: | Size: 934 KiB |
|
Before Width: | Height: | Size: 582 KiB After Width: | Height: | Size: 934 KiB |
|
Before Width: | Height: | Size: 582 KiB After Width: | Height: | Size: 934 KiB |
@@ -26,6 +26,7 @@
|
|||||||
"expo-media-library": "~55.0.16",
|
"expo-media-library": "~55.0.16",
|
||||||
"expo-print": "~55.0.14",
|
"expo-print": "~55.0.14",
|
||||||
"expo-sharing": "~55.0.18",
|
"expo-sharing": "~55.0.18",
|
||||||
|
"expo-splash-screen": "~55.0.20",
|
||||||
"expo-status-bar": "~55.0.6",
|
"expo-status-bar": "~55.0.6",
|
||||||
"expo-web-browser": "~55.0.15",
|
"expo-web-browser": "~55.0.15",
|
||||||
"react": "19.2.0",
|
"react": "19.2.0",
|
||||||
@@ -1466,6 +1467,24 @@
|
|||||||
"node-forge": "^1.3.3"
|
"node-forge": "^1.3.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@expo/config": {
|
||||||
|
"version": "55.0.16",
|
||||||
|
"resolved": "https://registry.npmjs.org/@expo/config/-/config-55.0.16.tgz",
|
||||||
|
"integrity": "sha512-H5dpQv5TfyZDNheZAWO3SmP10diGWZwN5QOUsArkDJih0QKNtahQBOmrV2xbhgln/nrUGoy41U/ZIY/MEx63Ug==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@expo/config-plugins": "~55.0.8",
|
||||||
|
"@expo/config-types": "^55.0.5",
|
||||||
|
"@expo/json-file": "^10.0.14",
|
||||||
|
"@expo/require-utils": "^55.0.5",
|
||||||
|
"deepmerge": "^4.3.1",
|
||||||
|
"getenv": "^2.0.0",
|
||||||
|
"glob": "^13.0.0",
|
||||||
|
"resolve-workspace-root": "^2.0.0",
|
||||||
|
"semver": "^7.6.0",
|
||||||
|
"slugify": "^1.3.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@expo/config-plugins": {
|
"node_modules/@expo/config-plugins": {
|
||||||
"version": "55.0.8",
|
"version": "55.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-55.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-55.0.8.tgz",
|
||||||
@@ -1604,24 +1623,6 @@
|
|||||||
"chalk": "^4.1.2"
|
"chalk": "^4.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@expo/local-build-cache-provider/node_modules/@expo/config": {
|
|
||||||
"version": "55.0.16",
|
|
||||||
"resolved": "https://registry.npmjs.org/@expo/config/-/config-55.0.16.tgz",
|
|
||||||
"integrity": "sha512-H5dpQv5TfyZDNheZAWO3SmP10diGWZwN5QOUsArkDJih0QKNtahQBOmrV2xbhgln/nrUGoy41U/ZIY/MEx63Ug==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@expo/config-plugins": "~55.0.8",
|
|
||||||
"@expo/config-types": "^55.0.5",
|
|
||||||
"@expo/json-file": "^10.0.14",
|
|
||||||
"@expo/require-utils": "^55.0.5",
|
|
||||||
"deepmerge": "^4.3.1",
|
|
||||||
"getenv": "^2.0.0",
|
|
||||||
"glob": "^13.0.0",
|
|
||||||
"resolve-workspace-root": "^2.0.0",
|
|
||||||
"semver": "^7.6.0",
|
|
||||||
"slugify": "^1.3.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@expo/metro": {
|
"node_modules/@expo/metro": {
|
||||||
"version": "55.1.1",
|
"version": "55.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@expo/metro/-/metro-55.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@expo/metro/-/metro-55.1.1.tgz",
|
||||||
@@ -1681,6 +1682,27 @@
|
|||||||
"xmlbuilder": "^15.1.1"
|
"xmlbuilder": "^15.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@expo/prebuild-config": {
|
||||||
|
"version": "55.0.17",
|
||||||
|
"resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-55.0.17.tgz",
|
||||||
|
"integrity": "sha512-Mcs+dg4Ripu0yCtzf66KZr18PehI1O8HxzJw+G5SUF8VWX+ic99aci1PltvmydWepLwTQL6ykmpXicAUA31IqA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@expo/config": "~55.0.16",
|
||||||
|
"@expo/config-plugins": "~55.0.8",
|
||||||
|
"@expo/config-types": "^55.0.5",
|
||||||
|
"@expo/image-utils": "^0.8.14",
|
||||||
|
"@expo/json-file": "^10.0.14",
|
||||||
|
"@react-native/normalize-colors": "0.83.6",
|
||||||
|
"debug": "^4.3.1",
|
||||||
|
"resolve-from": "^5.0.0",
|
||||||
|
"semver": "^7.6.0",
|
||||||
|
"xml2js": "0.6.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"expo": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@expo/require-utils": {
|
"node_modules/@expo/require-utils": {
|
||||||
"version": "55.0.5",
|
"version": "55.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@expo/require-utils/-/require-utils-55.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@expo/require-utils/-/require-utils-55.0.5.tgz",
|
||||||
@@ -4155,6 +4177,18 @@
|
|||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/expo-splash-screen": {
|
||||||
|
"version": "55.0.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/expo-splash-screen/-/expo-splash-screen-55.0.20.tgz",
|
||||||
|
"integrity": "sha512-WI5T0dutiZhxsqlF+jhEP4JRpQNILLlP8IpmKehsnV53Cncv6AQrKE7y1sOWwDyC2m2GBufZ/Vwam1RMt2EfmA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@expo/prebuild-config": "^55.0.17"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"expo": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/expo-status-bar": {
|
"node_modules/expo-status-bar": {
|
||||||
"version": "55.0.6",
|
"version": "55.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-55.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-55.0.6.tgz",
|
||||||
@@ -4268,27 +4302,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/expo/node_modules/@expo/cli/node_modules/@expo/prebuild-config": {
|
|
||||||
"version": "55.0.17",
|
|
||||||
"resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-55.0.17.tgz",
|
|
||||||
"integrity": "sha512-Mcs+dg4Ripu0yCtzf66KZr18PehI1O8HxzJw+G5SUF8VWX+ic99aci1PltvmydWepLwTQL6ykmpXicAUA31IqA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@expo/config": "~55.0.16",
|
|
||||||
"@expo/config-plugins": "~55.0.8",
|
|
||||||
"@expo/config-types": "^55.0.5",
|
|
||||||
"@expo/image-utils": "^0.8.14",
|
|
||||||
"@expo/json-file": "^10.0.14",
|
|
||||||
"@react-native/normalize-colors": "0.83.6",
|
|
||||||
"debug": "^4.3.1",
|
|
||||||
"resolve-from": "^5.0.0",
|
|
||||||
"semver": "^7.6.0",
|
|
||||||
"xml2js": "0.6.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"expo": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/expo/node_modules/@expo/cli/node_modules/@expo/router-server": {
|
"node_modules/expo/node_modules/@expo/cli/node_modules/@expo/router-server": {
|
||||||
"version": "55.0.16",
|
"version": "55.0.16",
|
||||||
"resolved": "https://registry.npmjs.org/@expo/router-server/-/router-server-55.0.16.tgz",
|
"resolved": "https://registry.npmjs.org/@expo/router-server/-/router-server-55.0.16.tgz",
|
||||||
@@ -4344,24 +4357,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/expo/node_modules/@expo/config": {
|
|
||||||
"version": "55.0.16",
|
|
||||||
"resolved": "https://registry.npmjs.org/@expo/config/-/config-55.0.16.tgz",
|
|
||||||
"integrity": "sha512-H5dpQv5TfyZDNheZAWO3SmP10diGWZwN5QOUsArkDJih0QKNtahQBOmrV2xbhgln/nrUGoy41U/ZIY/MEx63Ug==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@expo/config-plugins": "~55.0.8",
|
|
||||||
"@expo/config-types": "^55.0.5",
|
|
||||||
"@expo/json-file": "^10.0.14",
|
|
||||||
"@expo/require-utils": "^55.0.5",
|
|
||||||
"deepmerge": "^4.3.1",
|
|
||||||
"getenv": "^2.0.0",
|
|
||||||
"glob": "^13.0.0",
|
|
||||||
"resolve-workspace-root": "^2.0.0",
|
|
||||||
"semver": "^7.6.0",
|
|
||||||
"slugify": "^1.3.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/expo/node_modules/@expo/log-box": {
|
"node_modules/expo/node_modules/@expo/log-box": {
|
||||||
"version": "55.0.12",
|
"version": "55.0.12",
|
||||||
"resolved": "https://registry.npmjs.org/@expo/log-box/-/log-box-55.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/@expo/log-box/-/log-box-55.0.12.tgz",
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
"expo-media-library": "~55.0.16",
|
"expo-media-library": "~55.0.16",
|
||||||
"expo-print": "~55.0.14",
|
"expo-print": "~55.0.14",
|
||||||
"expo-sharing": "~55.0.18",
|
"expo-sharing": "~55.0.18",
|
||||||
|
"expo-splash-screen": "~55.0.20",
|
||||||
"expo-status-bar": "~55.0.6",
|
"expo-status-bar": "~55.0.6",
|
||||||
"expo-web-browser": "~55.0.15",
|
"expo-web-browser": "~55.0.15",
|
||||||
"react": "19.2.0",
|
"react": "19.2.0",
|
||||||
|
|||||||
@@ -64,8 +64,8 @@ export default function PlanetCore({ size = 90, glowIntensity = 0.5 }) {
|
|||||||
{/* Planet image */}
|
{/* Planet image */}
|
||||||
<Image
|
<Image
|
||||||
source={require('../../assets/icon.png')}
|
source={require('../../assets/icon.png')}
|
||||||
style={{ width: size, height: size * 0.88 }}
|
style={{ width: size, height: size }}
|
||||||
resizeMode="cover"
|
resizeMode="contain"
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -107,8 +107,8 @@ function PageContent({ item, isActive }) {
|
|||||||
)}
|
)}
|
||||||
<Image
|
<Image
|
||||||
source={require('../../assets/icon.png')}
|
source={require('../../assets/icon.png')}
|
||||||
style={{ width: item.iconSize, height: item.iconSize * 0.88 }}
|
style={{ width: item.iconSize * 1.2, height: item.iconSize * 1.2 }}
|
||||||
resizeMode="cover"
|
resizeMode="contain"
|
||||||
/>
|
/>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
|
|
||||||
|
|||||||
@@ -54,11 +54,13 @@ export default function ProfileScreen({ navigation }) {
|
|||||||
const resetIdentity = useIdentityStore((s) => s.reset);
|
const resetIdentity = useIdentityStore((s) => s.reset);
|
||||||
const resetHabits = useHabitStore((s) => s.reset);
|
const resetHabits = useHabitStore((s) => s.reset);
|
||||||
const resetJourney = useIdentityStore((s) => s.resetJourney);
|
const resetJourney = useIdentityStore((s) => s.resetJourney);
|
||||||
|
const deleteAccount = useAuthStore((s) => s.deleteAccount);
|
||||||
const fadeAnim = useRef(new Animated.Value(0)).current;
|
const fadeAnim = useRef(new Animated.Value(0)).current;
|
||||||
const [showGuide, setShowGuide] = useState(false);
|
const [showGuide, setShowGuide] = useState(false);
|
||||||
const [showReset, setShowReset] = useState(false);
|
const [showReset, setShowReset] = useState(false);
|
||||||
const [resetReason, setResetReason] = useState('');
|
const [resetReason, setResetReason] = useState('');
|
||||||
const [resetting, setResetting] = useState(false);
|
const [resetting, setResetting] = useState(false);
|
||||||
|
const [deleting, setDeleting] = useState(false);
|
||||||
const [focusCount, setFocusCount] = useState(0);
|
const [focusCount, setFocusCount] = useState(0);
|
||||||
const [profile, setProfile] = useState(null);
|
const [profile, setProfile] = useState(null);
|
||||||
const [journeyCount, setJourneyCount] = useState(0);
|
const [journeyCount, setJourneyCount] = useState(0);
|
||||||
@@ -119,6 +121,45 @@ export default function ProfileScreen({ navigation }) {
|
|||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDeleteAccount = () => {
|
||||||
|
showAlert(
|
||||||
|
'Delete your account?',
|
||||||
|
'This will permanently delete your account, all your data, habits, journals, and progress. This cannot be undone.',
|
||||||
|
[
|
||||||
|
{ text: 'Cancel', style: 'cancel' },
|
||||||
|
{
|
||||||
|
text: 'Delete Forever', style: 'destructive',
|
||||||
|
onPress: () => {
|
||||||
|
// Double confirm
|
||||||
|
showAlert(
|
||||||
|
'Last chance',
|
||||||
|
'Are you absolutely sure? Everything will be gone permanently.',
|
||||||
|
[
|
||||||
|
{ text: 'Keep my account', style: 'cancel' },
|
||||||
|
{
|
||||||
|
text: 'Yes, delete everything', style: 'destructive',
|
||||||
|
onPress: async () => {
|
||||||
|
setDeleting(true);
|
||||||
|
try {
|
||||||
|
resetIdentity();
|
||||||
|
resetHabits();
|
||||||
|
await deleteAccount();
|
||||||
|
navigation.dispatch(CommonActions.reset({ index: 0, routes: [{ name: 'Login' }] }));
|
||||||
|
} catch (e) {
|
||||||
|
showAlert('Error', e?.message || 'Failed to delete account.');
|
||||||
|
} finally {
|
||||||
|
setDeleting(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const phase = getDayPhase(currentDay);
|
const phase = getDayPhase(currentDay);
|
||||||
const progressPct = Math.round((currentDay / 40) * 100);
|
const progressPct = Math.round((currentDay / 40) * 100);
|
||||||
const displayName = profile?.nickname || profile?.fullName || user?.email?.split('@')[0] || 'Nova';
|
const displayName = profile?.nickname || profile?.fullName || user?.email?.split('@')[0] || 'Nova';
|
||||||
@@ -328,6 +369,18 @@ export default function ProfileScreen({ navigation }) {
|
|||||||
<Button title="Sign Out" onPress={handleSignOut} variant="secondary" style={st.signOutBtn} />
|
<Button title="Sign Out" onPress={handleSignOut} variant="secondary" style={st.signOutBtn} />
|
||||||
</FadeIn>
|
</FadeIn>
|
||||||
|
|
||||||
|
{/* ═══ Delete Account ═══ */}
|
||||||
|
<FadeIn delay={450} trigger={focusCount}>
|
||||||
|
<Pressable
|
||||||
|
style={({ pressed }) => [st.deleteBtn, pressed && st.deleteBtnPressed]}
|
||||||
|
onPress={handleDeleteAccount}
|
||||||
|
disabled={deleting}
|
||||||
|
>
|
||||||
|
<Text style={st.deleteIcon}>🗑</Text>
|
||||||
|
<Text style={st.deleteText}>{deleting ? 'Deleting...' : 'Delete Account'}</Text>
|
||||||
|
</Pressable>
|
||||||
|
</FadeIn>
|
||||||
|
|
||||||
{/* ═══ Footer ═══ */}
|
{/* ═══ Footer ═══ */}
|
||||||
<FadeIn delay={500} trigger={focusCount}>
|
<FadeIn delay={500} trigger={focusCount}>
|
||||||
<Text style={st.version}>Nova40 v1.0.0</Text>
|
<Text style={st.version}>Nova40 v1.0.0</Text>
|
||||||
@@ -457,6 +510,13 @@ const st = StyleSheet.create({
|
|||||||
legalArrow: { color: colors.textMuted, fontSize: fonts.sizes.lg },
|
legalArrow: { color: colors.textMuted, fontSize: fonts.sizes.lg },
|
||||||
|
|
||||||
signOutBtn: { borderColor: colors.error },
|
signOutBtn: { borderColor: colors.error },
|
||||||
|
deleteBtn: {
|
||||||
|
flexDirection: 'row', alignItems: 'center', justifyContent: 'center',
|
||||||
|
paddingVertical: spacing.md, marginTop: spacing.md,
|
||||||
|
},
|
||||||
|
deleteBtnPressed: { opacity: 0.5 },
|
||||||
|
deleteIcon: { fontSize: 14, marginRight: spacing.sm },
|
||||||
|
deleteText: { color: colors.textMuted, fontSize: fonts.sizes.sm },
|
||||||
|
|
||||||
// Footer
|
// Footer
|
||||||
version: { color: colors.textMuted, fontSize: 9, textAlign: 'center', marginTop: spacing.xl },
|
version: { color: colors.textMuted, fontSize: 9, textAlign: 'center', marginTop: spacing.xl },
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ export default function SplashScreen({ navigation }) {
|
|||||||
<Image
|
<Image
|
||||||
source={require('../../assets/icon.png')}
|
source={require('../../assets/icon.png')}
|
||||||
style={styles.logo}
|
style={styles.logo}
|
||||||
resizeMode="cover"
|
resizeMode="contain"
|
||||||
/>
|
/>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
|
|
||||||
@@ -114,12 +114,12 @@ export default function SplashScreen({ navigation }) {
|
|||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: { flex: 1, backgroundColor: colors.background },
|
container: { flex: 1, backgroundColor: colors.background },
|
||||||
content: { flex: 1, alignItems: 'center', justifyContent: 'center', paddingHorizontal: 40 },
|
content: { flex: 1, alignItems: 'center', justifyContent: 'center', paddingHorizontal: 40 },
|
||||||
logoContainer: { alignItems: 'center', justifyContent: 'center', marginBottom: 40 },
|
logoContainer: { alignItems: 'center', justifyContent: 'center', marginBottom: 32 },
|
||||||
glow: {
|
glow: {
|
||||||
width: 200, height: 200, borderRadius: 100,
|
width: 240, height: 240, borderRadius: 120,
|
||||||
backgroundColor: colors.planetGlow, opacity: 0.4, position: 'absolute',
|
backgroundColor: colors.planetGlow, opacity: 0.4, position: 'absolute',
|
||||||
},
|
},
|
||||||
logo: { width: 160, height: 140 },
|
logo: { width: 180, height: 180 },
|
||||||
title: {
|
title: {
|
||||||
color: colors.text, fontSize: fonts.sizes.hero,
|
color: colors.text, fontSize: fonts.sizes.hero,
|
||||||
fontWeight: fonts.weights.bold, letterSpacing: 8, marginBottom: 16,
|
fontWeight: fonts.weights.bold, letterSpacing: 8, marginBottom: 16,
|
||||||
|
|||||||
@@ -290,6 +290,60 @@ export async function signInWithFacebook() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function deleteAccount() {
|
||||||
|
if (!USE_OFFLINE) {
|
||||||
|
const { error } = await supabase.rpc('delete_user');
|
||||||
|
if (error) throw error;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const session = await getSession();
|
||||||
|
if (!session?.user?.email) throw new Error('No active session.');
|
||||||
|
|
||||||
|
const email = session.user.email.toLowerCase();
|
||||||
|
const userId = session.user.id;
|
||||||
|
|
||||||
|
// Import offline storage
|
||||||
|
const offline = await import('./offlineStorage');
|
||||||
|
|
||||||
|
// Get all user's identities to cascade delete related data
|
||||||
|
const identities = await offline.getAll('identities', { user_id: userId });
|
||||||
|
const identityIds = identities.map((i) => i.id);
|
||||||
|
|
||||||
|
// Remove all identity-related data
|
||||||
|
for (const identityId of identityIds) {
|
||||||
|
await offline.removeAll('habits', { identity_id: identityId });
|
||||||
|
await offline.removeAll('daily_logs', { identity_id: identityId });
|
||||||
|
await offline.removeAll('habit_logs', { identity_id: identityId });
|
||||||
|
await offline.removeAll('stats', { identity_id: identityId });
|
||||||
|
await offline.removeAll('game_sessions', { identity_id: identityId });
|
||||||
|
await offline.removeAll('reset_logs', { identity_id: identityId });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove identities & profile
|
||||||
|
await offline.removeAll('identities', { user_id: userId });
|
||||||
|
await offline.removeAll('profiles', { user_id: userId });
|
||||||
|
|
||||||
|
// Remove profile AsyncStorage key
|
||||||
|
await AsyncStorage.removeItem(`nova40_profile_${userId}`);
|
||||||
|
|
||||||
|
// Remove user from auth store
|
||||||
|
const users = await getStoredUsers();
|
||||||
|
delete users[email];
|
||||||
|
await saveUsers(users);
|
||||||
|
|
||||||
|
// Clear session
|
||||||
|
await clearSession();
|
||||||
|
|
||||||
|
// Clean up misc keys
|
||||||
|
const remembered = await AsyncStorage.getItem('remember_email');
|
||||||
|
if (remembered?.toLowerCase() === email) {
|
||||||
|
await AsyncStorage.removeItem('remember_email');
|
||||||
|
}
|
||||||
|
await AsyncStorage.removeItem('nova40_last_oauth');
|
||||||
|
await AsyncStorage.removeItem('nova40_onboarding_completed');
|
||||||
|
}
|
||||||
|
|
||||||
export function onAuthStateChange(callback) {
|
export function onAuthStateChange(callback) {
|
||||||
if (!USE_OFFLINE) {
|
if (!USE_OFFLINE) {
|
||||||
return supabase.auth.onAuthStateChange(callback);
|
return supabase.auth.onAuthStateChange(callback);
|
||||||
|
|||||||
@@ -137,6 +137,17 @@ const useAuthStore = create((set) => ({
|
|||||||
set({ session: null, user: null, error: null });
|
set({ session: null, user: null, error: null });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
deleteAccount: async () => {
|
||||||
|
set({ loading: true, error: null });
|
||||||
|
try {
|
||||||
|
await authService.deleteAccount();
|
||||||
|
set({ session: null, user: null, loading: false, error: null });
|
||||||
|
} catch (e) {
|
||||||
|
set({ loading: false, error: e.message });
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
fetchSession: async () => {
|
fetchSession: async () => {
|
||||||
try {
|
try {
|
||||||
const session = await authService.getSession();
|
const session = await authService.getSession();
|
||||||
|
|||||||