255 lines
8.2 KiB
TypeScript
255 lines
8.2 KiB
TypeScript
import React, { useEffect, useState } from "react";
|
|
import {
|
|
View,
|
|
ActivityIndicator,
|
|
ScrollView,
|
|
Image,
|
|
Pressable,
|
|
useColorScheme,
|
|
} from "react-native";
|
|
import { ScreenWrapper } from "@/components/ScreenWrapper";
|
|
import { Text } from "@/components/ui/text";
|
|
import { Card, CardContent } from "@/components/ui/card";
|
|
import {
|
|
ArrowLeft,
|
|
Edit,
|
|
Building2,
|
|
Hash,
|
|
Mail,
|
|
Phone,
|
|
Globe,
|
|
MapPin,
|
|
Calendar,
|
|
} from "@/lib/icons";
|
|
import { useSirouRouter } from "@sirou/react-native";
|
|
import { AppRoutes } from "@/lib/routes";
|
|
import { api } from "@/lib/api";
|
|
|
|
export default function CompanyDetailsScreen() {
|
|
const nav = useSirouRouter<AppRoutes>();
|
|
const isDark = useColorScheme() === "dark";
|
|
const iconCol = isDark ? "#94a3b8" : "#64748b";
|
|
|
|
const [loading, setLoading] = useState(true);
|
|
const [company, setCompany] = useState<any>(null);
|
|
|
|
useEffect(() => {
|
|
const load = async () => {
|
|
try {
|
|
setLoading(true);
|
|
const res = await api.company.get();
|
|
setCompany(res?.data ?? res);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
load();
|
|
}, []);
|
|
|
|
const fmtDate = (d: string) =>
|
|
d
|
|
? new Date(d).toLocaleDateString("en-GB", {
|
|
day: "numeric",
|
|
month: "short",
|
|
year: "numeric",
|
|
})
|
|
: "—";
|
|
|
|
if (loading) {
|
|
return (
|
|
<ScreenWrapper className="bg-background">
|
|
<View className="flex-1 items-center justify-center">
|
|
<ActivityIndicator size="large" color="#E46212" />
|
|
</View>
|
|
</ScreenWrapper>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<ScreenWrapper className="bg-background">
|
|
<View className="px-5 pt-4 flex-row justify-between items-center">
|
|
<Pressable
|
|
onPress={() => nav.back()}
|
|
className="h-9 w-9 rounded-[10px] bg-card items-center justify-center border border-border"
|
|
>
|
|
<ArrowLeft
|
|
color={isDark ? "#f8fafc" : "#0f172a"}
|
|
size={18}
|
|
/>
|
|
</Pressable>
|
|
<Text className="text-foreground text-[16px] font-sans-bold">
|
|
Company Details
|
|
</Text>
|
|
<Pressable
|
|
onPress={() => nav.go("company/edit")}
|
|
className="h-9 w-9 rounded-[10px] bg-card items-center justify-center border border-border"
|
|
>
|
|
<Edit color="#E46212" size={16} strokeWidth={2} />
|
|
</Pressable>
|
|
</View>
|
|
|
|
<ScrollView
|
|
showsVerticalScrollIndicator={false}
|
|
contentContainerStyle={{ padding: 16, paddingBottom: 40 }}
|
|
>
|
|
{/* Hero */}
|
|
<View className="items-center mb-6">
|
|
{company?.logoPath ? (
|
|
<View className="h-20 w-20 rounded-full overflow-hidden bg-muted mb-3 border-2 border-border/30">
|
|
<Image
|
|
source={{ uri: company.logoPath }}
|
|
className="h-full w-full"
|
|
resizeMode="cover"
|
|
/>
|
|
</View>
|
|
) : (
|
|
<View className="h-20 w-20 rounded-full bg-primary/10 items-center justify-center mb-3 border-2 border-primary/20">
|
|
<Building2 size={32} color="#E46212" strokeWidth={1.5} />
|
|
</View>
|
|
)}
|
|
<Text className="text-foreground text-xl font-sans-black tracking-tight text-center">
|
|
{company?.name || "Company"}
|
|
</Text>
|
|
{company?.tin && (
|
|
<View className="flex-row items-center mt-1.5">
|
|
<Hash size={12} color={iconCol} strokeWidth={2} />
|
|
<Text className="text-muted-foreground text-sm font-sans-medium ml-1.5">
|
|
TIN: {company.tin}
|
|
</Text>
|
|
</View>
|
|
)}
|
|
</View>
|
|
|
|
{/* Contact */}
|
|
<Text className="text-[10px] font-sans-bold uppercase tracking-widest text-muted-foreground mb-2 ml-1">
|
|
Contact
|
|
</Text>
|
|
<Card className="rounded-[6px] border-border bg-card overflow-hidden mb-5">
|
|
<CardContent className="p-0">
|
|
{company?.phone && (
|
|
<InfoRow
|
|
icon={<Phone size={15} color={iconCol} strokeWidth={2} />}
|
|
label="Phone"
|
|
value={company.phone}
|
|
isLast={!company?.email && !company?.website}
|
|
/>
|
|
)}
|
|
{company?.email && (
|
|
<InfoRow
|
|
icon={<Mail size={15} color={iconCol} strokeWidth={2} />}
|
|
label="Email"
|
|
value={company.email}
|
|
isLast={!company?.website}
|
|
/>
|
|
)}
|
|
{company?.website && (
|
|
<InfoRow
|
|
icon={<Globe size={15} color={iconCol} strokeWidth={2} />}
|
|
label="Website"
|
|
value={company.website}
|
|
isLast
|
|
/>
|
|
)}
|
|
{!company?.phone && !company?.email && !company?.website && (
|
|
<View className="px-4 py-3">
|
|
<Text className="text-muted-foreground text-sm font-sans-medium">
|
|
No contact information
|
|
</Text>
|
|
</View>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Address */}
|
|
<Text className="text-[10px] font-sans-bold uppercase tracking-widest text-muted-foreground mb-2 ml-1">
|
|
Address
|
|
</Text>
|
|
<Card className="rounded-[6px] border-border bg-card overflow-hidden mb-5">
|
|
<CardContent className="p-0">
|
|
{company?.address && (
|
|
<InfoRow
|
|
icon={<MapPin size={15} color={iconCol} strokeWidth={2} />}
|
|
label="Street"
|
|
value={company.address}
|
|
isLast={!company?.city && !company?.state && !company?.zipCode && !company?.country}
|
|
/>
|
|
)}
|
|
{(company?.city || company?.state) && (
|
|
<InfoRow
|
|
icon={<MapPin size={15} color={iconCol} strokeWidth={2} />}
|
|
label="City / State"
|
|
value={[company?.city, company?.state].filter(Boolean).join(", ")}
|
|
isLast={!company?.zipCode && !company?.country}
|
|
/>
|
|
)}
|
|
{(company?.zipCode || company?.country) && (
|
|
<InfoRow
|
|
icon={<MapPin size={15} color={iconCol} strokeWidth={2} />}
|
|
label="Zip / Country"
|
|
value={[company?.zipCode, company?.country].filter(Boolean).join(", ")}
|
|
isLast
|
|
/>
|
|
)}
|
|
{!company?.address && !company?.city && !company?.state && (
|
|
<View className="px-4 py-3">
|
|
<Text className="text-muted-foreground text-sm font-sans-medium">
|
|
No address information
|
|
</Text>
|
|
</View>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Info */}
|
|
<Text className="text-[10px] font-sans-bold uppercase tracking-widest text-muted-foreground mb-2 ml-1">
|
|
Account
|
|
</Text>
|
|
<Card className="rounded-[6px] border-border bg-card overflow-hidden mb-5">
|
|
<CardContent className="p-0">
|
|
<InfoRow
|
|
icon={<Calendar size={15} color={iconCol} strokeWidth={2} />}
|
|
label="Created"
|
|
value={fmtDate(company?.createdAt)}
|
|
isLast={!company?.updatedAt}
|
|
/>
|
|
{company?.updatedAt && (
|
|
<InfoRow
|
|
icon={<Calendar size={15} color={iconCol} strokeWidth={2} />}
|
|
label="Last Updated"
|
|
value={fmtDate(company?.updatedAt)}
|
|
isLast
|
|
/>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
</ScrollView>
|
|
</ScreenWrapper>
|
|
);
|
|
}
|
|
|
|
function InfoRow({
|
|
icon,
|
|
label,
|
|
value,
|
|
isLast,
|
|
}: {
|
|
icon: React.ReactNode;
|
|
label: string;
|
|
value: string;
|
|
isLast?: boolean;
|
|
}) {
|
|
return (
|
|
<View
|
|
className={`flex-row items-center px-4 py-3.5 ${!isLast ? "border-b border-border/40" : ""}`}
|
|
>
|
|
<View className="h-8 w-8 rounded-[6px] bg-secondary/60 items-center justify-center mr-3">
|
|
{icon}
|
|
</View>
|
|
<View className="flex-1">
|
|
<Text className="text-muted-foreground text-[10px] font-sans-medium">{label}</Text>
|
|
<Text className="text-foreground text-sm font-sans-bold mt-0.5">{value}</Text>
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|