mirror of
https://github.com/jjbrunton/Sauci.git
synced 2026-10-31 18:19:43 +00:00
Add profile appearance and notifications settings
Co-authored-by: Claude Code <claude@anthropic.com>
This commit is contained in:
1 parent
b082da436b
commit
1452519c76
7 files changed
+114
-5
No files matched your search
@@ -142,9 +142,10 @@ Track progress by checking off completed items.
|
|||||||
- [x] Extract `ProfileHeader.tsx`
|
- [x] Extract `ProfileHeader.tsx`
|
||||||
- [x] Extract `CoupleStatus.tsx`
|
- [x] Extract `CoupleStatus.tsx`
|
||||||
- [x] Extract `SettingsSection.tsx`
|
- [x] Extract `SettingsSection.tsx`
|
||||||
- [ ] Extract `NotificationSettings.tsx`
|
- [x] Extract `NotificationSettings.tsx`
|
||||||
- [x] Extract `PrivacySettings.tsx`
|
- [x] Extract `PrivacySettings.tsx`
|
||||||
- [ ] Extract `AppearanceSettings.tsx`
|
- [x] Extract `AppearanceSettings.tsx`
|
||||||
|
|
||||||
- [x] Extract `DangerZone.tsx`
|
- [x] Extract `DangerZone.tsx`
|
||||||
- [x] Extract `SwitchItem.tsx`
|
- [x] Extract `SwitchItem.tsx`
|
||||||
- [x] Extract `MenuItem.tsx`
|
- [x] Extract `MenuItem.tsx`
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { supabase } from '../../lib/supabase'; // Needed for debug reset
|
|||||||
import { useProfileSettings, useCoupleManagement } from './hooks';
|
import { useProfileSettings, useCoupleManagement } from './hooks';
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import { ProfileHeader, CoupleStatus, PrivacySettings, DangerZone, SettingsSection, MenuItem } from './components';
|
import { AppearanceSettings, CoupleStatus, NotificationSettings, PrivacySettings, DangerZone, SettingsSection, MenuItem } from './components';
|
||||||
|
|
||||||
const MAX_CONTENT_WIDTH = 500;
|
const MAX_CONTENT_WIDTH = 500;
|
||||||
const ACCENT_GRADIENT = featureColors.profile.gradient as [string, string];
|
const ACCENT_GRADIENT = featureColors.profile.gradient as [string, string];
|
||||||
@@ -81,7 +81,7 @@ export function ProfileScreen() {
|
|||||||
</Animated.View>
|
</Animated.View>
|
||||||
|
|
||||||
{/* Profile Header */}
|
{/* Profile Header */}
|
||||||
<ProfileHeader
|
<AppearanceSettings
|
||||||
user={user}
|
user={user}
|
||||||
isUploadingAvatar={settings.isUploadingAvatar}
|
isUploadingAvatar={settings.isUploadingAvatar}
|
||||||
isEditingName={settings.isEditingName}
|
isEditingName={settings.isEditingName}
|
||||||
@@ -175,6 +175,13 @@ export function ProfileScreen() {
|
|||||||
)}
|
)}
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
|
|
||||||
|
{/* Notifications */}
|
||||||
|
<NotificationSettings
|
||||||
|
pushEnabled={settings.pushEnabled}
|
||||||
|
isUpdatingPush={settings.isUpdatingPush}
|
||||||
|
onPushToggle={settings.handlePushToggle}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Preferences */}
|
{/* Preferences */}
|
||||||
<PrivacySettings
|
<PrivacySettings
|
||||||
showExplicit={settings.showExplicit}
|
showExplicit={settings.showExplicit}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { ProfileHeader } from './ProfileHeader';
|
||||||
|
import type { ProfileHeaderProps } from './ProfileHeader';
|
||||||
|
|
||||||
|
export type AppearanceSettingsProps = ProfileHeaderProps;
|
||||||
|
|
||||||
|
export const AppearanceSettings: React.FC<AppearanceSettingsProps> = (props) => {
|
||||||
|
return <ProfileHeader {...props} />;
|
||||||
|
};
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { SettingsSection } from './SettingsSection';
|
||||||
|
import { SwitchItem } from './SwitchItem';
|
||||||
|
|
||||||
|
export interface NotificationSettingsProps {
|
||||||
|
pushEnabled: boolean;
|
||||||
|
isUpdatingPush: boolean;
|
||||||
|
onPushToggle: (value: boolean) => void;
|
||||||
|
delay?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const NotificationSettings: React.FC<NotificationSettingsProps> = ({
|
||||||
|
pushEnabled,
|
||||||
|
isUpdatingPush,
|
||||||
|
onPushToggle,
|
||||||
|
delay = 360,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<SettingsSection title="Notifications" delay={delay}>
|
||||||
|
<SwitchItem
|
||||||
|
icon="notifications-outline"
|
||||||
|
label="Push Notifications"
|
||||||
|
description="Get alerts for matches and messages"
|
||||||
|
value={pushEnabled}
|
||||||
|
onValueChange={onPushToggle}
|
||||||
|
disabled={isUpdatingPush}
|
||||||
|
/>
|
||||||
|
</SettingsSection>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -10,7 +10,7 @@ import { Profile } from '../../../types';
|
|||||||
|
|
||||||
const ACCENT_GRADIENT = featureColors.profile.gradient as [string, string];
|
const ACCENT_GRADIENT = featureColors.profile.gradient as [string, string];
|
||||||
|
|
||||||
interface ProfileHeaderProps {
|
export interface ProfileHeaderProps {
|
||||||
user: Profile | null;
|
user: Profile | null;
|
||||||
isUploadingAvatar: boolean;
|
isUploadingAvatar: boolean;
|
||||||
isEditingName: boolean;
|
isEditingName: boolean;
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
// Profile feature components
|
// Profile feature components
|
||||||
export { ProfileHeader } from './ProfileHeader';
|
export { ProfileHeader } from './ProfileHeader';
|
||||||
|
export type { ProfileHeaderProps } from './ProfileHeader';
|
||||||
|
export { AppearanceSettings } from './AppearanceSettings';
|
||||||
|
export type { AppearanceSettingsProps } from './AppearanceSettings';
|
||||||
|
export { NotificationSettings } from './NotificationSettings';
|
||||||
|
export type { NotificationSettingsProps } from './NotificationSettings';
|
||||||
export { CoupleStatus } from './CoupleStatus';
|
export { CoupleStatus } from './CoupleStatus';
|
||||||
export { PrivacySettings } from './PrivacySettings';
|
export { PrivacySettings } from './PrivacySettings';
|
||||||
export { DangerZone } from './DangerZone';
|
export { DangerZone } from './DangerZone';
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ import { decode } from 'base64-arraybuffer';
|
|||||||
import { useAuthStore, useSubscriptionStore, usePacksStore } from '../../../store';
|
import { useAuthStore, useSubscriptionStore, usePacksStore } from '../../../store';
|
||||||
import { supabase } from '../../../lib/supabase';
|
import { supabase } from '../../../lib/supabase';
|
||||||
import { Events } from '../../../lib/analytics';
|
import { Events } from '../../../lib/analytics';
|
||||||
|
import {
|
||||||
|
registerForPushNotificationsAsync,
|
||||||
|
savePushToken,
|
||||||
|
clearPushToken,
|
||||||
|
} from '../../../lib/notifications';
|
||||||
import {
|
import {
|
||||||
isBiometricAvailable,
|
isBiometricAvailable,
|
||||||
isBiometricEnabled,
|
isBiometricEnabled,
|
||||||
@@ -30,6 +35,10 @@ export function useProfileSettings() {
|
|||||||
const [showExplicit, setShowExplicit] = useState(user?.show_explicit_content ?? true);
|
const [showExplicit, setShowExplicit] = useState(user?.show_explicit_content ?? true);
|
||||||
const [isUpdatingExplicit, setIsUpdatingExplicit] = useState(false);
|
const [isUpdatingExplicit, setIsUpdatingExplicit] = useState(false);
|
||||||
|
|
||||||
|
// Notifications
|
||||||
|
const [pushEnabled, setPushEnabled] = useState(!!user?.push_token);
|
||||||
|
const [isUpdatingPush, setIsUpdatingPush] = useState(false);
|
||||||
|
|
||||||
// Biometrics
|
// Biometrics
|
||||||
const [biometricAvailable, setBiometricAvailable] = useState(false);
|
const [biometricAvailable, setBiometricAvailable] = useState(false);
|
||||||
const [biometricEnabledState, setBiometricEnabledState] = useState(false);
|
const [biometricEnabledState, setBiometricEnabledState] = useState(false);
|
||||||
@@ -47,6 +56,7 @@ export function useProfileSettings() {
|
|||||||
if (user?.show_explicit_content !== undefined) {
|
if (user?.show_explicit_content !== undefined) {
|
||||||
setShowExplicit(user.show_explicit_content);
|
setShowExplicit(user.show_explicit_content);
|
||||||
}
|
}
|
||||||
|
setPushEnabled(!!user?.push_token);
|
||||||
}, [user]);
|
}, [user]);
|
||||||
|
|
||||||
// Check biometric availability
|
// Check biometric availability
|
||||||
@@ -276,6 +286,48 @@ export function useProfileSettings() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handlePushToggle = async (value: boolean) => {
|
||||||
|
if (!user?.id) return;
|
||||||
|
|
||||||
|
if (Platform.OS === 'web') {
|
||||||
|
setPushEnabled(false);
|
||||||
|
Alert.alert("Not Supported", "Push notifications aren't available on web.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPushEnabled(value);
|
||||||
|
setIsUpdatingPush(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (value) {
|
||||||
|
const token = await registerForPushNotificationsAsync();
|
||||||
|
if (!token) {
|
||||||
|
setPushEnabled(false);
|
||||||
|
Alert.alert(
|
||||||
|
"Enable Notifications",
|
||||||
|
"Allow notifications in system settings to receive alerts.",
|
||||||
|
[
|
||||||
|
{ text: "Not Now", style: "cancel" },
|
||||||
|
{ text: "Open Settings", onPress: () => Linking.openSettings() },
|
||||||
|
]
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await savePushToken(user.id, token);
|
||||||
|
} else {
|
||||||
|
await clearPushToken(user.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
await fetchUser();
|
||||||
|
} catch (error) {
|
||||||
|
setPushEnabled(!value);
|
||||||
|
Alert.alert("Error", "Failed to update notification settings. Please try again.");
|
||||||
|
} finally {
|
||||||
|
setIsUpdatingPush(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleBiometricToggle = async (value: boolean) => {
|
const handleBiometricToggle = async (value: boolean) => {
|
||||||
setIsUpdatingBiometric(true);
|
setIsUpdatingBiometric(true);
|
||||||
|
|
||||||
@@ -330,6 +382,8 @@ export function useProfileSettings() {
|
|||||||
isUploadingAvatar,
|
isUploadingAvatar,
|
||||||
showExplicit,
|
showExplicit,
|
||||||
isUpdatingExplicit,
|
isUpdatingExplicit,
|
||||||
|
pushEnabled,
|
||||||
|
isUpdatingPush,
|
||||||
biometricAvailable,
|
biometricAvailable,
|
||||||
biometricEnabled: biometricEnabledState,
|
biometricEnabled: biometricEnabledState,
|
||||||
biometricType,
|
biometricType,
|
||||||
@@ -343,6 +397,7 @@ export function useProfileSettings() {
|
|||||||
handleCancelEditName,
|
handleCancelEditName,
|
||||||
handleAvatarPress,
|
handleAvatarPress,
|
||||||
handleExplicitToggle,
|
handleExplicitToggle,
|
||||||
|
handlePushToggle,
|
||||||
handleBiometricToggle,
|
handleBiometricToggle,
|
||||||
handleRestorePurchases,
|
handleRestorePurchases,
|
||||||
handleManageSubscription,
|
handleManageSubscription,
|
||||||
|
|||||||
Reference in new issue
Block a user