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 { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||||
import HomeScreen from './src/screens/HomeScreen/homeScreen';
|
import HomeScreen from './src/screens/HomeScreen/homeScreen';
|
||||||
import { COLORS } from './src/constants/color';
|
import { COLORS } from './src/constants/color';
|
||||||
|
import { AssetCard } from './src/components/assetCard';
|
||||||
|
import AssetScreen from './src/screens/AssetsScreen/assetScreen';
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
return (
|
return (
|
||||||
<SafeAreaProvider>
|
<SafeAreaProvider>
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<StatusBar barStyle="light-content" backgroundColor={COLORS.background} />
|
<StatusBar barStyle="light-content" backgroundColor={COLORS.background} />
|
||||||
<HomeScreen />
|
<AssetScreen />
|
||||||
</View>
|
</View>
|
||||||
</SafeAreaProvider>
|
</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";
|
import { COLORS } from "./color";
|
||||||
|
|
||||||
export const actions = [
|
export const actions = [
|
||||||
@@ -55,3 +56,56 @@ export const cards = [
|
|||||||
icon: "pulse-outline",
|
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;
|
children: React.ReactNode;
|
||||||
style?: object;
|
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