mirror of
https://github.com/linkwarden/linkwarden.git
synced 2026-03-03 03:47:02 +00:00
fix(mobile): fix collection and tags not updating bug
This commit is contained in:
@@ -1,43 +1,17 @@
|
||||
import {
|
||||
FlatList,
|
||||
Platform,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from "react-native";
|
||||
import { Platform, ScrollView, StyleSheet } from "react-native";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { useDashboardData } from "@linkwarden/router/dashboardData";
|
||||
import useAuthStore from "@/store/auth";
|
||||
import { DashboardSection } from "@linkwarden/prisma/client";
|
||||
import { DashboardSection as PrismaDashboardSection } from "@linkwarden/prisma/client";
|
||||
import { useUser } from "@linkwarden/router/user";
|
||||
import { useCollections } from "@linkwarden/router/collections";
|
||||
import { useTags } from "@linkwarden/router/tags";
|
||||
import clsx from "clsx";
|
||||
import DashboardItem from "@/components/DashboardItem";
|
||||
import { LinkIncludingShortenedCollectionAndTags } from "@linkwarden/types";
|
||||
import LinkListing from "@/components/LinkListing";
|
||||
import { useRouter } from "expo-router";
|
||||
import { rawTheme, ThemeName } from "@/lib/colors";
|
||||
import { useColorScheme } from "nativewind";
|
||||
import {
|
||||
Clock8,
|
||||
ChevronRight,
|
||||
Pin,
|
||||
Folder,
|
||||
Hash,
|
||||
Link,
|
||||
} from "lucide-react-native";
|
||||
import Spinner from "@/components/ui/Spinner";
|
||||
|
||||
// Don't remove this, spent a couple of days to figure out why the app crashes in production :|
|
||||
type DashboardSectionType =
|
||||
| "STATS"
|
||||
| "RECENT_LINKS"
|
||||
| "PINNED_LINKS"
|
||||
| "COLLECTION";
|
||||
import DashboardSection from "@/components/DashboardSection";
|
||||
|
||||
export default function DashboardScreen() {
|
||||
const { auth } = useAuthStore();
|
||||
@@ -48,15 +22,16 @@ export default function DashboardScreen() {
|
||||
...dashboardData
|
||||
} = useDashboardData(auth);
|
||||
const { data: user, ...userData } = useUser(auth);
|
||||
const { data: collections = [] } = useCollections(auth);
|
||||
const { data: tags = [] } = useTags(auth);
|
||||
const { data: collections = [], refetch: refetchCollections } =
|
||||
useCollections(auth);
|
||||
const { data: tags = [], refetch: refetchTags } = useTags(auth);
|
||||
|
||||
const { colorScheme } = useColorScheme();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const [dashboardSections, setDashboardSections] = useState<
|
||||
DashboardSection[]
|
||||
PrismaDashboardSection[]
|
||||
>(user?.dashboardSections || []);
|
||||
|
||||
const [numberOfLinks, setNumberOfLinks] = useState(0);
|
||||
@@ -83,267 +58,6 @@ export default function DashboardScreen() {
|
||||
});
|
||||
}, [dashboardSections]);
|
||||
|
||||
const RenderItem = React.memo(
|
||||
({ item }: { item: LinkIncludingShortenedCollectionAndTags }) => {
|
||||
return <LinkListing link={item} dashboard />;
|
||||
}
|
||||
);
|
||||
|
||||
interface SectionProps {
|
||||
sectionData: { type: DashboardSectionType };
|
||||
collection?: any;
|
||||
links?: any[];
|
||||
tagsLength: number;
|
||||
numberOfLinks: number;
|
||||
collectionsLength: number;
|
||||
numberOfPinnedLinks: number;
|
||||
dashboardData: { isLoading: boolean };
|
||||
collectionLinks?: any[];
|
||||
}
|
||||
|
||||
const Section: React.FC<SectionProps> = ({
|
||||
sectionData,
|
||||
collection,
|
||||
links = [],
|
||||
tagsLength,
|
||||
numberOfLinks,
|
||||
collectionsLength,
|
||||
numberOfPinnedLinks,
|
||||
dashboardData,
|
||||
collectionLinks = [],
|
||||
}) => {
|
||||
switch (sectionData.type) {
|
||||
case "STATS":
|
||||
return (
|
||||
<View className="flex-col gap-4 max-w-full px-5">
|
||||
<View className="flex-row gap-4">
|
||||
<DashboardItem
|
||||
name={numberOfLinks === 1 ? "Link" : "Links"}
|
||||
value={numberOfLinks}
|
||||
icon={<Link size={23} color="white" />}
|
||||
color="#9c00cc"
|
||||
/>
|
||||
<DashboardItem
|
||||
name={collectionsLength === 1 ? "Collection" : "Collections"}
|
||||
value={collectionsLength}
|
||||
icon={<Folder size={23} color="white" fill="white" />}
|
||||
color="#0096cc"
|
||||
/>
|
||||
</View>
|
||||
<View className="flex-row gap-4">
|
||||
<DashboardItem
|
||||
name={tagsLength === 1 ? "Tag" : "Tags"}
|
||||
value={tagsLength}
|
||||
icon={<Hash size={23} color="white" />}
|
||||
color="#00cc99"
|
||||
/>
|
||||
<DashboardItem
|
||||
name={"Pinned Links"}
|
||||
value={numberOfPinnedLinks}
|
||||
icon={<Pin size={23} color="white" fill="white" />}
|
||||
color="#cc6d00"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
case "RECENT_LINKS":
|
||||
return (
|
||||
<>
|
||||
<View className="flex-row justify-between items-center px-5">
|
||||
<View className="flex-row gap-2 items-center">
|
||||
<View className={"flex-row items-center gap-2"}>
|
||||
<Clock8
|
||||
size={30}
|
||||
color={rawTheme[colorScheme as ThemeName].primary}
|
||||
/>
|
||||
<Text className="text-2xl capitalize text-base-content">
|
||||
Recent Links
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
className="flex-row items-center text-sm gap-1"
|
||||
onPress={() =>
|
||||
router.navigate("/(tabs)/dashboard/recent-links")
|
||||
}
|
||||
>
|
||||
<Text className="text-primary">View All</Text>
|
||||
<ChevronRight
|
||||
size={15}
|
||||
color={rawTheme[colorScheme as ThemeName].primary}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{dashboardData.isLoading ||
|
||||
(links.length > 0 && !dashboardData.isLoading) ? (
|
||||
<FlatList
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
directionalLockEnabled
|
||||
data={links || []}
|
||||
refreshing={dashboardData.isLoading}
|
||||
initialNumToRender={2}
|
||||
keyExtractor={(item) => item.id?.toString() || ""}
|
||||
renderItem={({ item }) => (
|
||||
<RenderItem item={item} key={item.id?.toString()} />
|
||||
)}
|
||||
ItemSeparatorComponent={() => <View style={{ width: 10 }} />}
|
||||
contentContainerStyle={{
|
||||
paddingHorizontal: 20,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<View className="flex-col gap-2 justify-center items-center h-40 p-10 rounded-xl bg-base-200 mx-5">
|
||||
<Clock8
|
||||
size={40}
|
||||
color={rawTheme[colorScheme as ThemeName].primary}
|
||||
/>
|
||||
<Text className="text-center text-xl text-neutral">
|
||||
No Recent Links
|
||||
</Text>
|
||||
|
||||
{/* <View className="text-center w-full mt-4 flex-row flex-wrap gap-4 justify-center">
|
||||
<Button onPress={() => setNewLinkModal(true)} variant="accent">
|
||||
<Icon name="bi-plus-lg" className="text-xl" />
|
||||
<Text>{t("add_link")}</Text>
|
||||
</Button>
|
||||
<ImportDropdown />
|
||||
</View> */}
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
case "PINNED_LINKS":
|
||||
return (
|
||||
<>
|
||||
<View className="flex-row justify-between items-center px-5">
|
||||
<View className="flex-row gap-2 items-center">
|
||||
<View className={"flex-row items-center gap-2"}>
|
||||
<Pin
|
||||
size={30}
|
||||
color={rawTheme[colorScheme as ThemeName].primary}
|
||||
/>
|
||||
<Text className="text-2xl capitalize text-base-content">
|
||||
Pinned Links
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
className="flex-row items-center text-sm gap-1"
|
||||
onPress={() =>
|
||||
router.navigate("/(tabs)/dashboard/pinned-links")
|
||||
}
|
||||
>
|
||||
<Text className="text-primary">View All</Text>
|
||||
<ChevronRight
|
||||
size={15}
|
||||
color={rawTheme[colorScheme as ThemeName].primary}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{dashboardData.isLoading ||
|
||||
links?.some((e: any) => e.pinnedBy && e.pinnedBy[0]) ? (
|
||||
<FlatList
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
data={
|
||||
links.filter((e: any) => e.pinnedBy && e.pinnedBy[0]) || []
|
||||
}
|
||||
refreshing={dashboardData.isLoading}
|
||||
initialNumToRender={2}
|
||||
keyExtractor={(item) => item.id?.toString() || ""}
|
||||
renderItem={({ item }) => (
|
||||
<RenderItem item={item} key={item.id?.toString()} />
|
||||
)}
|
||||
ItemSeparatorComponent={() => <View style={{ width: 10 }} />}
|
||||
contentContainerStyle={{
|
||||
paddingHorizontal: 20,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<View className="flex-col gap-2 justify-center items-center h-40 p-10 rounded-xl bg-base-200 mx-5">
|
||||
<Pin
|
||||
size={40}
|
||||
color={rawTheme[colorScheme as ThemeName].primary}
|
||||
/>
|
||||
<Text className="text-center text-xl text-neutral">
|
||||
No Pinned Links
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
case "COLLECTION":
|
||||
return collection?.id ? (
|
||||
<>
|
||||
<View className="flex-row justify-between items-center px-5">
|
||||
<View className="flex-row gap-2 items-center max-w-[60%]">
|
||||
<View className={clsx("flex-row items-center gap-2")}>
|
||||
<Folder
|
||||
size={30}
|
||||
fill={collection.color || "#0ea5e9"}
|
||||
color={collection.color || "#0ea5e9"}
|
||||
/>
|
||||
<Text
|
||||
className="text-2xl capitalize w-full text-base-content"
|
||||
numberOfLines={1}
|
||||
>
|
||||
{collection.name}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
className="flex-row items-center text-sm gap-1 whitespace-nowrap"
|
||||
onPress={() =>
|
||||
router.navigate(
|
||||
`/(tabs)/dashboard/collection?collectionId=${collection.id}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<Text className="text-primary">View All</Text>
|
||||
<ChevronRight
|
||||
size={15}
|
||||
color={rawTheme[colorScheme as ThemeName].primary}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{dashboardData.isLoading || collectionLinks.length > 0 ? (
|
||||
<FlatList
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
data={collectionLinks || []}
|
||||
refreshing={dashboardData.isLoading}
|
||||
initialNumToRender={2}
|
||||
keyExtractor={(item) => item.id?.toString() || ""}
|
||||
renderItem={({ item }) => (
|
||||
<RenderItem item={item} key={item.id?.toString()} />
|
||||
)}
|
||||
ItemSeparatorComponent={() => <View style={{ width: 10 }} />}
|
||||
contentContainerStyle={{
|
||||
paddingHorizontal: 20,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<View className="flex-col gap-2 justify-center items-center h-40 p-10 rounded-xl bg-base-200 mx-5">
|
||||
<Text className="text-center text-xl text-neutral">
|
||||
Empty Collection
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
) : null;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView
|
||||
style={styles.container}
|
||||
@@ -358,6 +72,8 @@ export default function DashboardScreen() {
|
||||
onRefresh={() => {
|
||||
dashboardData.refetch();
|
||||
userData.refetch();
|
||||
refetchCollections();
|
||||
refetchTags();
|
||||
}}
|
||||
progressBackgroundColor={
|
||||
rawTheme[colorScheme as ThemeName]["base-200"]
|
||||
@@ -375,7 +91,7 @@ export default function DashboardScreen() {
|
||||
>
|
||||
{orderedSections.map((sectionData) => {
|
||||
return (
|
||||
<Section
|
||||
<DashboardSection
|
||||
key={sectionData.id}
|
||||
sectionData={sectionData}
|
||||
collection={collections.find(
|
||||
|
||||
285
apps/mobile/components/DashboardSection.tsx
Normal file
285
apps/mobile/components/DashboardSection.tsx
Normal file
@@ -0,0 +1,285 @@
|
||||
import { FlatList, Text, TouchableOpacity, View } from "react-native";
|
||||
import React from "react";
|
||||
import clsx from "clsx";
|
||||
import DashboardItem from "@/components/DashboardItem";
|
||||
import { rawTheme, ThemeName } from "@/lib/colors";
|
||||
import {
|
||||
Clock8,
|
||||
ChevronRight,
|
||||
Pin,
|
||||
Folder,
|
||||
Hash,
|
||||
Link,
|
||||
} from "lucide-react-native";
|
||||
import { LinkIncludingShortenedCollectionAndTags } from "@linkwarden/types";
|
||||
import LinkListing from "@/components/LinkListing";
|
||||
import { useColorScheme } from "nativewind";
|
||||
import { useRouter } from "expo-router";
|
||||
|
||||
// Don't remove this, spent a couple of days to figure out why the app crashes in production :|
|
||||
type DashboardSectionType =
|
||||
| "STATS"
|
||||
| "RECENT_LINKS"
|
||||
| "PINNED_LINKS"
|
||||
| "COLLECTION";
|
||||
|
||||
type DashboardSectionProps = {
|
||||
sectionData: { type: DashboardSectionType };
|
||||
collection?: any;
|
||||
links?: any[];
|
||||
tagsLength: number;
|
||||
numberOfLinks: number;
|
||||
collectionsLength: number;
|
||||
numberOfPinnedLinks: number;
|
||||
dashboardData: { isLoading: boolean };
|
||||
collectionLinks?: any[];
|
||||
};
|
||||
|
||||
const DashboardSection: React.FC<DashboardSectionProps> = ({
|
||||
sectionData,
|
||||
collection,
|
||||
links = [],
|
||||
tagsLength,
|
||||
numberOfLinks,
|
||||
collectionsLength,
|
||||
numberOfPinnedLinks,
|
||||
dashboardData,
|
||||
collectionLinks = [],
|
||||
}) => {
|
||||
const { colorScheme } = useColorScheme();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
switch (sectionData.type) {
|
||||
case "STATS":
|
||||
return (
|
||||
<View className="flex-col gap-4 max-w-full px-5">
|
||||
<View className="flex-row gap-4">
|
||||
<DashboardItem
|
||||
name={numberOfLinks === 1 ? "Link" : "Links"}
|
||||
value={numberOfLinks}
|
||||
icon={<Link size={23} color="white" />}
|
||||
color="#9c00cc"
|
||||
/>
|
||||
<DashboardItem
|
||||
name={collectionsLength === 1 ? "Collection" : "Collections"}
|
||||
value={collectionsLength}
|
||||
icon={<Folder size={23} color="white" fill="white" />}
|
||||
color="#0096cc"
|
||||
/>
|
||||
</View>
|
||||
<View className="flex-row gap-4">
|
||||
<DashboardItem
|
||||
name={tagsLength === 1 ? "Tag" : "Tags"}
|
||||
value={tagsLength}
|
||||
icon={<Hash size={23} color="white" />}
|
||||
color="#00cc99"
|
||||
/>
|
||||
<DashboardItem
|
||||
name={"Pinned Links"}
|
||||
value={numberOfPinnedLinks}
|
||||
icon={<Pin size={23} color="white" fill="white" />}
|
||||
color="#cc6d00"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
case "RECENT_LINKS":
|
||||
return (
|
||||
<>
|
||||
<View className="flex-row justify-between items-center px-5">
|
||||
<View className="flex-row gap-2 items-center">
|
||||
<View className={"flex-row items-center gap-2"}>
|
||||
<Clock8
|
||||
size={30}
|
||||
color={rawTheme[colorScheme as ThemeName].primary}
|
||||
/>
|
||||
<Text className="text-2xl capitalize text-base-content">
|
||||
Recent Links
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
className="flex-row items-center text-sm gap-1"
|
||||
onPress={() => router.navigate("/(tabs)/dashboard/recent-links")}
|
||||
>
|
||||
<Text className="text-primary">View All</Text>
|
||||
<ChevronRight
|
||||
size={15}
|
||||
color={rawTheme[colorScheme as ThemeName].primary}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{dashboardData.isLoading ||
|
||||
(links.length > 0 && !dashboardData.isLoading) ? (
|
||||
<FlatList
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
directionalLockEnabled
|
||||
data={links || []}
|
||||
refreshing={dashboardData.isLoading}
|
||||
initialNumToRender={2}
|
||||
keyExtractor={(item) => item.id?.toString() || ""}
|
||||
renderItem={({ item }) => (
|
||||
<RenderItem item={item} key={item.id?.toString()} />
|
||||
)}
|
||||
ItemSeparatorComponent={() => <View style={{ width: 10 }} />}
|
||||
contentContainerStyle={{
|
||||
paddingHorizontal: 20,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<View className="flex-col gap-2 justify-center items-center h-40 p-10 rounded-xl bg-base-200 mx-5">
|
||||
<Clock8
|
||||
size={40}
|
||||
color={rawTheme[colorScheme as ThemeName].primary}
|
||||
/>
|
||||
<Text className="text-center text-xl text-neutral">
|
||||
No Recent Links
|
||||
</Text>
|
||||
|
||||
{/* <View className="text-center w-full mt-4 flex-row flex-wrap gap-4 justify-center">
|
||||
<Button onPress={() => setNewLinkModal(true)} variant="accent">
|
||||
<Icon name="bi-plus-lg" className="text-xl" />
|
||||
<Text>{t("add_link")}</Text>
|
||||
</Button>
|
||||
<ImportDropdown />
|
||||
</View> */}
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
case "PINNED_LINKS":
|
||||
return (
|
||||
<>
|
||||
<View className="flex-row justify-between items-center px-5">
|
||||
<View className="flex-row gap-2 items-center">
|
||||
<View className={"flex-row items-center gap-2"}>
|
||||
<Pin
|
||||
size={30}
|
||||
color={rawTheme[colorScheme as ThemeName].primary}
|
||||
/>
|
||||
<Text className="text-2xl capitalize text-base-content">
|
||||
Pinned Links
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
className="flex-row items-center text-sm gap-1"
|
||||
onPress={() => router.navigate("/(tabs)/dashboard/pinned-links")}
|
||||
>
|
||||
<Text className="text-primary">View All</Text>
|
||||
<ChevronRight
|
||||
size={15}
|
||||
color={rawTheme[colorScheme as ThemeName].primary}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{dashboardData.isLoading ||
|
||||
links?.some((e: any) => e.pinnedBy && e.pinnedBy[0]) ? (
|
||||
<FlatList
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
data={links.filter((e: any) => e.pinnedBy && e.pinnedBy[0]) || []}
|
||||
refreshing={dashboardData.isLoading}
|
||||
initialNumToRender={2}
|
||||
keyExtractor={(item) => item.id?.toString() || ""}
|
||||
renderItem={({ item }) => (
|
||||
<RenderItem item={item} key={item.id?.toString()} />
|
||||
)}
|
||||
ItemSeparatorComponent={() => <View style={{ width: 10 }} />}
|
||||
contentContainerStyle={{
|
||||
paddingHorizontal: 20,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<View className="flex-col gap-2 justify-center items-center h-40 p-10 rounded-xl bg-base-200 mx-5">
|
||||
<Pin
|
||||
size={40}
|
||||
color={rawTheme[colorScheme as ThemeName].primary}
|
||||
/>
|
||||
<Text className="text-center text-xl text-neutral">
|
||||
No Pinned Links
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
case "COLLECTION":
|
||||
return collection?.id ? (
|
||||
<>
|
||||
<View className="flex-row justify-between items-center px-5">
|
||||
<View className="flex-row gap-2 items-center max-w-[60%]">
|
||||
<View className={clsx("flex-row items-center gap-2")}>
|
||||
<Folder
|
||||
size={30}
|
||||
fill={collection.color || "#0ea5e9"}
|
||||
color={collection.color || "#0ea5e9"}
|
||||
/>
|
||||
<Text
|
||||
className="text-2xl capitalize w-full text-base-content"
|
||||
numberOfLines={1}
|
||||
>
|
||||
{collection.name}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
className="flex-row items-center text-sm gap-1 whitespace-nowrap"
|
||||
onPress={() =>
|
||||
router.navigate(
|
||||
`/(tabs)/dashboard/collection?collectionId=${collection.id}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<Text className="text-primary">View All</Text>
|
||||
<ChevronRight
|
||||
size={15}
|
||||
color={rawTheme[colorScheme as ThemeName].primary}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{dashboardData.isLoading || collectionLinks.length > 0 ? (
|
||||
<FlatList
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
data={collectionLinks || []}
|
||||
refreshing={dashboardData.isLoading}
|
||||
initialNumToRender={2}
|
||||
keyExtractor={(item) => item.id?.toString() || ""}
|
||||
renderItem={({ item }) => (
|
||||
<RenderItem item={item} key={item.id?.toString()} />
|
||||
)}
|
||||
ItemSeparatorComponent={() => <View style={{ width: 10 }} />}
|
||||
contentContainerStyle={{
|
||||
paddingHorizontal: 20,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<View className="flex-col gap-2 justify-center items-center h-40 p-10 rounded-xl bg-base-200 mx-5">
|
||||
<Text className="text-center text-xl text-neutral">
|
||||
Empty Collection
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
) : null;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export default DashboardSection;
|
||||
|
||||
const RenderItem = React.memo(
|
||||
({ item }: { item: LinkIncludingShortenedCollectionAndTags }) => {
|
||||
return <LinkListing link={item} dashboard />;
|
||||
}
|
||||
);
|
||||
Reference in New Issue
Block a user