feat: persist view mode (grid/list) across division, project, dan division/task

- Simpan preferensi tampilan ke AsyncStorage dengan key 'division_view_mode'
- Load preferensi saat halaman dibuka agar tidak reset
- Samakan style list item division/task dengan project (bg transparent, icon hitam)
- Sejajarkan toggle dengan input pencarian pada halaman division/task
This commit is contained in:
2026-05-07 16:16:21 +08:00
parent e48456ea7f
commit fad89fc910
3 changed files with 46 additions and 18 deletions

View File

@@ -21,6 +21,7 @@ import { router, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Pressable, RefreshControl, ScrollView, View, VirtualizedList } from "react-native"; import { Pressable, RefreshControl, ScrollView, View, VirtualizedList } from "react-native";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import AsyncStorage from "@react-native-async-storage/async-storage";
type Props = { type Props = {
id: string; id: string;
@@ -36,6 +37,18 @@ export default function ListTask() {
const { id, status, year } = useLocalSearchParams<{ id: string; status: string; year: string }>() const { id, status, year } = useLocalSearchParams<{ id: string; status: string; year: string }>()
const [isList, setList] = useState(false) const [isList, setList] = useState(false)
const { token, decryptToken } = useAuthSession() const { token, decryptToken } = useAuthSession()
useEffect(() => {
AsyncStorage.getItem('division_view_mode').then((val) => {
if (val !== null) setList(val === 'list')
})
}, [])
function toggleView() {
const next = !isList
setList(next)
AsyncStorage.setItem('division_view_mode', next ? 'list' : 'grid')
}
const [data, setData] = useState<Props[]>([]) const [data, setData] = useState<Props[]>([])
const [search, setSearch] = useState("") const [search, setSearch] = useState("")
const update = useSelector((state: any) => state.taskUpdate) const update = useSelector((state: any) => state.taskUpdate)
@@ -172,13 +185,9 @@ export default function ListTask() {
n={4} n={4}
/> />
</ScrollView> </ScrollView>
<View style={[Styles.rowSpaceBetween]}> <View style={[Styles.rowSpaceBetween, { alignItems: 'center' }]}>
<InputSearch width={68} onChange={setSearch} /> <InputSearch width={68} onChange={setSearch} />
<Pressable <Pressable onPress={toggleView}>
onPress={() => {
setList(!isList);
}}
>
<MaterialCommunityIcons <MaterialCommunityIcons
name={isList ? "format-list-bulleted" : "view-grid"} name={isList ? "format-list-bulleted" : "view-grid"}
color={colors.text} color={colors.text}
@@ -219,9 +228,10 @@ export default function ListTask() {
router.push(`./task/${item.id}`); router.push(`./task/${item.id}`);
}} }}
borderType="bottom" borderType="bottom"
bgColor="transparent"
icon={ icon={
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}> <View style={[Styles.iconContent]}>
<AntDesign name="areachart" size={25} color={"#384288"} /> <AntDesign name="areachart" size={25} color={"black"} />
</View> </View>
} }
title={item.title} title={item.title}

View File

@@ -17,6 +17,7 @@ import {
Ionicons, Ionicons,
MaterialCommunityIcons MaterialCommunityIcons
} from "@expo/vector-icons"; } from "@expo/vector-icons";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { useInfiniteQuery, useQueryClient } from "@tanstack/react-query"; import { useInfiniteQuery, useQueryClient } from "@tanstack/react-query";
import { router, useLocalSearchParams } from "expo-router"; import { router, useLocalSearchParams } from "expo-router";
import { useEffect, useMemo, useState } from "react"; import { useEffect, useMemo, useState } from "react";
@@ -37,6 +38,18 @@ export default function ListDivision() {
cat?: string; cat?: string;
}>(); }>();
const [isList, setList] = useState(false); const [isList, setList] = useState(false);
useEffect(() => {
AsyncStorage.getItem('division_view_mode').then((val) => {
if (val !== null) setList(val === 'list')
})
}, [])
function toggleView() {
const next = !isList
setList(next)
AsyncStorage.setItem('division_view_mode', next ? 'list' : 'grid')
}
const entityUser = useSelector((state: any) => state.user) const entityUser = useSelector((state: any) => state.user)
const { token, decryptToken } = useAuthSession() const { token, decryptToken } = useAuthSession()
const { colors } = useTheme(); const { colors } = useTheme();
@@ -184,11 +197,7 @@ export default function ListDivision() {
<View style={[Styles.rowSpaceBetween, { alignItems: 'center' }]}> <View style={[Styles.rowSpaceBetween, { alignItems: 'center' }]}>
<InputSearch width={68} onChange={setSearch} /> <InputSearch width={68} onChange={setSearch} />
<Pressable <Pressable onPress={toggleView}>
onPress={() => {
setList(!isList);
}}
>
<MaterialCommunityIcons <MaterialCommunityIcons
name={isList ? "format-list-bulleted" : "view-grid"} name={isList ? "format-list-bulleted" : "view-grid"}
color={colors.text} color={colors.text}

View File

@@ -23,6 +23,7 @@ import { router, useLocalSearchParams } from "expo-router";
import { useEffect, useMemo, useState } from "react"; import { useEffect, useMemo, useState } from "react";
import { Pressable, RefreshControl, ScrollView, View, VirtualizedList } from "react-native"; import { Pressable, RefreshControl, ScrollView, View, VirtualizedList } from "react-native";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import AsyncStorage from "@react-native-async-storage/async-storage";
type Props = { type Props = {
id: string; id: string;
@@ -50,6 +51,18 @@ export default function ListProject() {
const [search, setSearch] = useState("") const [search, setSearch] = useState("")
const [isList, setList] = useState(false) const [isList, setList] = useState(false)
const update = useSelector((state: any) => state.projectUpdate) const update = useSelector((state: any) => state.projectUpdate)
useEffect(() => {
AsyncStorage.getItem('division_view_mode').then((val) => {
if (val !== null) setList(val === 'list')
})
}, [])
function toggleView() {
const next = !isList
setList(next)
AsyncStorage.setItem('division_view_mode', next ? 'list' : 'grid')
}
const queryClient = useQueryClient() const queryClient = useQueryClient()
const [refreshing, setRefreshing] = useState(false) const [refreshing, setRefreshing] = useState(false)
@@ -188,11 +201,7 @@ export default function ListProject() {
<View style={[Styles.rowSpaceBetween, Styles.rowItemsCenter]}> <View style={[Styles.rowSpaceBetween, Styles.rowItemsCenter]}>
<InputSearch width={68} onChange={setSearch} /> <InputSearch width={68} onChange={setSearch} />
<Pressable <Pressable onPress={toggleView}>
onPress={() => {
setList(!isList);
}}
>
<MaterialCommunityIcons <MaterialCommunityIcons
name={isList ? "format-list-bulleted" : "view-grid"} name={isList ? "format-list-bulleted" : "view-grid"}
color={colors.text} color={colors.text}