Asset,Alarm,Module Screen is added
This commit is contained in:
47
App.tsx
47
App.tsx
@@ -1,25 +1,32 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { StatusBar, StyleSheet, View } from 'react-native';
|
import { View } from 'react-native';
|
||||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
import ModuleScreen from './src/screens/ModuleScreen/moduleScreen';
|
||||||
import HomeScreen from './src/screens/HomeScreen/homeScreen';
|
import AlarmsScreen from './src/screens/AlarmScreen/alarmScreen';
|
||||||
import { COLORS } from './src/constants/color';
|
import AssetsScreen from './src/screens/AssetsScreen/assetScreen';
|
||||||
import { AssetCard } from './src/components/assetCard';
|
import HomeScreen from './src/screens/HomeScreen/homeScreen';
|
||||||
import AssetScreen from './src/screens/AssetsScreen/assetScreen';
|
import BottomTabBar, { TabType } from './src/navigation/bottonTabBar';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default function App(): React.JSX.Element {
|
||||||
|
// Use generic type annotation for useState
|
||||||
|
const [activeTab, setActiveTab] = useState<TabType>('Home');
|
||||||
|
|
||||||
export default function App() {
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaProvider>
|
<View style={{ flex: 1 }}>
|
||||||
<View style={styles.container}>
|
|
||||||
<StatusBar barStyle="light-content" backgroundColor={COLORS.background} />
|
{/* SCREEN AREA */}
|
||||||
<AssetScreen />
|
<View style={{ flex: 1 }}>
|
||||||
|
{activeTab === 'Home' && <HomeScreen />}
|
||||||
|
{activeTab === 'Assets' && <AssetsScreen />}
|
||||||
|
{/* {activeTab === 'Scan' && <ScanScreen />} */}
|
||||||
|
{activeTab === 'Alarms' && <AlarmsScreen />}
|
||||||
|
{activeTab === 'More' && <ModuleScreen />}
|
||||||
</View>
|
</View>
|
||||||
</SafeAreaProvider>
|
|
||||||
|
{/* BOTTOM TAB BAR */}
|
||||||
|
<BottomTabBar activeTab={activeTab} setActiveTab={setActiveTab} />
|
||||||
|
|
||||||
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
backgroundColor: COLORS.background,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
3993
package-lock.json
generated
3993
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -11,9 +11,13 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-native/new-app-screen": "0.86.0",
|
"@react-native/new-app-screen": "0.86.0",
|
||||||
|
"@react-navigation/bottom-tabs": "^7.18.15",
|
||||||
|
"@react-navigation/native": "^7.3.15",
|
||||||
|
"expo-router": "^57.0.11",
|
||||||
"react": "19.2.3",
|
"react": "19.2.3",
|
||||||
"react-native": "0.86.0",
|
"react-native": "0.86.0",
|
||||||
"react-native-safe-area-context": "^5.8.0",
|
"react-native-safe-area-context": "^5.8.1",
|
||||||
|
"react-native-screens": "^4.26.2",
|
||||||
"react-native-svg": "^15.15.5",
|
"react-native-svg": "^15.15.5",
|
||||||
"react-native-vector-icons": "^10.3.0"
|
"react-native-vector-icons": "^10.3.0"
|
||||||
},
|
},
|
||||||
|
|||||||
104
src/components/Alarm/alarmCard.tsx
Normal file
104
src/components/Alarm/alarmCard.tsx
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { View, Text, TouchableOpacity } from 'react-native';
|
||||||
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||||
|
|
||||||
|
import { COLORS } from '../../constants/color';
|
||||||
|
import { AlarmCardProps, SeverityLevel } from '../../types/type';
|
||||||
|
import { styles } from '../../styles/Alarm/alarmcard';
|
||||||
|
|
||||||
|
// Map severity levels to designated theme colors
|
||||||
|
const getSeverityColor = (severity: SeverityLevel): string => {
|
||||||
|
switch (severity) {
|
||||||
|
case 'CRITICAL':
|
||||||
|
return COLORS.red;
|
||||||
|
case 'HIGH':
|
||||||
|
return COLORS.red;
|
||||||
|
case 'MEDIUM':
|
||||||
|
return COLORS.orange;
|
||||||
|
case 'LOW':
|
||||||
|
return COLORS.cyan;
|
||||||
|
default:
|
||||||
|
return COLORS.textSecondary;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function AlarmCard ({alarm,onAcknowledge,onAssign,onPressDetails }:AlarmCardProps)
|
||||||
|
{
|
||||||
|
const accentColor = getSeverityColor(alarm.severity);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.card,
|
||||||
|
alarm.isExpanded && { borderColor: accentColor },
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{/* Vertical Accent Strip */}
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.statusIndicator,
|
||||||
|
{ backgroundColor: accentColor },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<View style={styles.cardContent}>
|
||||||
|
{/* Header */}
|
||||||
|
<View style={styles.headerRow}>
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.badge,
|
||||||
|
{ backgroundColor: `${accentColor}20` },
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
styles.badgeText,
|
||||||
|
{ color: accentColor },
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{alarm.severity}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Text style={styles.timeAgo}>{alarm.timeAgo}</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Title */}
|
||||||
|
<Text style={styles.title}>{alarm.title}</Text>
|
||||||
|
|
||||||
|
{/* Details */}
|
||||||
|
<Text style={styles.details}>{alarm.details}</Text>
|
||||||
|
|
||||||
|
{/* Expanded Buttons */}
|
||||||
|
{alarm.isExpanded && (
|
||||||
|
<View style={styles.actionRow}>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={styles.acknowledgeButton}
|
||||||
|
onPress={() => onAcknowledge?.(alarm.id)}
|
||||||
|
>
|
||||||
|
<Text style={styles.acknowledgeText}>Acknowledge</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
<TouchableOpacity
|
||||||
|
style={styles.assignButton}
|
||||||
|
onPress={() => onAssign?.(alarm.id)}
|
||||||
|
>
|
||||||
|
<Text style={styles.assignText}>Assign</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
<TouchableOpacity
|
||||||
|
style={styles.iconButton}
|
||||||
|
onPress={() => onPressDetails?.(alarm.id)}
|
||||||
|
>
|
||||||
|
<Ionicons
|
||||||
|
name="chevron-forward"
|
||||||
|
size={18}
|
||||||
|
color={COLORS.textPrimary}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { View, Text } from "react-native";
|
import { View, Text } from "react-native";
|
||||||
import { Asset, AssetCardProps } from "../types/type";
|
import { Asset, AssetCardProps } from "../../types/type";
|
||||||
import { styles } from "../styles/AssetCard";
|
import { styles } from "../../styles/Asset/AssetCard";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { View, TextInput } from "react-native";
|
import { View, TextInput } from "react-native";
|
||||||
import { COLORS } from "../constants/color";
|
import { COLORS } from "../../constants/color";
|
||||||
import { styles } from "../styles/SearchbarStyles";
|
import { styles } from "../../styles/Home/SearchbarStyles";
|
||||||
import {SearchBarProps} from "../types/type"
|
import {SearchBarProps} from "../../types/type"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { View, Text, TouchableOpacity } from 'react-native';
|
import { View, Text, TouchableOpacity } from 'react-native';
|
||||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||||
import { styles } from '../styles/ActionGridStyles';
|
import { styles } from '../../styles/Home/ActionGridStyles';
|
||||||
import { actions } from '../constants/data';
|
import { actions } from '../../constants/data';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { View, Text, TouchableOpacity } from 'react-native';
|
import { View, Text, TouchableOpacity } from 'react-native';
|
||||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||||
import { COLORS } from '../constants/color';
|
import { COLORS } from '../../constants/color';
|
||||||
import { HeaderProps } from '../types/type';
|
import { HeaderProps } from '../../types/type';
|
||||||
import { styles } from '../styles/HeaderStyles';
|
import { styles } from '../../styles/Home/HeaderStyles';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -2,9 +2,9 @@ import React from 'react';
|
|||||||
import { View, Text } from 'react-native';
|
import { View, Text } from 'react-native';
|
||||||
import Svg, { Circle } from 'react-native-svg';
|
import Svg, { Circle } from 'react-native-svg';
|
||||||
|
|
||||||
import { COLORS } from '../constants/color';
|
import { COLORS } from '../../constants/color';
|
||||||
import { styles } from '../styles/SiteHealthCardStyles';
|
import { styles } from '../../styles/Home/SiteHealthCardStyles';
|
||||||
import Card from '../utils/card';
|
import Card from '../common/card';
|
||||||
|
|
||||||
export default function SiteHealthCard() {
|
export default function SiteHealthCard() {
|
||||||
return (
|
return (
|
||||||
@@ -2,9 +2,9 @@ import React from 'react';
|
|||||||
import { View, Text } from 'react-native';
|
import { View, Text } from 'react-native';
|
||||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||||
|
|
||||||
import { StatCardProps } from '../types/type';
|
import { StatCardProps } from '../../types/type';
|
||||||
import Card from '../utils/card';
|
import Card from '../common/card';
|
||||||
import { styles } from '../styles/StatCardStyle';
|
import { styles } from '../../styles/StatCardStyle';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
76
src/components/Module/module.tsx
Normal file
76
src/components/Module/module.tsx
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Text, TouchableOpacity, StyleSheet, View, Platform } from 'react-native';
|
||||||
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||||
|
|
||||||
|
import { COLORS } from '../../constants/color';
|
||||||
|
import Card from '../common/card';
|
||||||
|
|
||||||
|
export interface ModuleItem {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
iconName: string;
|
||||||
|
iconColor: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ModuleTileProps {
|
||||||
|
module: ModuleItem;
|
||||||
|
onPress?: (module: ModuleItem) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ModuleTile: React.FC<ModuleTileProps> = ({ module, onPress }) => {
|
||||||
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
activeOpacity={0.7}
|
||||||
|
style={styles.touchable}
|
||||||
|
onPress={() => onPress?.(module)}
|
||||||
|
>
|
||||||
|
<Card style={styles.cardOverride}>
|
||||||
|
<View style={styles.iconContainer}>
|
||||||
|
<Ionicons name={module.iconName} size={28} color={module.iconColor} />
|
||||||
|
</View>
|
||||||
|
<Text style={styles.title} numberOfLines={2}>
|
||||||
|
{module.title}
|
||||||
|
</Text>
|
||||||
|
</Card>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
touchable: {
|
||||||
|
width: '30.5%',
|
||||||
|
},
|
||||||
|
cardOverride: {
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
paddingVertical: 16,
|
||||||
|
paddingHorizontal: 8,
|
||||||
|
height: 100,
|
||||||
|
borderRadius: 16,
|
||||||
|
backgroundColor: '#162032', // Dark card background
|
||||||
|
|
||||||
|
// --- BORDER STYLING ---
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: 'rgba(255, 255, 255, 0.08)', // Subtle border highlight
|
||||||
|
|
||||||
|
// --- SHADOW FOR iOS ---
|
||||||
|
shadowColor: '#000',
|
||||||
|
shadowOffset: { width: 0, height: 4 },
|
||||||
|
shadowOpacity: 0.35,
|
||||||
|
shadowRadius: 6,
|
||||||
|
|
||||||
|
// --- SHADOW FOR ANDROID ---
|
||||||
|
elevation: 6,
|
||||||
|
},
|
||||||
|
iconContainer: {
|
||||||
|
marginBottom: 8,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
color: '#FFFFFF',
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: '500',
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
});
|
||||||
83
src/components/Notification/notificationcard.tsx
Normal file
83
src/components/Notification/notificationcard.tsx
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
|
||||||
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||||
|
import { NotificationCardProps } from '../../types/type';
|
||||||
|
import Card from '../common/card';
|
||||||
|
import { COLORS } from '../../constants/color';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const NotificationCard: React.FC<NotificationCardProps> = ({
|
||||||
|
notification,
|
||||||
|
onPress,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
activeOpacity={0.8}
|
||||||
|
onPress={() => onPress?.(notification.id)}
|
||||||
|
style={styles.touchable}
|
||||||
|
>
|
||||||
|
<Card style={styles.cardOverride}>
|
||||||
|
{/* Left Icon Container with Soft Colored Background */}
|
||||||
|
<View style={[styles.iconContainer, { backgroundColor: notification.iconBgColor }]}>
|
||||||
|
<Ionicons
|
||||||
|
name={notification.iconName}
|
||||||
|
size={20}
|
||||||
|
color={notification.iconColor}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Text Content */}
|
||||||
|
<View style={styles.content}>
|
||||||
|
<Text style={styles.title} numberOfLines={1}>
|
||||||
|
{notification.title}
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.subtitle} numberOfLines={1}>
|
||||||
|
{notification.subtitle}
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.time}>{notification.time}</Text>
|
||||||
|
</View>
|
||||||
|
</Card>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
touchable: {
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
cardOverride: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
padding: 14,
|
||||||
|
borderRadius: 16,
|
||||||
|
},
|
||||||
|
iconContainer: {
|
||||||
|
width: 42,
|
||||||
|
height: 42,
|
||||||
|
borderRadius: 12,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
marginRight: 14,
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
color: COLORS.textPrimary,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: '700',
|
||||||
|
marginBottom: 3,
|
||||||
|
},
|
||||||
|
subtitle: {
|
||||||
|
color: COLORS.textSecondary,
|
||||||
|
fontSize: 13,
|
||||||
|
marginBottom: 4,
|
||||||
|
},
|
||||||
|
time: {
|
||||||
|
color: COLORS.textSecondary,
|
||||||
|
fontSize: 12,
|
||||||
|
opacity: 0.8,
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { View } from 'react-native';
|
import { View } from 'react-native';
|
||||||
|
|
||||||
import { styles } from '../styles/cardStyle';
|
import { styles } from '../../styles/cardStyle';
|
||||||
import { CardProps } from '../types/type';
|
import { CardProps } from '../../types/type';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Asset } from "../types/type";
|
import { ModuleItem } from "../components/Module/module";
|
||||||
|
import { AlarmItem, Asset, NotificationItem } from "../types/type";
|
||||||
import { COLORS } from "./color";
|
import { COLORS } from "./color";
|
||||||
|
|
||||||
export const actions = [
|
export const actions = [
|
||||||
@@ -109,3 +110,168 @@ export const SAMPLE_ASSETS: Asset[] = [
|
|||||||
health: 96,
|
health: 96,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const ALARM_DATA: AlarmItem[] = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
severity: 'CRITICAL',
|
||||||
|
title: 'CH-02 compressor trip',
|
||||||
|
details: 'Plant Room B1 · discharge 21.4 bar · load shifted to CH-01',
|
||||||
|
timeAgo: '4m ago',
|
||||||
|
isExpanded: true, // First item active/expanded with buttons
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
severity: 'HIGH',
|
||||||
|
title: 'AHU-03 supply fan overload',
|
||||||
|
details: 'Floor 5 · motor current 14.8 A',
|
||||||
|
timeAgo: '18m ago',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
severity: 'MEDIUM',
|
||||||
|
title: 'P-07 vibration above baseline',
|
||||||
|
details: 'Plant Room B1 · 7.2 mm/s RMS',
|
||||||
|
timeAgo: '41m ago',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
severity: 'MEDIUM',
|
||||||
|
title: 'IAQ CO₂ high — Zone 4A',
|
||||||
|
details: 'Floor 4 · 1,180 ppm',
|
||||||
|
timeAgo: '1h ago',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '5',
|
||||||
|
severity: 'LOW',
|
||||||
|
title: 'Water tank T-02 level low',
|
||||||
|
details: 'Terrace · 34% capacity',
|
||||||
|
timeAgo: '2h ago',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const NOTIFICATIONS_DATA = [
|
||||||
|
{
|
||||||
|
title: 'TODAY',
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
type: 'CRITICAL',
|
||||||
|
title: 'Critical alarm — CH-02 trip',
|
||||||
|
subtitle: 'Plant Room B1 · discharge 21.4 bar',
|
||||||
|
time: '2 min ago',
|
||||||
|
iconName: 'warning-outline',
|
||||||
|
iconColor: COLORS.red,
|
||||||
|
iconBgColor: '#2D1A24',
|
||||||
|
section: 'TODAY',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
type: 'SETPOINT',
|
||||||
|
title: 'Setpoint applied — AHU-01',
|
||||||
|
subtitle: '18.0 °C · via Remote Control',
|
||||||
|
time: '28 min ago',
|
||||||
|
iconName: 'locate-outline',
|
||||||
|
iconColor: COLORS.cyan,
|
||||||
|
iconBgColor: '#122536',
|
||||||
|
section: 'TODAY',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
type: 'AIR_QUALITY',
|
||||||
|
title: 'Air quality — Zone 4A',
|
||||||
|
subtitle: 'CO₂ 1,180 ppm · damper auto-opened',
|
||||||
|
time: '1 h ago',
|
||||||
|
iconName: 'pulse-outline',
|
||||||
|
iconColor: COLORS.cyan,
|
||||||
|
iconBgColor: '#122536',
|
||||||
|
section: 'TODAY',
|
||||||
|
},
|
||||||
|
] as NotificationItem[],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'EARLIER',
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
type: 'SUCCESS',
|
||||||
|
title: 'PPM-1198 completed & synced',
|
||||||
|
subtitle: 'DG-01 monthly · by Suresh K.',
|
||||||
|
time: 'Yesterday · 17:20',
|
||||||
|
iconName: 'checkmark',
|
||||||
|
iconColor: COLORS.green,
|
||||||
|
iconBgColor: '#0F2C2B',
|
||||||
|
section: 'EARLIER',
|
||||||
|
},
|
||||||
|
] as NotificationItem[],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const MODULES_DATA: ModuleItem[] = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
title: 'Equipment',
|
||||||
|
iconName: 'cube-outline',
|
||||||
|
iconColor: COLORS.green,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
title: 'Optix AI',
|
||||||
|
iconName: 'sparkles-outline',
|
||||||
|
iconColor: COLORS.orange,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
title: 'Energy',
|
||||||
|
iconName: 'flash-outline',
|
||||||
|
iconColor: COLORS.orange,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
title: 'Remote Ctrl',
|
||||||
|
iconName: 'locate-outline',
|
||||||
|
iconColor: COLORS.cyan,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '5',
|
||||||
|
title: 'Help Desk',
|
||||||
|
iconName: 'chatbox-outline',
|
||||||
|
iconColor: COLORS.cyan,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '6',
|
||||||
|
title: 'Visitors',
|
||||||
|
iconName: 'person-add-outline',
|
||||||
|
iconColor: COLORS.green,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '7',
|
||||||
|
title: 'Attendance',
|
||||||
|
iconName: 'checkbox-outline',
|
||||||
|
iconColor: COLORS.green,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '8',
|
||||||
|
title: 'Air Quality',
|
||||||
|
iconName: 'pulse-outline',
|
||||||
|
iconColor: COLORS.cyan,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '9',
|
||||||
|
title: 'Alerts',
|
||||||
|
iconName: 'notifications-outline',
|
||||||
|
iconColor: COLORS.orange,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '10',
|
||||||
|
title: 'Offline Sync',
|
||||||
|
iconName: 'sync-outline',
|
||||||
|
iconColor: COLORS.textSecondary,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '11',
|
||||||
|
title: 'Profile',
|
||||||
|
iconName: 'person-outline',
|
||||||
|
iconColor: COLORS.textSecondary,
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -5,57 +5,89 @@ import Ionicons from 'react-native-vector-icons/Ionicons';
|
|||||||
import { styles } from '../styles/BottontabStyle';
|
import { styles } from '../styles/BottontabStyle';
|
||||||
import { COLORS } from '../constants/color';
|
import { COLORS } from '../constants/color';
|
||||||
|
|
||||||
export default function BottomTabBar() {
|
// Define allowed tab names as a TypeScript type
|
||||||
|
export type TabType = 'Home' | 'Assets' | 'Scan' | 'Alarms' | 'More';
|
||||||
|
|
||||||
|
// Interface for component props
|
||||||
|
interface BottomTabBarProps {
|
||||||
|
activeTab: TabType;
|
||||||
|
setActiveTab: (tab: TabType) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function BottomTabBar({ activeTab, setActiveTab }: BottomTabBarProps) {
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
|
|
||||||
{/* Home */}
|
{/* Home */}
|
||||||
<TouchableOpacity style={styles.tab}>
|
<TouchableOpacity
|
||||||
<Ionicons name="home" size={22} color={COLORS.tabActive} />
|
style={styles.tab}
|
||||||
<Text style={[styles.label, { color: COLORS.tabActive }]}>
|
onPress={() => setActiveTab('Home')}
|
||||||
|
>
|
||||||
|
<Ionicons
|
||||||
|
name={activeTab === 'Home' ? "home" : "home-outline"}
|
||||||
|
size={22}
|
||||||
|
color={activeTab === 'Home' ? COLORS.tabActive : COLORS.tabInactive}
|
||||||
|
/>
|
||||||
|
<Text style={[styles.label, { color: activeTab === 'Home' ? COLORS.tabActive : COLORS.tabInactive }]}>
|
||||||
Home
|
Home
|
||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
||||||
{/* Assets */}
|
{/* Assets */}
|
||||||
<TouchableOpacity style={styles.tab}>
|
<TouchableOpacity
|
||||||
<Ionicons name="cube-outline" size={22} color={COLORS.tabInactive} />
|
style={styles.tab}
|
||||||
<Text style={styles.label}>
|
onPress={() => setActiveTab('Assets')}
|
||||||
|
>
|
||||||
|
<Ionicons
|
||||||
|
name={activeTab === 'Assets' ? "cube" : "cube-outline"}
|
||||||
|
size={22}
|
||||||
|
color={activeTab === 'Assets' ? COLORS.tabActive : COLORS.tabInactive}
|
||||||
|
/>
|
||||||
|
<Text style={[styles.label, { color: activeTab === 'Assets' ? COLORS.tabActive : COLORS.tabInactive }]}>
|
||||||
Assets
|
Assets
|
||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
||||||
{/* Scan Button */}
|
{/* Scan Button */}
|
||||||
<View style={styles.scanContainer}>
|
<View style={styles.scanContainer}>
|
||||||
<TouchableOpacity style={styles.scanButton}>
|
<TouchableOpacity
|
||||||
|
style={styles.scanButton}
|
||||||
|
onPress={() => setActiveTab('Scan')}
|
||||||
|
>
|
||||||
<Ionicons name="scan" size={28} color="#000" />
|
<Ionicons name="scan" size={28} color="#000" />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
||||||
<Text style={[styles.label, { color: COLORS.tabActive }]}>
|
<Text style={[styles.label, { color: activeTab === 'Scan' ? COLORS.tabActive : COLORS.tabInactive }]}>
|
||||||
Scan
|
Scan
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Alarms */}
|
{/* Alarms */}
|
||||||
<TouchableOpacity style={styles.tab}>
|
<TouchableOpacity
|
||||||
|
style={styles.tab}
|
||||||
|
onPress={() => setActiveTab('Alarms')}
|
||||||
|
>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="notifications-outline"
|
name={activeTab === 'Alarms' ? "notifications" : "notifications-outline"}
|
||||||
size={22}
|
size={22}
|
||||||
color={COLORS.tabInactive}
|
color={activeTab === 'Alarms' ? COLORS.tabActive : COLORS.tabInactive}
|
||||||
/>
|
/>
|
||||||
<Text style={styles.label}>
|
<Text style={[styles.label, { color: activeTab === 'Alarms' ? COLORS.tabActive : COLORS.tabInactive }]}>
|
||||||
Alarms
|
Alarms
|
||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
||||||
{/* More */}
|
{/* More */}
|
||||||
<TouchableOpacity style={styles.tab}>
|
<TouchableOpacity
|
||||||
|
style={styles.tab}
|
||||||
|
onPress={() => setActiveTab('More')}
|
||||||
|
>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="ellipsis-horizontal"
|
name={activeTab === 'More' ? "ellipsis-horizontal" : "ellipsis-horizontal-outline"}
|
||||||
size={22}
|
size={22}
|
||||||
color={COLORS.tabInactive}
|
color={activeTab === 'More' ? COLORS.tabActive : COLORS.tabInactive}
|
||||||
/>
|
/>
|
||||||
<Text style={styles.label}>
|
<Text style={[styles.label, { color: activeTab === 'More' ? COLORS.tabActive : COLORS.tabInactive }]}>
|
||||||
More
|
More
|
||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|||||||
159
src/screens/AirqualityScreen/airqualityScreen.tsx
Normal file
159
src/screens/AirqualityScreen/airqualityScreen.tsx
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
View,
|
||||||
|
TouchableOpacity,
|
||||||
|
SafeAreaView,
|
||||||
|
ScrollView,
|
||||||
|
StatusBar,
|
||||||
|
} from 'react-native';
|
||||||
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||||
|
import Svg, { Circle, Path, Line } from 'react-native-svg';
|
||||||
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||||
|
import { styles } from '../../styles/Airquality/airqualityScreen';
|
||||||
|
|
||||||
|
|
||||||
|
export default function AirQualityScreen() {
|
||||||
|
return (
|
||||||
|
<SafeAreaProvider style={styles.container}>
|
||||||
|
<StatusBar barStyle="light-content" backgroundColor="#070D18" />
|
||||||
|
<ScrollView
|
||||||
|
contentContainerStyle={styles.scrollContent}
|
||||||
|
showsVerticalScrollIndicator={false}
|
||||||
|
>
|
||||||
|
{/* Top Header */}
|
||||||
|
<View style={styles.header}>
|
||||||
|
<TouchableOpacity style={styles.backButton} activeOpacity={0.7}>
|
||||||
|
<Ionicons name="chevron-back" size={20} color="#FFFFFF" />
|
||||||
|
</TouchableOpacity>
|
||||||
|
<View style={styles.headerTitleContainer}>
|
||||||
|
<Text style={styles.headerTitle}>Air Quality</Text>
|
||||||
|
<Text style={styles.headerSubtitle}>Floor 4 · Zone 4A · live</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Main AQI Banner */}
|
||||||
|
<View style={styles.bannerCard}>
|
||||||
|
{/* Circular Gauge */}
|
||||||
|
<View style={styles.gaugeContainer}>
|
||||||
|
<Svg width={120} height={120} viewBox="0 0 120 120">
|
||||||
|
{/* Gauge Track */}
|
||||||
|
<Circle
|
||||||
|
cx="60"
|
||||||
|
cy="60"
|
||||||
|
r="46"
|
||||||
|
stroke="#1B293E"
|
||||||
|
strokeWidth="10"
|
||||||
|
fill="none"
|
||||||
|
/>
|
||||||
|
{/* Active Progress Arc */}
|
||||||
|
<Circle
|
||||||
|
cx="60"
|
||||||
|
cy="60"
|
||||||
|
r="46"
|
||||||
|
stroke="#F59E0B"
|
||||||
|
strokeWidth="10"
|
||||||
|
fill="none"
|
||||||
|
strokeDasharray="289"
|
||||||
|
strokeDashoffset="75"
|
||||||
|
strokeLinecap="round"
|
||||||
|
transform="rotate(135 60 60)"
|
||||||
|
/>
|
||||||
|
</Svg>
|
||||||
|
<View style={styles.gaugeTextContainer}>
|
||||||
|
<Text style={styles.aqiValue}>78</Text>
|
||||||
|
<Text style={styles.aqiLabel}>AQI</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Banner Description */}
|
||||||
|
<View style={styles.bannerDetails}>
|
||||||
|
<View style={styles.badge}>
|
||||||
|
<Text style={styles.badgeText}>MODERATE</Text>
|
||||||
|
</View>
|
||||||
|
<Text style={styles.bannerDescription}>
|
||||||
|
CO₂ slightly elevated. Fresh-air damper increased to 35% automatically.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Metric Cards Grid */}
|
||||||
|
<View style={styles.grid}>
|
||||||
|
{/* CO2 Metric */}
|
||||||
|
<View style={styles.card}>
|
||||||
|
<Text style={styles.cardTitle}>
|
||||||
|
CO<Text style={styles.subscript}>2</Text>
|
||||||
|
</Text>
|
||||||
|
<View style={styles.valueRow}>
|
||||||
|
<Text style={[styles.cardValue, { color: '#F59E0B' }]}>1,180</Text>
|
||||||
|
<Text style={styles.cardUnit}>ppm</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* PM2.5 Metric */}
|
||||||
|
<View style={styles.card}>
|
||||||
|
<Text style={styles.cardTitle}>PM2.5</Text>
|
||||||
|
<View style={styles.valueRow}>
|
||||||
|
<Text style={[styles.cardValue, { color: '#10B981' }]}>18</Text>
|
||||||
|
<Text style={styles.cardUnit}>μg/m³</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* TVOC Metric */}
|
||||||
|
<View style={styles.card}>
|
||||||
|
<Text style={styles.cardTitle}>TVOC</Text>
|
||||||
|
<View style={styles.valueRow}>
|
||||||
|
<Text style={[styles.cardValue, { color: '#10B981' }]}>0.31</Text>
|
||||||
|
<Text style={styles.cardUnit}>ppm</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Temp / RH Metric */}
|
||||||
|
<View style={styles.card}>
|
||||||
|
<Text style={styles.cardTitle}>Temp / RH</Text>
|
||||||
|
<View style={styles.valueRow}>
|
||||||
|
<Text style={[styles.cardValue, { color: '#FFFFFF' }]}>23.4°</Text>
|
||||||
|
<Text style={styles.secondaryValue}> · 52%</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Chart Section */}
|
||||||
|
<View style={styles.chartCard}>
|
||||||
|
<View style={styles.chartHeader}>
|
||||||
|
<Text style={styles.chartTitle}>
|
||||||
|
CO<Text style={styles.subscript}>2</Text> · LAST 12H
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.chartSubtitle}>peak 1,240 · 14:00</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.chartContainer}>
|
||||||
|
<Svg width="100%" height={70} viewBox="0 0 300 70">
|
||||||
|
{/* Threshold Line */}
|
||||||
|
<Line
|
||||||
|
x1="0"
|
||||||
|
y1="35"
|
||||||
|
x2="300"
|
||||||
|
y2="35"
|
||||||
|
stroke="#B91C1C"
|
||||||
|
strokeDasharray="4, 4"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
opacity={0.6}
|
||||||
|
/>
|
||||||
|
{/* Trend Line */}
|
||||||
|
<Path
|
||||||
|
d="M 0 55 Q 60 50 120 40 T 240 48 L 300 42"
|
||||||
|
fill="none"
|
||||||
|
stroke="#F59E0B"
|
||||||
|
strokeWidth="3.5"
|
||||||
|
strokeLinecap="round"
|
||||||
|
/>
|
||||||
|
</Svg>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
</SafeAreaProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
50
src/screens/AlarmScreen/alarmScreen.tsx
Normal file
50
src/screens/AlarmScreen/alarmScreen.tsx
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import {
|
||||||
|
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
FlatList,
|
||||||
|
StyleSheet,
|
||||||
|
StatusBar,
|
||||||
|
} from 'react-native';
|
||||||
|
import { AlarmItem } from '../../types/type';
|
||||||
|
import { ALARM_DATA } from '../../constants/data';
|
||||||
|
import AlarmCard from '../../components/Alarm/alarmCard';
|
||||||
|
import { COLORS } from '../../constants/color';
|
||||||
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||||
|
import { styles } from '../../styles/Alarm/alarmScreen';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default function AlarmsScreen() {
|
||||||
|
const [alarms, setAlarms] = useState<AlarmItem[]>(ALARM_DATA);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SafeAreaProvider style={{ flex: 1, backgroundColor: COLORS.background }}>
|
||||||
|
<StatusBar barStyle="light-content" backgroundColor={COLORS.background} />
|
||||||
|
|
||||||
|
<FlatList
|
||||||
|
data={alarms}
|
||||||
|
keyExtractor={(item) => item.id}
|
||||||
|
renderItem={({ item }) => (
|
||||||
|
<AlarmCard
|
||||||
|
alarm={item}
|
||||||
|
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
ListHeaderComponent={
|
||||||
|
<View style={styles.header}>
|
||||||
|
<Text style={styles.title}>Alarms</Text>
|
||||||
|
<Text style={styles.subtitle}>Live event stream</Text>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
contentContainerStyle={styles.listContent}
|
||||||
|
showsVerticalScrollIndicator={false}
|
||||||
|
/>
|
||||||
|
</SafeAreaProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -10,11 +10,12 @@ import {
|
|||||||
import { SAMPLE_ASSETS } from '../../constants/data';
|
import { SAMPLE_ASSETS } from '../../constants/data';
|
||||||
import { COLORS } from '../../constants/color';
|
import { COLORS } from '../../constants/color';
|
||||||
import { } from '../../types/type';
|
import { } from '../../types/type';
|
||||||
import { SearchBar } from '../../components/searchbar';
|
import { SearchBar } from '../../components/Asset/searchbar';
|
||||||
import { AssetCard } from '../../components/assetCard';
|
import { AssetCard } from '../../components/Asset/assetCard';
|
||||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||||
import BottomTabBar from '../../navigation/bottonTabBar';
|
import BottomTabBar from '../../navigation/bottonTabBar';
|
||||||
import { ScrollView } from 'react-native';
|
import { ScrollView } from 'react-native';
|
||||||
|
import { styles } from '../../styles/Asset/assetScreen';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -29,9 +30,10 @@ export default function AssetsScreen() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaProvider style={{ flex: 1, backgroundColor: COLORS.background }}>
|
<SafeAreaProvider style={{ flex: 1, backgroundColor: COLORS.background }}>
|
||||||
<ScrollView>
|
|
||||||
<StatusBar barStyle="light-content" backgroundColor={COLORS.background} />
|
<StatusBar barStyle="light-content" backgroundColor={COLORS.background} />
|
||||||
<View style={styles.content}>
|
<View style={styles.content}>
|
||||||
|
|
||||||
{/* Header Section */}
|
{/* Header Section */}
|
||||||
<Text style={styles.title}>Assets</Text>
|
<Text style={styles.title}>Assets</Text>
|
||||||
<Text style={styles.subtitle}>251 assets · 242 online</Text>
|
<Text style={styles.subtitle}>251 assets · 242 online</Text>
|
||||||
@@ -46,32 +48,11 @@ export default function AssetsScreen() {
|
|||||||
renderItem={({ item }) => <AssetCard asset={item} />}
|
renderItem={({ item }) => <AssetCard asset={item} />}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
|
||||||
<BottomTabBar />
|
|
||||||
</SafeAreaProvider>
|
</SafeAreaProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
backgroundColor: COLORS.background,
|
|
||||||
},
|
|
||||||
content: {
|
|
||||||
flex: 1,
|
|
||||||
paddingHorizontal: 20,
|
|
||||||
paddingTop: 16,
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
color: COLORS.textPrimary,
|
|
||||||
fontSize: 28,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
},
|
|
||||||
subtitle: {
|
|
||||||
color: COLORS.textSecondary,
|
|
||||||
fontSize: 14,
|
|
||||||
marginTop: 4,
|
|
||||||
marginBottom: 16,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { View, StyleSheet, ScrollView,Text } from 'react-native';
|
import { View, ScrollView,Text } from 'react-native';
|
||||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||||
|
|
||||||
import { cards } from '../../constants/data';
|
import { cards } from '../../constants/data';
|
||||||
import { COLORS } from '../../constants/color';
|
import { COLORS } from '../../constants/color';
|
||||||
import Header from '../../components/header';
|
import Header from '../../components/Home/header';
|
||||||
import SiteHealthCard from '../../components/siteHealthCard';
|
import SiteHealthCard from '../../components/Home/siteHealthCard';
|
||||||
import ActionGrid from '../../components/actionGrid';
|
import ActionGrid from '../../components/Home/actionGrid';
|
||||||
import StatCard from '../../components/statCard';
|
import StatCard from '../../components/Home/statCard';
|
||||||
import BottomTabBar from '../../navigation/bottonTabBar';
|
import Card from '../../components/common/card';
|
||||||
import Card from '../../utils/card';
|
|
||||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||||
|
import styles from '../../styles/Home/homeScreen';
|
||||||
|
|
||||||
export default function HomeScreen() {
|
export default function HomeScreen() {
|
||||||
return (
|
return (
|
||||||
@@ -92,7 +92,7 @@ export default function HomeScreen() {
|
|||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
<BottomTabBar />
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -103,60 +103,4 @@ export default function HomeScreen() {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
backgroundColor: COLORS.background,
|
|
||||||
},
|
|
||||||
scrollContent: {
|
|
||||||
paddingHorizontal: 16,
|
|
||||||
paddingTop: 16,
|
|
||||||
paddingBottom: 20,
|
|
||||||
},
|
|
||||||
gridRow: {
|
|
||||||
|
|
||||||
flexDirection: 'row',
|
|
||||||
flexGrow:1,
|
|
||||||
|
|
||||||
marginBottom: 8,
|
|
||||||
gap:10
|
|
||||||
},
|
|
||||||
card: {
|
|
||||||
|
|
||||||
borderColor: COLORS.orange,
|
|
||||||
|
|
||||||
marginHorizontal: 10,
|
|
||||||
|
|
||||||
marginTop: 10,
|
|
||||||
|
|
||||||
marginBottom: 20,
|
|
||||||
},
|
|
||||||
|
|
||||||
header: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
|
|
||||||
alignItems: 'center',
|
|
||||||
|
|
||||||
marginBottom: 10,
|
|
||||||
},
|
|
||||||
|
|
||||||
title: {
|
|
||||||
color: COLORS.orange,
|
|
||||||
|
|
||||||
fontSize: 18,
|
|
||||||
|
|
||||||
fontWeight: 'bold',
|
|
||||||
|
|
||||||
marginLeft: 8,
|
|
||||||
},
|
|
||||||
|
|
||||||
message: {
|
|
||||||
color: COLORS.textPrimary,
|
|
||||||
|
|
||||||
fontSize: 16,
|
|
||||||
|
|
||||||
lineHeight: 24,
|
|
||||||
|
|
||||||
marginLeft: 20,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|||||||
48
src/screens/ModuleScreen/moduleScreen.tsx
Normal file
48
src/screens/ModuleScreen/moduleScreen.tsx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
SafeAreaView,
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
ScrollView,
|
||||||
|
StyleSheet,
|
||||||
|
StatusBar,
|
||||||
|
} from 'react-native';
|
||||||
|
import { COLORS } from '../../constants/color';
|
||||||
|
import { ModuleTile } from '../../components/Module/module';
|
||||||
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||||
|
import { MODULES_DATA } from '../../constants/data';
|
||||||
|
import styles from '../../styles/Module/module';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default function ModulesScreen() {
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SafeAreaProvider style={{ flex: 1, backgroundColor: COLORS.background }}>
|
||||||
|
|
||||||
|
<StatusBar barStyle="light-content" backgroundColor={COLORS.background} />
|
||||||
|
|
||||||
|
<ScrollView contentContainerStyle={styles.scrollContent} showsVerticalScrollIndicator={false}>
|
||||||
|
{/* Header Title & Subtitle */}
|
||||||
|
<View style={styles.header}>
|
||||||
|
<Text style={styles.title}>All modules</Text>
|
||||||
|
<Text style={styles.subtitle}>Facility Management & IoT platform</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 3-Column Grid Container */}
|
||||||
|
<View style={styles.gridContainer}>
|
||||||
|
{MODULES_DATA.map((item) => (
|
||||||
|
<ModuleTile
|
||||||
|
key={item.id}
|
||||||
|
module={item}
|
||||||
|
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
</SafeAreaProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
64
src/screens/Notification/notification.tsx
Normal file
64
src/screens/Notification/notification.tsx
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import {
|
||||||
|
SafeAreaView,
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
SectionList,
|
||||||
|
TouchableOpacity,
|
||||||
|
StyleSheet,
|
||||||
|
StatusBar,
|
||||||
|
} from 'react-native';
|
||||||
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||||
|
import { COLORS } from '../../constants/color';
|
||||||
|
import { NOTIFICATIONS_DATA } from '../../constants/data';
|
||||||
|
import { NotificationCard } from '../../components/Notification/notificationcard';
|
||||||
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||||
|
import { styles } from '../../styles/Notification/notification';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default function NotificationsScreen({ navigation }: any) {
|
||||||
|
const [sections, setSections] = useState(NOTIFICATIONS_DATA);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const handleBackPress = () => {
|
||||||
|
if (navigation) {
|
||||||
|
navigation.goBack();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SafeAreaProvider style={styles.container}>
|
||||||
|
<StatusBar barStyle="light-content" backgroundColor={COLORS.background} />
|
||||||
|
|
||||||
|
{/* Header Bar */}
|
||||||
|
<View style={styles.headerRow}>
|
||||||
|
<TouchableOpacity style={styles.backButton} onPress={handleBackPress}>
|
||||||
|
<Ionicons name="chevron-back" size={20} color={COLORS.textPrimary} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
<Text style={styles.headerTitle}>Notifications</Text>
|
||||||
|
|
||||||
|
<TouchableOpacity >
|
||||||
|
<Text style={styles.markAllReadText}>Mark all read</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Grouped Notifications List */}
|
||||||
|
<SectionList
|
||||||
|
sections={sections}
|
||||||
|
keyExtractor={(item) => item.id}
|
||||||
|
renderItem={({ item }) => <NotificationCard notification={item} />}
|
||||||
|
renderSectionHeader={({ section: { title } }) => (
|
||||||
|
<Text style={styles.sectionHeader}>{title}</Text>
|
||||||
|
)}
|
||||||
|
contentContainerStyle={styles.listContent}
|
||||||
|
showsVerticalScrollIndicator={false}
|
||||||
|
stickySectionHeadersEnabled={false}
|
||||||
|
/>
|
||||||
|
</SafeAreaProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
125
src/screens/ProfileScreen/profilescreen.tsx
Normal file
125
src/screens/ProfileScreen/profilescreen.tsx
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import {
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
View,
|
||||||
|
TouchableOpacity,
|
||||||
|
Switch,
|
||||||
|
ScrollView,
|
||||||
|
StatusBar,
|
||||||
|
} from 'react-native';
|
||||||
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||||
|
import { styles } from '../../styles/Profile/profile';
|
||||||
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||||
|
|
||||||
|
export default function ProfileScreen() {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SafeAreaProvider style={styles.container}>
|
||||||
|
<StatusBar barStyle="light-content" backgroundColor="#0A111E" />
|
||||||
|
<ScrollView contentContainerStyle={styles.scrollContent} showsVerticalScrollIndicator={false}>
|
||||||
|
|
||||||
|
{/* Header */}
|
||||||
|
<View style={styles.header}>
|
||||||
|
<TouchableOpacity style={styles.backButton} activeOpacity={0.7}>
|
||||||
|
<Ionicons name="chevron-back" size={20} color="#FFFFFF" />
|
||||||
|
</TouchableOpacity>
|
||||||
|
<Text style={styles.headerTitle}>Profile</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Profile Card Info */}
|
||||||
|
<View style={styles.profileContainer}>
|
||||||
|
<View style={styles.avatar}>
|
||||||
|
<Text style={styles.avatarText}>AM</Text>
|
||||||
|
</View>
|
||||||
|
<View style={styles.userInfo}>
|
||||||
|
<Text style={styles.userName}>Arjun Mehta</Text>
|
||||||
|
<Text style={styles.userRole}>Facility Engineer · Shift A</Text>
|
||||||
|
<Text style={styles.userLocation}>Godrej One — Vikhroli</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Metrics/Stats Row */}
|
||||||
|
<View style={styles.statsRow}>
|
||||||
|
<View style={styles.statCard}>
|
||||||
|
<Text style={[styles.statValue, { color: '#FFFFFF' }]}>128</Text>
|
||||||
|
<Text style={styles.statLabel}>WOs closed</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.statCard}>
|
||||||
|
<Text style={[styles.statValue, { color: '#10B981' }]}>96%</Text>
|
||||||
|
<Text style={styles.statLabel}>PPM on-time</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.statCard}>
|
||||||
|
<Text style={[styles.statValue, { color: '#F97316' }]}>4.8</Text>
|
||||||
|
<Text style={styles.statLabel}>Rating</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Options Menu Container */}
|
||||||
|
<View style={styles.menuContainer}>
|
||||||
|
{/* Push Notifications */}
|
||||||
|
<View style={styles.menuItem}>
|
||||||
|
<View style={styles.menuLeft}>
|
||||||
|
<Ionicons name="notifications-outline" size={22} color="#60A5FA" />
|
||||||
|
<Text style={styles.menuText}>Push notifications</Text>
|
||||||
|
</View>
|
||||||
|
<Switch
|
||||||
|
|
||||||
|
trackColor={{ false: '#374151', true: '#10B981' }}
|
||||||
|
thumbColor="#0F172A"
|
||||||
|
ios_backgroundColor="#374151"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.divider} />
|
||||||
|
|
||||||
|
{/* Biometric Login */}
|
||||||
|
<View style={styles.menuItem}>
|
||||||
|
<View style={styles.menuLeft}>
|
||||||
|
<Ionicons name="lock-closed-outline" size={22} color="#38BDF8" />
|
||||||
|
<Text style={styles.menuText}>Biometric login</Text>
|
||||||
|
</View>
|
||||||
|
<Switch
|
||||||
|
|
||||||
|
trackColor={{ false: '#374151', true: '#10B981' }}
|
||||||
|
thumbColor="#0F172A"
|
||||||
|
ios_backgroundColor="#374151"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.divider} />
|
||||||
|
|
||||||
|
{/* Offline Sync */}
|
||||||
|
<TouchableOpacity style={styles.menuItem} activeOpacity={0.7}>
|
||||||
|
<View style={styles.menuLeft}>
|
||||||
|
<Ionicons name="refresh-outline" size={22} color="#34D399" />
|
||||||
|
<Text style={styles.menuText}>Offline sync</Text>
|
||||||
|
</View>
|
||||||
|
<Text style={styles.menuSubtext}>Wi-Fi only</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
<View style={styles.divider} />
|
||||||
|
|
||||||
|
{/* Help & Support */}
|
||||||
|
<TouchableOpacity style={styles.menuItem} activeOpacity={0.7}>
|
||||||
|
<View style={styles.menuLeft}>
|
||||||
|
<Ionicons name="alert-circle-outline" size={22} color="#9CA3AF" />
|
||||||
|
<Text style={styles.menuText}>Help & support</Text>
|
||||||
|
</View>
|
||||||
|
<Ionicons name="chevron-forward" size={18} color="#6B7280" />
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Sign Out Button */}
|
||||||
|
<TouchableOpacity style={styles.signOutButton} activeOpacity={0.8}>
|
||||||
|
<Ionicons name="log-out-outline" size={20} color="#EF4444" />
|
||||||
|
<Text style={styles.signOutText}>Sign out</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
</SafeAreaProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
164
src/styles/Airquality/airqualityScreen.ts
Normal file
164
src/styles/Airquality/airqualityScreen.ts
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
import { StyleSheet } from "react-native";
|
||||||
|
|
||||||
|
export const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: '#070D18',
|
||||||
|
},
|
||||||
|
scrollContent: {
|
||||||
|
paddingHorizontal: 18,
|
||||||
|
paddingTop: 12,
|
||||||
|
paddingBottom: 24,
|
||||||
|
},
|
||||||
|
/* Header */
|
||||||
|
header: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: 20,
|
||||||
|
},
|
||||||
|
backButton: {
|
||||||
|
width: 42,
|
||||||
|
height: 42,
|
||||||
|
borderRadius: 12,
|
||||||
|
backgroundColor: '#152134',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginRight: 16,
|
||||||
|
},
|
||||||
|
headerTitleContainer: {
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
headerTitle: {
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: '700',
|
||||||
|
color: '#FFFFFF',
|
||||||
|
},
|
||||||
|
headerSubtitle: {
|
||||||
|
fontSize: 13,
|
||||||
|
color: '#64748B',
|
||||||
|
marginTop: 2,
|
||||||
|
},
|
||||||
|
/* Banner Card */
|
||||||
|
bannerCard: {
|
||||||
|
backgroundColor: '#152134',
|
||||||
|
borderRadius: 20,
|
||||||
|
padding: 20,
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
gaugeContainer: {
|
||||||
|
width: 110,
|
||||||
|
height: 110,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
gaugeTextContainer: {
|
||||||
|
position: 'absolute',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
aqiValue: {
|
||||||
|
fontSize: 32,
|
||||||
|
fontWeight: '800',
|
||||||
|
color: '#FFFFFF',
|
||||||
|
lineHeight: 34,
|
||||||
|
},
|
||||||
|
aqiLabel: {
|
||||||
|
fontSize: 11,
|
||||||
|
fontWeight: '600',
|
||||||
|
color: '#64748B',
|
||||||
|
marginTop: 2,
|
||||||
|
},
|
||||||
|
bannerDetails: {
|
||||||
|
flex: 1,
|
||||||
|
marginLeft: 12,
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
},
|
||||||
|
badge: {
|
||||||
|
backgroundColor: 'rgba(245, 158, 11, 0.15)',
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
paddingVertical: 5,
|
||||||
|
borderRadius: 8,
|
||||||
|
marginBottom: 10,
|
||||||
|
},
|
||||||
|
badgeText: {
|
||||||
|
color: '#F59E0B',
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: '700',
|
||||||
|
letterSpacing: 0.5,
|
||||||
|
},
|
||||||
|
bannerDescription: {
|
||||||
|
color: '#94A3B8',
|
||||||
|
fontSize: 13.5,
|
||||||
|
lineHeight: 20,
|
||||||
|
fontWeight: '400',
|
||||||
|
},
|
||||||
|
/* Grid Cards */
|
||||||
|
grid: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
gap: 12,
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
card: {
|
||||||
|
width: '48.2%',
|
||||||
|
backgroundColor: '#152134',
|
||||||
|
borderRadius: 16,
|
||||||
|
padding: 16,
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
height: 100,
|
||||||
|
},
|
||||||
|
cardTitle: {
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: '600',
|
||||||
|
color: '#8E9BAE',
|
||||||
|
},
|
||||||
|
subscript: {
|
||||||
|
fontSize: 10,
|
||||||
|
},
|
||||||
|
valueRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'baseline',
|
||||||
|
},
|
||||||
|
cardValue: {
|
||||||
|
fontSize: 26,
|
||||||
|
fontWeight: '700',
|
||||||
|
},
|
||||||
|
cardUnit: {
|
||||||
|
fontSize: 13,
|
||||||
|
color: '#64748B',
|
||||||
|
marginLeft: 6,
|
||||||
|
fontWeight: '500',
|
||||||
|
},
|
||||||
|
secondaryValue: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#64748B',
|
||||||
|
fontWeight: '500',
|
||||||
|
},
|
||||||
|
/* Chart Card */
|
||||||
|
chartCard: {
|
||||||
|
backgroundColor: '#152134',
|
||||||
|
borderRadius: 20,
|
||||||
|
padding: 20,
|
||||||
|
},
|
||||||
|
chartHeader: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
chartTitle: {
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: '700',
|
||||||
|
color: '#8E9BAE',
|
||||||
|
letterSpacing: 0.5,
|
||||||
|
},
|
||||||
|
chartSubtitle: {
|
||||||
|
fontSize: 13,
|
||||||
|
color: '#64748B',
|
||||||
|
},
|
||||||
|
chartContainer: {
|
||||||
|
height: 70,
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
});
|
||||||
27
src/styles/Alarm/alarmScreen.ts
Normal file
27
src/styles/Alarm/alarmScreen.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { StyleSheet } from "react-native";
|
||||||
|
import { COLORS } from "../../constants/color";
|
||||||
|
|
||||||
|
export const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: COLORS.background,
|
||||||
|
},
|
||||||
|
listContent: {
|
||||||
|
paddingHorizontal: 18,
|
||||||
|
paddingBottom: 24,
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
paddingTop: 16,
|
||||||
|
paddingBottom: 16,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
color: COLORS.textPrimary,
|
||||||
|
fontSize: 28,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
subtitle: {
|
||||||
|
color: COLORS.textSecondary,
|
||||||
|
fontSize: 14,
|
||||||
|
marginTop: 4,
|
||||||
|
},
|
||||||
|
});
|
||||||
111
src/styles/Alarm/alarmcard.ts
Normal file
111
src/styles/Alarm/alarmcard.ts
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
import { COLORS } from '../../constants/color';
|
||||||
|
|
||||||
|
export const styles = StyleSheet.create({
|
||||||
|
card: {
|
||||||
|
backgroundColor: COLORS.cardBg,
|
||||||
|
borderColor: COLORS.cardBorder,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderRadius: 16,
|
||||||
|
marginBottom: 12,
|
||||||
|
flexDirection: 'row',
|
||||||
|
overflow: 'hidden',
|
||||||
|
},
|
||||||
|
|
||||||
|
statusIndicator: {
|
||||||
|
width: 5,
|
||||||
|
borderTopLeftRadius: 16,
|
||||||
|
borderBottomLeftRadius: 16,
|
||||||
|
},
|
||||||
|
|
||||||
|
cardContent: {
|
||||||
|
flex: 1,
|
||||||
|
padding: 16,
|
||||||
|
},
|
||||||
|
|
||||||
|
headerRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
|
||||||
|
badge: {
|
||||||
|
paddingHorizontal: 8,
|
||||||
|
paddingVertical: 3,
|
||||||
|
borderRadius: 6,
|
||||||
|
},
|
||||||
|
|
||||||
|
badgeText: {
|
||||||
|
fontSize: 11,
|
||||||
|
fontWeight: '800',
|
||||||
|
letterSpacing: 0.5,
|
||||||
|
},
|
||||||
|
|
||||||
|
timeAgo: {
|
||||||
|
color: COLORS.textSecondary,
|
||||||
|
fontSize: 13,
|
||||||
|
},
|
||||||
|
|
||||||
|
title: {
|
||||||
|
color: COLORS.textPrimary,
|
||||||
|
fontSize: 17,
|
||||||
|
fontWeight: '700',
|
||||||
|
marginBottom: 6,
|
||||||
|
},
|
||||||
|
|
||||||
|
details: {
|
||||||
|
color: COLORS.textSecondary,
|
||||||
|
fontSize: 14,
|
||||||
|
lineHeight: 20,
|
||||||
|
},
|
||||||
|
|
||||||
|
actionRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginTop: 16,
|
||||||
|
gap: 10,
|
||||||
|
},
|
||||||
|
|
||||||
|
acknowledgeButton: {
|
||||||
|
backgroundColor: COLORS.tabActive,
|
||||||
|
paddingVertical: 10,
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
borderRadius: 10,
|
||||||
|
flex: 1,
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
|
||||||
|
acknowledgeText: {
|
||||||
|
color: '#000',
|
||||||
|
fontWeight: '700',
|
||||||
|
fontSize: 14,
|
||||||
|
},
|
||||||
|
|
||||||
|
assignButton: {
|
||||||
|
backgroundColor: '#1E2D42',
|
||||||
|
borderColor: COLORS.cardBorder,
|
||||||
|
borderWidth: 1,
|
||||||
|
paddingVertical: 10,
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
borderRadius: 10,
|
||||||
|
flex: 1,
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
|
||||||
|
assignText: {
|
||||||
|
color: COLORS.textPrimary,
|
||||||
|
fontWeight: '600',
|
||||||
|
fontSize: 14,
|
||||||
|
},
|
||||||
|
|
||||||
|
iconButton: {
|
||||||
|
backgroundColor: '#1E2D42',
|
||||||
|
borderColor: COLORS.cardBorder,
|
||||||
|
borderWidth: 1,
|
||||||
|
padding: 10,
|
||||||
|
borderRadius: 10,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { StyleSheet } from "react-native";
|
import { StyleSheet } from "react-native";
|
||||||
import { COLORS } from "../constants/color";
|
import { COLORS } from "../../constants/color";
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
export const styles = StyleSheet.create({
|
||||||
card: {
|
card: {
|
||||||
25
src/styles/Asset/assetScreen.ts
Normal file
25
src/styles/Asset/assetScreen.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { StyleSheet } from "react-native";
|
||||||
|
import { COLORS } from "../../constants/color";
|
||||||
|
|
||||||
|
export const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: COLORS.background,
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
flex: 1,
|
||||||
|
paddingHorizontal: 20,
|
||||||
|
paddingTop: 16,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
color: COLORS.textPrimary,
|
||||||
|
fontSize: 28,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
subtitle: {
|
||||||
|
color: COLORS.textSecondary,
|
||||||
|
fontSize: 14,
|
||||||
|
marginTop: 4,
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { StyleSheet } from 'react-native';
|
import { StyleSheet } from 'react-native';
|
||||||
import { COLORS } from '../constants/color';
|
import { COLORS } from '../../constants/color';
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
export const styles = StyleSheet.create({
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { StyleSheet } from 'react-native';
|
import { StyleSheet } from 'react-native';
|
||||||
import { COLORS } from '../constants/color';
|
import { COLORS } from '../../constants/color';
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
export const styles = StyleSheet.create({
|
||||||
|
|
||||||
53
src/styles/Home/HomeScreen.ts
Normal file
53
src/styles/Home/HomeScreen.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// HomeScreen.styles.js
|
||||||
|
|
||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
import { COLORS } from '../../constants/color';
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: COLORS.background,
|
||||||
|
},
|
||||||
|
|
||||||
|
scrollContent: {
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
paddingTop: 16,
|
||||||
|
paddingBottom: 20,
|
||||||
|
},
|
||||||
|
|
||||||
|
gridRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
flexGrow: 1,
|
||||||
|
marginBottom: 8,
|
||||||
|
gap: 10,
|
||||||
|
},
|
||||||
|
|
||||||
|
card: {
|
||||||
|
borderColor: COLORS.orange,
|
||||||
|
marginHorizontal: 10,
|
||||||
|
marginTop: 10,
|
||||||
|
marginBottom: 20,
|
||||||
|
},
|
||||||
|
|
||||||
|
header: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: 10,
|
||||||
|
},
|
||||||
|
|
||||||
|
title: {
|
||||||
|
color: COLORS.orange,
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginLeft: 8,
|
||||||
|
},
|
||||||
|
|
||||||
|
message: {
|
||||||
|
color: COLORS.textPrimary,
|
||||||
|
fontSize: 16,
|
||||||
|
lineHeight: 24,
|
||||||
|
marginLeft: 20,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default styles;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { StyleSheet } from "react-native";
|
import { StyleSheet } from "react-native";
|
||||||
import { COLORS } from "../constants/color";
|
import { COLORS } from "../../constants/color";
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
export const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { StyleSheet } from 'react-native';
|
import { StyleSheet } from 'react-native';
|
||||||
import { COLORS } from '../constants/color';
|
import { COLORS } from '../../constants/color';
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
export const styles = StyleSheet.create({
|
||||||
|
|
||||||
38
src/styles/Module/module.ts
Normal file
38
src/styles/Module/module.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { StyleSheet, Platform, StatusBar } from 'react-native';
|
||||||
|
import { COLORS } from '../../constants/color';
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: COLORS.background,
|
||||||
|
},
|
||||||
|
scrollContent: {
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
// Extra top padding ensures content clears notch and status bar
|
||||||
|
paddingTop: Platform.OS === 'android' ? (StatusBar.currentHeight || 20) + 16 : 24,
|
||||||
|
paddingBottom: 100, // Safe distance from bottom tab bar
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
marginTop: 12, // Pushes header down away from top screen edge/time
|
||||||
|
marginBottom: 20,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
color: COLORS.textPrimary,
|
||||||
|
fontSize: 26,
|
||||||
|
fontWeight: '700',
|
||||||
|
letterSpacing: 0.3,
|
||||||
|
},
|
||||||
|
subtitle: {
|
||||||
|
color: COLORS.textSecondary,
|
||||||
|
fontSize: 14,
|
||||||
|
marginTop: 4,
|
||||||
|
},
|
||||||
|
gridContainer: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
justifyContent: 'flex-start',
|
||||||
|
gap: 12,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default styles;
|
||||||
50
src/styles/Notification/notification.ts
Normal file
50
src/styles/Notification/notification.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { StyleSheet } from "react-native";
|
||||||
|
import { COLORS } from "../../constants/color";
|
||||||
|
|
||||||
|
export const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: COLORS.background,
|
||||||
|
},
|
||||||
|
headerRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
paddingVertical: 14,
|
||||||
|
},
|
||||||
|
backButton: {
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
borderRadius: 12,
|
||||||
|
backgroundColor: COLORS.cardBg,
|
||||||
|
borderColor: COLORS.cardBorder,
|
||||||
|
borderWidth: 1,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
headerTitle: {
|
||||||
|
color: COLORS.textPrimary,
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: '700',
|
||||||
|
flex: 1,
|
||||||
|
marginLeft: 14,
|
||||||
|
},
|
||||||
|
markAllReadText: {
|
||||||
|
color: COLORS.orange,
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: '600',
|
||||||
|
},
|
||||||
|
listContent: {
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
paddingBottom: 24,
|
||||||
|
},
|
||||||
|
sectionHeader: {
|
||||||
|
color: COLORS.textSecondary,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: '700',
|
||||||
|
letterSpacing: 0.8,
|
||||||
|
marginTop: 18,
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
});
|
||||||
147
src/styles/Profile/profile.ts
Normal file
147
src/styles/Profile/profile.ts
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
import { StyleSheet } from "react-native";
|
||||||
|
|
||||||
|
export const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: '#0A111E',
|
||||||
|
},
|
||||||
|
scrollContent: {
|
||||||
|
paddingHorizontal: 20,
|
||||||
|
paddingTop: 16,
|
||||||
|
paddingBottom: 40,
|
||||||
|
},
|
||||||
|
/* Header */
|
||||||
|
header: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: 24,
|
||||||
|
},
|
||||||
|
backButton: {
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
borderRadius: 12,
|
||||||
|
backgroundColor: '#162235',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginRight: 16,
|
||||||
|
},
|
||||||
|
headerTitle: {
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: '700',
|
||||||
|
color: '#FFFFFF',
|
||||||
|
},
|
||||||
|
/* User Profile Header */
|
||||||
|
profileContainer: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: 24,
|
||||||
|
},
|
||||||
|
avatar: {
|
||||||
|
width: 64,
|
||||||
|
height: 64,
|
||||||
|
borderRadius: 18,
|
||||||
|
backgroundColor: '#D97706',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginRight: 16,
|
||||||
|
},
|
||||||
|
avatarText: {
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: '700',
|
||||||
|
color: '#0F172A',
|
||||||
|
},
|
||||||
|
userInfo: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
userName: {
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: '700',
|
||||||
|
color: '#FFFFFF',
|
||||||
|
marginBottom: 2,
|
||||||
|
},
|
||||||
|
userRole: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#94A3B8',
|
||||||
|
marginBottom: 2,
|
||||||
|
},
|
||||||
|
userLocation: {
|
||||||
|
fontSize: 13,
|
||||||
|
color: '#64748B',
|
||||||
|
},
|
||||||
|
/* Stats Cards */
|
||||||
|
statsRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
marginBottom: 24,
|
||||||
|
gap: 12,
|
||||||
|
},
|
||||||
|
statCard: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: '#162235',
|
||||||
|
borderRadius: 16,
|
||||||
|
paddingVertical: 18,
|
||||||
|
paddingHorizontal: 10,
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
statValue: {
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: '700',
|
||||||
|
marginBottom: 4,
|
||||||
|
},
|
||||||
|
statLabel: {
|
||||||
|
fontSize: 12,
|
||||||
|
color: '#64748B',
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
/* Menu Items Section */
|
||||||
|
menuContainer: {
|
||||||
|
backgroundColor: '#162235',
|
||||||
|
borderRadius: 16,
|
||||||
|
paddingVertical: 6,
|
||||||
|
marginBottom: 24,
|
||||||
|
},
|
||||||
|
menuItem: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
paddingVertical: 14,
|
||||||
|
},
|
||||||
|
menuLeft: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 12,
|
||||||
|
},
|
||||||
|
menuText: {
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: '500',
|
||||||
|
color: '#FFFFFF',
|
||||||
|
},
|
||||||
|
menuSubtext: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#64748B',
|
||||||
|
},
|
||||||
|
divider: {
|
||||||
|
height: 1,
|
||||||
|
backgroundColor: '#1E2D4A',
|
||||||
|
marginLeft: 48,
|
||||||
|
},
|
||||||
|
/* Sign Out Button */
|
||||||
|
signOutButton: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
backgroundColor: 'rgba(239, 68, 68, 0.1)',
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: 'rgba(239, 68, 68, 0.3)',
|
||||||
|
borderRadius: 16,
|
||||||
|
paddingVertical: 16,
|
||||||
|
gap: 10,
|
||||||
|
},
|
||||||
|
signOutText: {
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: '600',
|
||||||
|
color: '#EF4444',
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -2,6 +2,7 @@ export interface HeaderProps {
|
|||||||
userName: string;
|
userName: string;
|
||||||
locationName: string;
|
locationName: string;
|
||||||
badgeCount?: number;
|
badgeCount?: number;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StatCardProps {
|
export interface StatCardProps {
|
||||||
@@ -38,3 +39,39 @@ export interface SearchBarProps {
|
|||||||
export interface AssetCardProps {
|
export interface AssetCardProps {
|
||||||
asset: Asset;
|
asset: Asset;
|
||||||
}
|
}
|
||||||
|
export type SeverityLevel = 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW';
|
||||||
|
|
||||||
|
export interface AlarmItem {
|
||||||
|
id: string;
|
||||||
|
severity: SeverityLevel;
|
||||||
|
title: string;
|
||||||
|
details: string;
|
||||||
|
timeAgo: string;
|
||||||
|
isExpanded?: boolean;
|
||||||
|
}
|
||||||
|
export interface AlarmCardProps {
|
||||||
|
alarm: AlarmItem;
|
||||||
|
onAcknowledge?: (id: string) => void;
|
||||||
|
onAssign?: (id: string) => void;
|
||||||
|
onPressDetails?: (id: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NotificationType = 'CRITICAL' | 'SETPOINT' | 'AIR_QUALITY' | 'SUCCESS';
|
||||||
|
|
||||||
|
export interface NotificationItem {
|
||||||
|
id: string;
|
||||||
|
type: NotificationType;
|
||||||
|
title: string;
|
||||||
|
subtitle: string;
|
||||||
|
time: string;
|
||||||
|
iconName: string;
|
||||||
|
iconColor: string;
|
||||||
|
iconBgColor: string;
|
||||||
|
section: 'TODAY' | 'EARLIER';
|
||||||
|
isUnread?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NotificationCardProps {
|
||||||
|
notification: NotificationItem;
|
||||||
|
onPress?: (id: string) => void;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user