Assets screen is added
This commit is contained in:
4
App.tsx
4
App.tsx
@@ -3,13 +3,15 @@ import { StatusBar, StyleSheet, View } from 'react-native';
|
||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||
import HomeScreen from './src/screens/HomeScreen/homeScreen';
|
||||
import { COLORS } from './src/constants/color';
|
||||
import { AssetCard } from './src/components/assetCard';
|
||||
import AssetScreen from './src/screens/AssetsScreen/assetScreen';
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<SafeAreaProvider>
|
||||
<View style={styles.container}>
|
||||
<StatusBar barStyle="light-content" backgroundColor={COLORS.background} />
|
||||
<HomeScreen />
|
||||
<AssetScreen />
|
||||
</View>
|
||||
</SafeAreaProvider>
|
||||
);
|
||||
|
||||
60
src/components/assetCard.tsx
Normal file
60
src/components/assetCard.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import React from "react";
|
||||
import { View, Text } from "react-native";
|
||||
import { Asset, AssetCardProps } from "../types/type";
|
||||
import { styles } from "../styles/AssetCard";
|
||||
|
||||
|
||||
|
||||
export const AssetCard = ({ asset }: AssetCardProps) => {
|
||||
return (
|
||||
<View style={styles.card}>
|
||||
<View
|
||||
style={[
|
||||
styles.statusIndicator,
|
||||
{ backgroundColor: asset.statusColor },
|
||||
]}
|
||||
/>
|
||||
|
||||
<View style={styles.content}>
|
||||
<View style={styles.headerRow}>
|
||||
<Text style={styles.title}>
|
||||
{asset.name} {asset.type ? `· ${asset.type}` : ""}
|
||||
</Text>
|
||||
|
||||
<View
|
||||
style={[
|
||||
styles.badge,
|
||||
{ backgroundColor: asset.statusColor + "20" },
|
||||
]}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
styles.badgeText,
|
||||
{ color: asset.statusColor },
|
||||
]}
|
||||
>
|
||||
{asset.status}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<Text style={styles.location}>{asset.location}</Text>
|
||||
|
||||
<Text style={styles.metrics}>{asset.metrics}</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.healthContainer}>
|
||||
<Text
|
||||
style={[
|
||||
styles.healthValue,
|
||||
{ color: asset.statusColor },
|
||||
]}
|
||||
>
|
||||
{asset.health}
|
||||
</Text>
|
||||
|
||||
<Text style={styles.healthLabel}>health</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
21
src/components/searchbar.tsx
Normal file
21
src/components/searchbar.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import React from "react";
|
||||
import { View, TextInput } from "react-native";
|
||||
import { COLORS } from "../constants/color";
|
||||
import { styles } from "../styles/SearchbarStyles";
|
||||
import {SearchBarProps} from "../types/type"
|
||||
|
||||
|
||||
|
||||
export const SearchBar = ({ value, onChangeText }: SearchBarProps) => {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Search asset or tag..."
|
||||
placeholderTextColor={COLORS.textSecondary}
|
||||
value={value}
|
||||
onChangeText={onChangeText}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Asset } from "../types/type";
|
||||
import { COLORS } from "./color";
|
||||
|
||||
export const actions = [
|
||||
@@ -55,3 +56,56 @@ export const cards = [
|
||||
icon: "pulse-outline",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
export const SAMPLE_ASSETS: Asset[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'AHU-01',
|
||||
location: 'Floor 3 · East Wing',
|
||||
status: 'RUNNING',
|
||||
statusColor: COLORS.green,
|
||||
metrics: '18.2 °C · 12.3 kW',
|
||||
health: 94,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'CH-02',
|
||||
type: 'Chiller',
|
||||
location: 'Plant Room B1',
|
||||
status: 'FAULT',
|
||||
statusColor: COLORS.red,
|
||||
metrics: '21.4 bar · tripped',
|
||||
health: 41,
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'P-07',
|
||||
type: 'CHW Pump',
|
||||
location: 'Plant Room B1',
|
||||
status: 'ATTENTION',
|
||||
statusColor: COLORS.orange,
|
||||
metrics: '52 Hz · vibration ↑',
|
||||
health: 68,
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
name: 'DG-01',
|
||||
type: 'Genset',
|
||||
location: 'Basement Yard',
|
||||
status: 'STANDBY',
|
||||
statusColor: COLORS.green,
|
||||
metrics: 'fuel 82% · battery OK',
|
||||
health: 91,
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
name: 'LP-03',
|
||||
type: 'LT Panel',
|
||||
location: 'Ground . Utility',
|
||||
status: 'RUNNING',
|
||||
statusColor: COLORS.green,
|
||||
metrics: '412 V · PF 0.97',
|
||||
health: 96,
|
||||
},
|
||||
];
|
||||
77
src/screens/AssetsScreen/assetScreen.tsx
Normal file
77
src/screens/AssetsScreen/assetScreen.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
SafeAreaView,
|
||||
View,
|
||||
Text,
|
||||
FlatList,
|
||||
StyleSheet,
|
||||
StatusBar,
|
||||
} from 'react-native';
|
||||
import { SAMPLE_ASSETS } from '../../constants/data';
|
||||
import { COLORS } from '../../constants/color';
|
||||
import { } from '../../types/type';
|
||||
import { SearchBar } from '../../components/searchbar';
|
||||
import { AssetCard } from '../../components/assetCard';
|
||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||
import BottomTabBar from '../../navigation/bottonTabBar';
|
||||
import { ScrollView } from 'react-native';
|
||||
|
||||
|
||||
|
||||
export default function AssetsScreen() {
|
||||
const [search, setSearch] = useState('');
|
||||
|
||||
const filteredAssets = SAMPLE_ASSETS.filter(
|
||||
(item) =>
|
||||
item.name.toLowerCase().includes(search.toLowerCase()) ||
|
||||
item.location.toLowerCase().includes(search.toLowerCase())
|
||||
);
|
||||
|
||||
return (
|
||||
<SafeAreaProvider style={{ flex: 1, backgroundColor: COLORS.background }}>
|
||||
<ScrollView>
|
||||
<StatusBar barStyle="light-content" backgroundColor={COLORS.background} />
|
||||
<View style={styles.content}>
|
||||
{/* Header Section */}
|
||||
<Text style={styles.title}>Assets</Text>
|
||||
<Text style={styles.subtitle}>251 assets · 242 online</Text>
|
||||
|
||||
{/* Search */}
|
||||
<SearchBar value={search} onChangeText={setSearch} />
|
||||
|
||||
{/* Assets List */}
|
||||
<FlatList
|
||||
data={filteredAssets}
|
||||
keyExtractor={(item) => item.id}
|
||||
renderItem={({ item }) => <AssetCard asset={item} />}
|
||||
showsVerticalScrollIndicator={false}
|
||||
/>
|
||||
</View>
|
||||
</ScrollView>
|
||||
<BottomTabBar />
|
||||
</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,
|
||||
},
|
||||
});
|
||||
80
src/styles/AssetCard.ts
Normal file
80
src/styles/AssetCard.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
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,
|
||||
padding: 16,
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
marginBottom: 12,
|
||||
},
|
||||
|
||||
statusIndicator: {
|
||||
width: 6,
|
||||
height: "100%",
|
||||
borderRadius: 3,
|
||||
marginRight: 12,
|
||||
},
|
||||
|
||||
content: {
|
||||
flex: 1,
|
||||
},
|
||||
|
||||
headerRow: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
|
||||
title: {
|
||||
color: COLORS.textPrimary,
|
||||
fontSize: 18,
|
||||
fontWeight: "700",
|
||||
marginRight: 8,
|
||||
},
|
||||
|
||||
badge: {
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 2,
|
||||
borderRadius: 6,
|
||||
},
|
||||
|
||||
badgeText: {
|
||||
fontSize: 11,
|
||||
fontWeight: "700",
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
|
||||
location: {
|
||||
color: COLORS.textSecondary,
|
||||
fontSize: 14,
|
||||
marginTop: 4,
|
||||
},
|
||||
|
||||
metrics: {
|
||||
color: COLORS.textSecondary,
|
||||
fontSize: 14,
|
||||
marginTop: 6,
|
||||
fontFamily: "monospace",
|
||||
},
|
||||
|
||||
healthContainer: {
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
marginLeft: 8,
|
||||
},
|
||||
|
||||
healthValue: {
|
||||
fontSize: 22,
|
||||
fontWeight: "bold",
|
||||
},
|
||||
|
||||
healthLabel: {
|
||||
color: COLORS.textSecondary,
|
||||
fontSize: 12,
|
||||
},
|
||||
});
|
||||
19
src/styles/SearchbarStyles.ts
Normal file
19
src/styles/SearchbarStyles.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { StyleSheet } from "react-native";
|
||||
import { COLORS } from "../constants/color";
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: COLORS.cardBg,
|
||||
borderColor: COLORS.cardBorder,
|
||||
borderWidth: 1,
|
||||
borderRadius: 12,
|
||||
paddingHorizontal: 16,
|
||||
height: 48,
|
||||
justifyContent: "center",
|
||||
marginBottom: 16,
|
||||
},
|
||||
input: {
|
||||
color: COLORS.textPrimary,
|
||||
fontSize: 16,
|
||||
},
|
||||
});
|
||||
@@ -16,3 +16,25 @@ export interface CardProps {
|
||||
children: React.ReactNode;
|
||||
style?: object;
|
||||
}
|
||||
|
||||
export type AssetStatus = 'RUNNING' | 'FAULT' | 'ATTENTION' | 'STANDBY';
|
||||
|
||||
export interface Asset {
|
||||
id: string;
|
||||
name: string;
|
||||
type?: string;
|
||||
location: string;
|
||||
status: AssetStatus;
|
||||
statusColor: string;
|
||||
metrics: string;
|
||||
health: number;
|
||||
}
|
||||
|
||||
export interface SearchBarProps {
|
||||
value: string;
|
||||
onChangeText: (text: string) => void;
|
||||
}
|
||||
|
||||
export interface AssetCardProps {
|
||||
asset: Asset;
|
||||
}
|
||||
Reference in New Issue
Block a user