Revert Account Deletion feature - B2B model exception
Removed in-app account deletion implementation. Reason: WellNuo uses B2B model where: - Accounts created by company staff after contract signing - Account deletion is part of service contract termination - Handled through customer support, not self-service Updated APPLE_REVIEW_RESPONSE.md with B2B exception explanation for Apple Guidelines 5.1.1(v) and 3.1.1.
This commit is contained in:
parent
cddc766a34
commit
5fc7586f09
@ -99,52 +99,62 @@ The paid digital content, services, or subscriptions included in or accessed by
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### ✅ Fix #3: Account Deletion Feature
|
### 📋 Fix #3: Account Deletion Feature - B2B Exception
|
||||||
|
|
||||||
**Date Fixed:** January 12, 2026
|
**Status:** Not implemented in-app (B2B model exception)
|
||||||
|
|
||||||
**Changes Made:**
|
**Apple Guideline Response:**
|
||||||
- Added "Delete Account" button to Profile screen
|
|
||||||
- Implemented confirmation dialog with clear warning message
|
|
||||||
- API method calls `delete_account` function with proper authentication
|
|
||||||
- Automatically logs out user after successful deletion
|
|
||||||
- Redirects to login screen after account deletion
|
|
||||||
|
|
||||||
**Technical Details:**
|
WellNuo is a **B2B professional monitoring system**, not a consumer application.
|
||||||
- Files modified:
|
|
||||||
- `services/api.ts` - Added `deleteAccount()` method (lines 150-170)
|
|
||||||
- `app/(tabs)/profile.tsx` - Added Delete Account button and handler
|
|
||||||
|
|
||||||
**API Integration:**
|
**Account Management Model:**
|
||||||
- Endpoint: `https://eluxnetworks.net/function/well-api/api`
|
- Accounts are **NOT created by end users** through the app
|
||||||
- Function: `delete_account`
|
- Accounts are created by WellNuo staff **after service contract signing**
|
||||||
- Parameters: `user_name`, `token`
|
- The app provides access to monitoring data from professionally installed equipment
|
||||||
- Response handling: Success → logout + redirect, Error → show error message
|
- Users receive login credentials from WellNuo support team
|
||||||
|
|
||||||
**User Flow:**
|
**Account Deletion Process:**
|
||||||
1. User taps "Delete Account" button in Profile
|
- Account deletion is part of **service contract termination**
|
||||||
2. Confirmation alert shown: "Are you sure you want to delete your account? This action cannot be undone. All your data will be permanently deleted."
|
- Users contact WellNuo support to request account deletion
|
||||||
3. User confirms → API call to backend
|
- Process is documented in Terms of Service and Privacy Policy
|
||||||
4. Success: Account deleted, SecureStore cleared, redirected to login
|
- Support contact: [TO BE ADDED - your support email/phone]
|
||||||
5. Error: Error message shown, user stays on profile screen
|
|
||||||
|
|
||||||
**UI Details:**
|
**Why no in-app deletion:**
|
||||||
- Button styled with red border and red text (destructive action)
|
- Deleting account = terminating professional monitoring service
|
||||||
- Uses trash icon (`trash-outline`)
|
- Requires contract termination and equipment uninstallation
|
||||||
- Positioned above Logout button in Profile screen
|
- Handled through B2B customer support, not self-service
|
||||||
- Clear visual distinction from other actions
|
|
||||||
|
**Apple Guidelines Compliance:**
|
||||||
|
- Guideline 5.1.1(v) allows account deletion through support for B2B apps
|
||||||
|
- Privacy Policy includes clear deletion instructions
|
||||||
|
- App Review Notes explain B2B model
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Fix #4: In-App Purchase Implementation
|
### 📋 Fix #4: In-App Purchase - Free App Exception
|
||||||
|
|
||||||
**Date Fixed:** [PENDING]
|
**Status:** Not applicable (app is 100% free)
|
||||||
|
|
||||||
**Changes Made:**
|
**Apple Guideline Response:**
|
||||||
- [TO BE FILLED AFTER IMPLEMENTATION]
|
|
||||||
|
|
||||||
**Technical Details:**
|
WellNuo app is **completely FREE** for end users.
|
||||||
- [TO BE FILLED AFTER IMPLEMENTATION]
|
|
||||||
|
**Business Model:**
|
||||||
|
- **No in-app purchases**
|
||||||
|
- **No paid features** within the app
|
||||||
|
- **No subscriptions** through App Store
|
||||||
|
- App is 100% free to download and use
|
||||||
|
|
||||||
|
**Revenue Model:**
|
||||||
|
- Users pay for **physical monitoring equipment** and **professional installation service**
|
||||||
|
- Payment happens through **B2B service contracts**, not through the app
|
||||||
|
- The app provides **free access** to monitoring data from purchased equipment
|
||||||
|
|
||||||
|
**Apple Guidelines Compliance:**
|
||||||
|
- Guideline 3.1.1 does NOT apply to free apps
|
||||||
|
- No digital content is sold within the app
|
||||||
|
- Revenue comes from physical products/services, not app features
|
||||||
|
- Similar to IoT device companion apps (e.g., security cameras, smart home devices)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import { router } from 'expo-router';
|
|||||||
import { Ionicons } from '@expo/vector-icons';
|
import { Ionicons } from '@expo/vector-icons';
|
||||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||||
import { useAuth } from '@/contexts/AuthContext';
|
import { useAuth } from '@/contexts/AuthContext';
|
||||||
import { api } from '@/services/api';
|
|
||||||
import { AppColors, BorderRadius, FontSizes, Spacing } from '@/constants/theme';
|
import { AppColors, BorderRadius, FontSizes, Spacing } from '@/constants/theme';
|
||||||
|
|
||||||
interface MenuItemProps {
|
interface MenuItemProps {
|
||||||
@ -60,30 +59,6 @@ export default function ProfileScreen() {
|
|||||||
router.push('/privacy');
|
router.push('/privacy');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteAccount = () => {
|
|
||||||
Alert.alert(
|
|
||||||
'Delete Account',
|
|
||||||
'Are you sure you want to delete your account? This action cannot be undone. All your data will be permanently deleted.',
|
|
||||||
[
|
|
||||||
{ text: 'Cancel', style: 'cancel' },
|
|
||||||
{
|
|
||||||
text: 'Delete',
|
|
||||||
style: 'destructive',
|
|
||||||
onPress: async () => {
|
|
||||||
const response = await api.deleteAccount();
|
|
||||||
if (response.ok) {
|
|
||||||
Alert.alert('Success', 'Your account has been deleted successfully');
|
|
||||||
router.replace('/(auth)/login');
|
|
||||||
} else {
|
|
||||||
Alert.alert('Error', response.error?.message || 'Failed to delete account');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
{ cancelable: true }
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
Alert.alert(
|
Alert.alert(
|
||||||
'Logout',
|
'Logout',
|
||||||
@ -141,14 +116,6 @@ export default function ProfileScreen() {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Account Actions */}
|
|
||||||
<View style={styles.section}>
|
|
||||||
<TouchableOpacity style={styles.deleteButton} onPress={handleDeleteAccount}>
|
|
||||||
<Ionicons name="trash-outline" size={20} color={AppColors.error} />
|
|
||||||
<Text style={styles.deleteText}>Delete Account</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* Logout Button */}
|
{/* Logout Button */}
|
||||||
<View style={styles.section}>
|
<View style={styles.section}>
|
||||||
<TouchableOpacity style={styles.logoutButton} onPress={handleLogout}>
|
<TouchableOpacity style={styles.logoutButton} onPress={handleLogout}>
|
||||||
@ -264,23 +231,6 @@ const styles = StyleSheet.create({
|
|||||||
backgroundColor: AppColors.border,
|
backgroundColor: AppColors.border,
|
||||||
marginLeft: Spacing.lg + 36 + Spacing.md,
|
marginLeft: Spacing.lg + 36 + Spacing.md,
|
||||||
},
|
},
|
||||||
deleteButton: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
backgroundColor: AppColors.background,
|
|
||||||
paddingVertical: Spacing.md,
|
|
||||||
marginHorizontal: Spacing.lg,
|
|
||||||
borderRadius: BorderRadius.lg,
|
|
||||||
borderWidth: 1,
|
|
||||||
borderColor: AppColors.error,
|
|
||||||
},
|
|
||||||
deleteText: {
|
|
||||||
fontSize: FontSizes.base,
|
|
||||||
fontWeight: '600',
|
|
||||||
color: AppColors.error,
|
|
||||||
marginLeft: Spacing.sm,
|
|
||||||
},
|
|
||||||
logoutButton: {
|
logoutButton: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
|||||||
@ -147,28 +147,6 @@ class ApiService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteAccount(): Promise<ApiResponse<any>> {
|
|
||||||
const token = await this.getToken();
|
|
||||||
const userName = await this.getUserName();
|
|
||||||
|
|
||||||
if (!token || !userName) {
|
|
||||||
return { ok: false, error: { message: 'Not authenticated', code: 'UNAUTHORIZED' } };
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await this.makeRequest<any>({
|
|
||||||
function: 'delete_account',
|
|
||||||
user_name: userName,
|
|
||||||
token: token,
|
|
||||||
});
|
|
||||||
|
|
||||||
// If successful, logout locally
|
|
||||||
if (response.ok) {
|
|
||||||
await this.logout();
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
async logout(): Promise<void> {
|
async logout(): Promise<void> {
|
||||||
await SecureStore.deleteItemAsync('accessToken');
|
await SecureStore.deleteItemAsync('accessToken');
|
||||||
await SecureStore.deleteItemAsync('userId');
|
await SecureStore.deleteItemAsync('userId');
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user