diff --git a/apps/mobile/app.config.js b/apps/mobile/app.config.js index 96c2c77..cb6aaff 100644 --- a/apps/mobile/app.config.js +++ b/apps/mobile/app.config.js @@ -9,7 +9,7 @@ export default { splash: { image: "./assets/splash.png", resizeMode: "cover", - backgroundColor: "#4338ca" + backgroundColor: "#2f3e4e" }, ios: { supportsTablet: true @@ -18,7 +18,7 @@ export default { googleServicesFile: process.env.GOOGLE_SERVICES_JSON ?? "./google-services.json", adaptiveIcon: { foregroundImage: "./assets/adaptive-icon.png", - backgroundColor: "#4338ca" + backgroundColor: "#2f3e4e" }, package: "com.inspirebyte.vaastio", edgeToEdgeEnabled: false, diff --git a/apps/mobile/assets/logo.png b/apps/mobile/assets/logo.png new file mode 100644 index 0000000..30f98f4 Binary files /dev/null and b/apps/mobile/assets/logo.png differ diff --git a/apps/mobile/src/constants/colors.ts b/apps/mobile/src/constants/colors.ts index 154e520..960f3c0 100644 --- a/apps/mobile/src/constants/colors.ts +++ b/apps/mobile/src/constants/colors.ts @@ -1,5 +1,5 @@ export const Colors = { - primary: '#4338ca', + primary: '#2f3e4e', background: '#f8fafc', surface: '#ffffff', text: '#0f172a', diff --git a/apps/mobile/src/screens/announcements/AnnouncementDetailScreen.tsx b/apps/mobile/src/screens/announcements/AnnouncementDetailScreen.tsx index 82050d6..d7bddd9 100644 --- a/apps/mobile/src/screens/announcements/AnnouncementDetailScreen.tsx +++ b/apps/mobile/src/screens/announcements/AnnouncementDetailScreen.tsx @@ -27,15 +27,19 @@ import { getApiErrorCode } from '../../services/api' import { getErrorMessage } from '../../utils/errorMessages' import { Colors } from '../../constants/colors' import { Spacing } from '../../constants/spacing' +import { Ionicons } from '@expo/vector-icons' type Props = NativeStackScreenProps -const CATEGORY_ICON: Record = { - GENERAL: '๐Ÿ“ข', - MAINTENANCE: '๐Ÿ”ง', - MEETING: '๐Ÿ‘ฅ', - EMERGENCY: '๐Ÿšจ', - CELEBRATION: '๐ŸŽ‰', +const CATEGORY_ICON: Record< + AnnouncementCategory, + keyof typeof Ionicons.glyphMap +> = { + GENERAL: 'megaphone-outline', + MAINTENANCE: 'construct-outline', + MEETING: 'people-outline', + EMERGENCY: 'warning-outline', + CELEBRATION: 'sparkles-outline', } const CATEGORY_COLORS: Record = { @@ -122,7 +126,11 @@ export function AnnouncementDetailScreen({ route, navigation }: Props) { {/* Badges row */} - {CATEGORY_ICON[announcement.category]} + {announcement.category.charAt(0) + announcement.category.slice(1).toLowerCase()} diff --git a/apps/mobile/src/screens/announcements/AnnouncementsListScreen.tsx b/apps/mobile/src/screens/announcements/AnnouncementsListScreen.tsx index 417b644..3080580 100644 --- a/apps/mobile/src/screens/announcements/AnnouncementsListScreen.tsx +++ b/apps/mobile/src/screens/announcements/AnnouncementsListScreen.tsx @@ -20,6 +20,7 @@ import { useAuth } from '../../hooks/useAuth' import { listAnnouncements, Announcement, AnnouncementCategory } from '../../services/announcements' import { Colors } from '../../constants/colors' import { Spacing } from '../../constants/spacing' +import { Ionicons } from '@expo/vector-icons' type Props = NativeStackScreenProps @@ -34,13 +35,16 @@ const FILTERS: { label: string; value: CategoryFilter }[] = [ { label: 'Celebration', value: 'CELEBRATION' }, ] -const CATEGORY_ICON: Record = { - GENERAL: '๐Ÿ“ข', - MAINTENANCE: '๐Ÿ”ง', - MEETING: '๐Ÿ‘ฅ', - EMERGENCY: '๐Ÿšจ', - CELEBRATION: '๐ŸŽ‰', -} +const CATEGORY_ICON: Record< + AnnouncementCategory, + keyof typeof Ionicons.glyphMap + > = { + GENERAL: 'megaphone-outline', + MAINTENANCE: 'construct-outline', + MEETING: 'people-outline', + EMERGENCY: 'warning-outline', + CELEBRATION: 'sparkles-outline', + } const CATEGORY_COLORS: Record = { GENERAL: { bg: '#f3f4f6', text: '#6b7280', icon: '#9ca3af' }, @@ -98,14 +102,24 @@ export function AnnouncementsListScreen({ route, navigation }: Props) { style={({ pressed }) => [styles.row, pressed && styles.rowPressed]} > - {CATEGORY_ICON[item.category]} + {item.title} - {item.isPinned ? ๐Ÿ“Œ : null} + {item.isPinned ? ( + + ) : null} {item.body} @@ -262,7 +276,6 @@ const styles = StyleSheet.create({ justifyContent: 'center', flexShrink: 0, }, - rowIconText: { fontSize: 18 }, rowContent: { flex: 1, gap: 4 }, rowTop: { flexDirection: 'row', alignItems: 'center', gap: 6 }, rowTitle: { flex: 1, fontSize: 15, fontWeight: '600', color: Colors.text }, diff --git a/apps/mobile/src/screens/auth/LoginOTPScreen.tsx b/apps/mobile/src/screens/auth/LoginOTPScreen.tsx index 2bf9d2b..b2d8067 100644 --- a/apps/mobile/src/screens/auth/LoginOTPScreen.tsx +++ b/apps/mobile/src/screens/auth/LoginOTPScreen.tsx @@ -25,7 +25,7 @@ import { Colors } from '../../constants/colors' type Props = NativeStackScreenProps const OTP_LENGTH = 6 -const BRAND = '#4338ca' +const BRAND = '#2f3e4e' export function LoginOTPScreen({ route, navigation }: Props) { const { phone } = route.params @@ -125,7 +125,7 @@ export function LoginOTPScreen({ route, navigation }: Props) { if (!fontsLoaded) return null return ( - + {/* โ”€โ”€ Top: gradient header โ”€โ”€ */} diff --git a/apps/mobile/src/screens/auth/LoginPhoneScreen.tsx b/apps/mobile/src/screens/auth/LoginPhoneScreen.tsx index ca162bb..46c3aea 100644 --- a/apps/mobile/src/screens/auth/LoginPhoneScreen.tsx +++ b/apps/mobile/src/screens/auth/LoginPhoneScreen.tsx @@ -24,7 +24,7 @@ import { Colors } from '../../constants/colors' type Props = NativeStackScreenProps -const BRAND = '#4338ca' +const BRAND = '#2f3e4e' export function LoginPhoneScreen({ navigation }: Props) { const insets = useSafeAreaInsets() @@ -62,7 +62,7 @@ export function LoginPhoneScreen({ navigation }: Props) { if (!fontsLoaded) return null return ( - + {/* โ”€โ”€ Top: gradient header โ”€โ”€ */} @@ -77,7 +77,7 @@ export function LoginPhoneScreen({ navigation }: Props) { diff --git a/apps/mobile/src/screens/auth/SetNameScreen.tsx b/apps/mobile/src/screens/auth/SetNameScreen.tsx index 1697dac..03618ba 100644 --- a/apps/mobile/src/screens/auth/SetNameScreen.tsx +++ b/apps/mobile/src/screens/auth/SetNameScreen.tsx @@ -21,7 +21,7 @@ import { Colors } from '../../constants/colors' type Props = NativeStackScreenProps -const BRAND = '#4338ca' +const BRAND = '#2f3e4e' export function SetNameScreen({ route, navigation }: Props) { const { requiresOrgSelection, memberships, currentOrgId } = route.params @@ -70,7 +70,7 @@ export function SetNameScreen({ route, navigation }: Props) { if (!fontsLoaded) return null return ( - + {/* โ”€โ”€ Top: gradient header โ”€โ”€ */} diff --git a/apps/mobile/src/screens/auth/WelcomeScreen.tsx b/apps/mobile/src/screens/auth/WelcomeScreen.tsx index 22e3ff8..9e0fb3c 100644 --- a/apps/mobile/src/screens/auth/WelcomeScreen.tsx +++ b/apps/mobile/src/screens/auth/WelcomeScreen.tsx @@ -9,7 +9,7 @@ import { AuthStackParamList } from '../../navigation/AuthNavigator' type Props = NativeStackScreenProps -const BRAND = '#4338ca' +const BRAND = '#2f3e4e' const FEATURES: React.ComponentProps['name'][] = [ 'business-outline', @@ -26,13 +26,13 @@ export function WelcomeScreen({ navigation }: Props) { if (!fontsLoaded) return null return ( - + {/* โ”€โ”€ Brand area โ”€โ”€ */} @@ -81,7 +81,6 @@ const styles = StyleSheet.create({ logo: { width: 92, height: 116, - tintColor: '#fff', marginBottom: 4, }, appName: { diff --git a/apps/mobile/src/screens/complaints/ComplaintDetailScreen.tsx b/apps/mobile/src/screens/complaints/ComplaintDetailScreen.tsx index cc050a1..624aed0 100644 --- a/apps/mobile/src/screens/complaints/ComplaintDetailScreen.tsx +++ b/apps/mobile/src/screens/complaints/ComplaintDetailScreen.tsx @@ -25,6 +25,7 @@ import { getApiErrorCode } from '../../services/api' import { getErrorMessage } from '../../utils/errorMessages' import { Colors } from '../../constants/colors' import { Spacing } from '../../constants/spacing' +import { Ionicons } from '@expo/vector-icons' type Props = NativeStackScreenProps @@ -168,14 +169,32 @@ export function ComplaintDetailScreen({ route }: Props) { {/* Category + Visibility tags */} - - {CATEGORY_ICON[complaint.category]}{' '}{CATEGORY_LABEL[complaint.category]} - + + + + {CATEGORY_LABEL[complaint.category]} + + - - {complaint.visibility === 'PUBLIC' ? '๐ŸŒ Public' : '๐Ÿ”’ Private'} - + + + + {complaint.visibility === 'PUBLIC' ? 'Public' : 'Private'} + + diff --git a/apps/mobile/src/screens/complaints/ComplaintListScreen.tsx b/apps/mobile/src/screens/complaints/ComplaintListScreen.tsx index e63f77d..abadab6 100644 --- a/apps/mobile/src/screens/complaints/ComplaintListScreen.tsx +++ b/apps/mobile/src/screens/complaints/ComplaintListScreen.tsx @@ -21,6 +21,7 @@ import { listComplaints, ComplaintListItem, ComplaintStatus } from '../../servic import { CATEGORY_LABEL, CATEGORY_ICON, STATUS_LABEL, STATUS_COLORS } from '../../utils/complaintMeta' import { Colors } from '../../constants/colors' import { Spacing } from '../../constants/spacing' +import { Ionicons } from '@expo/vector-icons' type Props = NativeStackScreenProps @@ -146,7 +147,11 @@ export function ComplaintListScreen({ route, navigation }: Props) { style={({ pressed }) => [styles.row, pressed && styles.rowPressed]} > - {CATEGORY_ICON[c.category] ?? '๐Ÿ“‹'} + @@ -365,7 +370,6 @@ const styles = StyleSheet.create({ justifyContent: 'center', flexShrink: 0, }, - rowIconText: { fontSize: 18 }, rowContent: { flex: 1, gap: 4 }, rowTop: { flexDirection: 'row', alignItems: 'center', gap: 8 }, rowTitle: { flex: 1, fontSize: 15, fontWeight: '600', color: Colors.text }, diff --git a/apps/mobile/src/screens/complaints/RaiseComplaintScreen.tsx b/apps/mobile/src/screens/complaints/RaiseComplaintScreen.tsx index 6dfe701..b7f964e 100644 --- a/apps/mobile/src/screens/complaints/RaiseComplaintScreen.tsx +++ b/apps/mobile/src/screens/complaints/RaiseComplaintScreen.tsx @@ -21,6 +21,7 @@ import { getApiErrorCode, getApiErrorDetails } from '../../services/api' import { getErrorMessage } from '../../utils/errorMessages' import { Colors } from '../../constants/colors' import { Spacing } from '../../constants/spacing' +import { Ionicons } from '@expo/vector-icons' type Props = NativeStackScreenProps @@ -186,31 +187,74 @@ export function RaiseComplaintScreen({ route, navigation }: Props) { {/* Visibility toggle */} - Visibility - - setVisibility('PRIVATE')} - style={[styles.visibilityCard, visibility === 'PRIVATE' && styles.visibilityCardActive]} - > - ๐Ÿ”’ - - Private - - Only admins can see this - - - setVisibility('PUBLIC')} - style={[styles.visibilityCard, visibility === 'PUBLIC' && styles.visibilityCardActive]} - > - ๐ŸŒ - - Public - - Visible to all residents - - - + Visibility + + + + {/* Private */} + setVisibility('PRIVATE')} + style={[ + styles.visibilityCard, + visibility === 'PRIVATE' && styles.visibilityCardActive, + ]} + > + + + + Private + + + + Only admins can see this + + + + {/* Public */} + setVisibility('PUBLIC')} + style={[ + styles.visibilityCard, + visibility === 'PUBLIC' && styles.visibilityCardActive, + ]} + > + + + + Public + + + + Visible to all residents + + + + + {/* Image picker */} @@ -338,7 +382,7 @@ const styles = StyleSheet.create({ borderColor: Colors.primary, backgroundColor: '#ede9fe', }, - visibilityIcon: { fontSize: 22 }, + visibilityIcon: { marginBottom: 6 }, visibilityLabel: { fontSize: 14, fontWeight: '600', diff --git a/apps/mobile/src/screens/society/DashboardScreen.tsx b/apps/mobile/src/screens/society/DashboardScreen.tsx index 9b5596b..78550af 100644 --- a/apps/mobile/src/screens/society/DashboardScreen.tsx +++ b/apps/mobile/src/screens/society/DashboardScreen.tsx @@ -25,6 +25,7 @@ import { getApiErrorCode } from '../../services/api' import { getErrorMessage } from '../../utils/errorMessages' import { Colors } from '../../constants/colors' import { Spacing } from '../../constants/spacing' +import { Ionicons } from '@expo/vector-icons' type Props = NativeStackScreenProps @@ -218,7 +219,7 @@ export function DashboardScreen({ route, navigation }: Props) { {canViewAnnouncements ? ( navigation.navigate('AnnouncementsList', { societyId })} @@ -226,7 +227,7 @@ export function DashboardScreen({ route, navigation }: Props) { ) : null} {canViewStructure ? ( navigation.navigate('Structure', { societyId })} @@ -234,7 +235,7 @@ export function DashboardScreen({ route, navigation }: Props) { ) : null} {canInvite ? ( navigation.navigate('InviteMember', { societyId })} @@ -242,7 +243,7 @@ export function DashboardScreen({ route, navigation }: Props) { ) : null} {canViewMembers ? ( navigation.navigate('MemberList', { societyId })} @@ -250,7 +251,7 @@ export function DashboardScreen({ route, navigation }: Props) { ) : null} {canViewComplaints ? ( navigation.navigate('ComplaintList', { societyId })} @@ -258,7 +259,7 @@ export function DashboardScreen({ route, navigation }: Props) { ) : null} {canViewUnitInventory ? ( navigation.navigate('UnitInventory', { societyId })} @@ -266,7 +267,7 @@ export function DashboardScreen({ route, navigation }: Props) { ) : null} {canViewMyHome && currentMemberId ? ( navigation.navigate('MyHome', { societyId, memberId: currentMemberId })} @@ -274,7 +275,7 @@ export function DashboardScreen({ route, navigation }: Props) { ) : null} {canSwitchSociety ? ( navigation.navigate('SwitchSociety')} @@ -351,25 +352,31 @@ export function DashboardScreen({ route, navigation }: Props) { // โ”€โ”€โ”€ Action Row โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ interface ActionRowProps { - icon: string - label: string - subtitle: string - onPress: () => void + icon: keyof typeof Ionicons.glyphMap } function ActionRow({ icon, label, subtitle, onPress }: ActionRowProps) { return ( [styles.actionRow, pressed && styles.actionRowPressed]} + style={({ pressed }) => [ + styles.actionRow, + pressed && styles.actionRowPressed, + ]} > - {icon} + + {label} {subtitle} + โ€บ ) diff --git a/apps/mobile/src/utils/complaintMeta.ts b/apps/mobile/src/utils/complaintMeta.ts index 7f13ce9..d415c3f 100644 --- a/apps/mobile/src/utils/complaintMeta.ts +++ b/apps/mobile/src/utils/complaintMeta.ts @@ -1,4 +1,5 @@ import { ComplaintCategory, ComplaintStatus } from '../services/complaints' +import { Ionicons } from '@expo/vector-icons' export const CATEGORY_LABEL: Record = { WATER_SUPPLY: 'Water Supply', @@ -22,26 +23,29 @@ export const CATEGORY_LABEL: Record = { OTHER: 'Other', } -export const CATEGORY_ICON: Record = { - WATER_SUPPLY: '๐Ÿ’ง', - ELECTRICITY: 'โšก', - LIFT_ELEVATOR: '๐Ÿ”ผ', - GENERATOR: '๐Ÿ”‹', - INTERNET_CABLE: '๐Ÿ“ก', - PARKING: '๐Ÿ…ฟ๏ธ', - GARBAGE_WASTE: '๐Ÿ—‘๏ธ', - GARDEN_LANDSCAPING: '๐ŸŒฟ', - GYM_CLUBHOUSE: '๐Ÿ‹๏ธ', - SWIMMING_POOL: '๐ŸŠ', - SECURITY: '๐Ÿ”’', - NOISE: '๐Ÿ“ข', - PET_RELATED: '๐Ÿพ', - DOMESTIC_HELP: '๐Ÿงน', - NEIGHBOUR_BEHAVIOUR: '๐Ÿ‘ฅ', - STAFF_BEHAVIOUR: '๐Ÿ‘ท', - MAINTENANCE_REPAIR: '๐Ÿ”ง', - RULE_VIOLATION: 'โš ๏ธ', - OTHER: '๐Ÿ“‹', +export const CATEGORY_ICON: Record< + ComplaintCategory, + keyof typeof Ionicons.glyphMap +> = { + WATER_SUPPLY: 'water-outline', + ELECTRICITY: 'flash-outline', + LIFT_ELEVATOR: 'arrow-up-circle-outline', + GENERATOR: 'battery-charging-outline', + INTERNET_CABLE: 'wifi-outline', + PARKING: 'car-outline', + GARBAGE_WASTE: 'trash-outline', + GARDEN_LANDSCAPING: 'leaf-outline', + GYM_CLUBHOUSE: 'barbell-outline', + SWIMMING_POOL: 'water-outline', + SECURITY: 'shield-checkmark-outline', + NOISE: 'volume-high-outline', + PET_RELATED: 'paw-outline', + DOMESTIC_HELP: 'home-outline', + NEIGHBOUR_BEHAVIOUR: 'people-outline', + STAFF_BEHAVIOUR: 'person-outline', + MAINTENANCE_REPAIR: 'construct-outline', + RULE_VIOLATION: 'warning-outline', + OTHER: 'document-text-outline', } export const STATUS_LABEL: Record = {