upd: announcement
Deskripsi: - load all announcement - pencarian announcement - tambah announcement - get detail one announcement No Issues
This commit is contained in:
@@ -1,12 +1,40 @@
|
|||||||
import HeaderRightAnnouncementDetail from "@/components/announcement/headerAnnouncementDetail";
|
import HeaderRightAnnouncementDetail from "@/components/announcement/headerAnnouncementDetail";
|
||||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||||
import Styles from "@/constants/Styles";
|
import Styles from "@/constants/Styles";
|
||||||
import { AntDesign, MaterialIcons } from "@expo/vector-icons";
|
import { apiGetAnnouncementOne } from "@/lib/api";
|
||||||
|
import { useAuthSession } from "@/providers/AuthProvider";
|
||||||
|
import { AntDesign, Entypo, MaterialIcons } from "@expo/vector-icons";
|
||||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||||
import { SafeAreaView, ScrollView, SectionList, Text, View } from "react-native";
|
import { useEffect, useState } from "react";
|
||||||
|
import { SafeAreaView, ScrollView, Text, View } from "react-native";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
id: string
|
||||||
|
title: string
|
||||||
|
desc: string
|
||||||
|
}
|
||||||
|
|
||||||
export default function DetailAnnouncement() {
|
export default function DetailAnnouncement() {
|
||||||
const { id } = useLocalSearchParams()
|
const { id } = useLocalSearchParams<{ id: string }>();
|
||||||
|
const { token, decryptToken } = useAuthSession()
|
||||||
|
const [data, setData] = useState<Props>()
|
||||||
|
const [dataMember, setDataMember] = useState<any>({})
|
||||||
|
|
||||||
|
async function handleLoad() {
|
||||||
|
try {
|
||||||
|
const hasil = await decryptToken(String(token?.current))
|
||||||
|
const response = await apiGetAnnouncementOne({ id: id, user: hasil })
|
||||||
|
setData(response.data)
|
||||||
|
setDataMember(response.member)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
handleLoad()
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaView>
|
<SafeAreaView>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
@@ -17,39 +45,42 @@ export default function DetailAnnouncement() {
|
|||||||
headerRight: () => <HeaderRightAnnouncementDetail id={id} />,
|
headerRight: () => <HeaderRightAnnouncementDetail id={id} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{/* <ScrollView> */}
|
<ScrollView>
|
||||||
<View style={[Styles.p15]}>
|
<View style={[Styles.p15]}>
|
||||||
<View style={[Styles.wrapPaper]}>
|
<View style={[Styles.wrapPaper]}>
|
||||||
<View style={Styles.rowItemsCenter}>
|
<View style={Styles.rowItemsCenter}>
|
||||||
<MaterialIcons name="campaign" size={30} color="black" style={Styles.mr05} />
|
<MaterialIcons name="campaign" size={30} color="black" style={Styles.mr05} />
|
||||||
<Text style={[Styles.textDefaultSemiBold]}>Libur Nyepi</Text>
|
<Text style={[Styles.textDefaultSemiBold]}>{data?.title}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={[Styles.rowItemsCenter, Styles.mt10]}>
|
||||||
|
<AntDesign name="profile" size={30} color="black" style={Styles.mr05} />
|
||||||
|
<Text style={[Styles.textDefault]}>{data?.desc}</Text>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View style={[Styles.rowItemsCenter, Styles.mt10]}>
|
<View style={[Styles.wrapPaper, Styles.mv15]}>
|
||||||
<AntDesign name="profile" size={30} color="black" style={Styles.mr05} />
|
{
|
||||||
<Text style={[Styles.textDefault]}>Pengumuman terkait libur nyepi</Text>
|
Object.keys(dataMember).map((v: any, i: any) => {
|
||||||
|
return (
|
||||||
|
<View key={i} style={[Styles.mb05]}>
|
||||||
|
<Text style={[Styles.textDefaultSemiBold]}>{dataMember[v]?.[0].group}</Text>
|
||||||
|
{
|
||||||
|
dataMember[v].map((item: any, x: any) => {
|
||||||
|
return (
|
||||||
|
<View style={[Styles.rowItemsCenter]}>
|
||||||
|
<Entypo name="dot-single" size={24} color="black" />
|
||||||
|
<Text style={[Styles.textDefault]}>{item.division}</Text>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View style={[Styles.wrapPaper, Styles.mv15, { paddingTop: 0, paddingBottom: 10 }]}>
|
</ScrollView>
|
||||||
<SectionList
|
|
||||||
sections={[
|
|
||||||
{ title: 'Dinas', data: ['TU dan Umum', 'Kasi Pemerintahan', 'Pelaksana Kewilayahan'] },
|
|
||||||
{
|
|
||||||
title: 'Adat',
|
|
||||||
data: [
|
|
||||||
'PKK',
|
|
||||||
'Karang Taruna',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
renderItem={({ item }) => <Text style={Styles.textDefault}>{item}</Text>}
|
|
||||||
renderSectionHeader={({ section }) => (
|
|
||||||
<Text style={[Styles.textDefaultSemiBold, Styles.mt10, { borderBottomWidth: 1, borderBottomColor: 'gray' }]}>{section.title}</Text>
|
|
||||||
)}
|
|
||||||
keyExtractor={item => `basicListEntry-${item}`}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
{/* </ScrollView> */}
|
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2,43 +2,172 @@ import ButtonBackHeader from "@/components/buttonBackHeader";
|
|||||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||||
import ButtonSelect from "@/components/buttonSelect";
|
import ButtonSelect from "@/components/buttonSelect";
|
||||||
import { InputForm } from "@/components/inputForm";
|
import { InputForm } from "@/components/inputForm";
|
||||||
|
import ModalSelectMultiple from "@/components/modalSelectMultiple";
|
||||||
import Styles from "@/constants/Styles";
|
import Styles from "@/constants/Styles";
|
||||||
|
import { setUpdateAnnouncement } from "@/lib/announcementUpdate";
|
||||||
|
import { apiCreateAnnouncement } from "@/lib/api";
|
||||||
|
import { useAuthSession } from "@/providers/AuthProvider";
|
||||||
|
import { Entypo } from "@expo/vector-icons";
|
||||||
import { router, Stack } from "expo-router";
|
import { router, Stack } from "expo-router";
|
||||||
import { SafeAreaView, ScrollView, ToastAndroid, View } from "react-native";
|
import { useEffect, useState } from "react";
|
||||||
|
import { SafeAreaView, ScrollView, Text, ToastAndroid, View } from "react-native";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
|
||||||
export default function CreateAnnouncement() {
|
export default function CreateAnnouncement() {
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
const update = useSelector((state: any) => state.announcementUpdate)
|
||||||
|
const { token, decryptToken } = useAuthSession()
|
||||||
|
const [disableBtn, setDisableBtn] = useState(true);
|
||||||
|
const [modalDivisi, setModalDivisi] = useState(false);
|
||||||
|
const [divisionMember, setDivisionMember] = useState<any>([]);
|
||||||
|
const [dataForm, setDataForm] = useState({
|
||||||
|
title: "",
|
||||||
|
desc: "",
|
||||||
|
});
|
||||||
|
const [error, setError] = useState({
|
||||||
|
title: false,
|
||||||
|
desc: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
function validationForm(cat: string, val: any) {
|
||||||
|
if (cat == "title") {
|
||||||
|
setDataForm({ ...dataForm, title: val });
|
||||||
|
if (val == "" || val == "null") {
|
||||||
|
setError({ ...error, title: true });
|
||||||
|
} else {
|
||||||
|
setError({ ...error, title: false });
|
||||||
|
}
|
||||||
|
} else if (cat == "desc") {
|
||||||
|
setDataForm({ ...dataForm, desc: val });
|
||||||
|
if (val == "" || val == "null") {
|
||||||
|
setError({ ...error, desc: true });
|
||||||
|
} else {
|
||||||
|
setError({ ...error, desc: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkForm() {
|
||||||
|
if (
|
||||||
|
Object.values(error).some((v) => v == true) ||
|
||||||
|
Object.values(dataForm).some((v) => v == "")
|
||||||
|
) {
|
||||||
|
setDisableBtn(true);
|
||||||
|
} else {
|
||||||
|
setDisableBtn(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
checkForm();
|
||||||
|
}, [error, dataForm]);
|
||||||
|
|
||||||
|
async function handleCreate() {
|
||||||
|
try {
|
||||||
|
const hasil = await decryptToken(String(token?.current))
|
||||||
|
const response = await apiCreateAnnouncement({
|
||||||
|
data: { ...dataForm, user: hasil, groups: divisionMember },
|
||||||
|
});
|
||||||
|
if (response.success) {
|
||||||
|
dispatch(setUpdateAnnouncement(!update))
|
||||||
|
ToastAndroid.show("Berhasil menambahkan data", ToastAndroid.SHORT);
|
||||||
|
router.back();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaView>
|
<SafeAreaView>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
options={{
|
options={{
|
||||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
headerLeft: () => (
|
||||||
headerTitle: 'Tambah Pengumuman',
|
<ButtonBackHeader
|
||||||
headerTitleAlign: 'center',
|
onPress={() => {
|
||||||
headerRight: () => <ButtonSaveHeader category="create" onPress={() => {
|
router.back();
|
||||||
ToastAndroid.show('Berhasil menambah data', ToastAndroid.SHORT)
|
}}
|
||||||
router.push('/announcement')
|
/>
|
||||||
}} />
|
),
|
||||||
|
headerTitle: "Tambah Pengumuman",
|
||||||
|
headerTitleAlign: "center",
|
||||||
|
headerRight: () => (
|
||||||
|
<ButtonSaveHeader
|
||||||
|
disable={disableBtn}
|
||||||
|
category="create"
|
||||||
|
onPress={() => {
|
||||||
|
divisionMember.length == 0
|
||||||
|
? ToastAndroid.show("Anda belum memilih divisi", ToastAndroid.SHORT)
|
||||||
|
: handleCreate();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ScrollView>
|
<ScrollView>
|
||||||
<View style={[Styles.p15, Styles.mb100]}>
|
<View style={[Styles.p15, Styles.mb100]}>
|
||||||
<InputForm label="Judul" type="default" placeholder="Judul Pengumuman" required />
|
<InputForm
|
||||||
<InputForm label="Pengumuman" type="default" placeholder="Deskripsi Pengumuman" required />
|
label="Judul"
|
||||||
<ButtonSelect value="Pilih divisi penerima pengumuman" />
|
type="default"
|
||||||
{/* <ButtonForm
|
placeholder="Judul Pengumuman"
|
||||||
text="SIMPAN"
|
required
|
||||||
|
error={error.title}
|
||||||
|
errorText="Judul harus diisi"
|
||||||
|
onChange={(val) => validationForm("title", val)}
|
||||||
|
/>
|
||||||
|
<InputForm
|
||||||
|
label="Pengumuman"
|
||||||
|
type="default"
|
||||||
|
placeholder="Deskripsi Pengumuman"
|
||||||
|
required
|
||||||
|
error={error.desc}
|
||||||
|
errorText="Pengumuman harus diisi"
|
||||||
|
onChange={(val) => validationForm("desc", val)}
|
||||||
|
/>
|
||||||
|
<ButtonSelect
|
||||||
|
value="Pilih divisi penerima pengumuman"
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
AlertKonfirmasi({
|
setModalDivisi(true)
|
||||||
title: 'Konfirmasi',
|
}}
|
||||||
desc: 'Apakah anda yakin ingin menambahkan data?',
|
/>
|
||||||
onPress: () => {
|
|
||||||
ToastAndroid.show('Berhasil menambahkan data', ToastAndroid.SHORT)
|
{
|
||||||
router.push('/announcement')
|
divisionMember.length > 0
|
||||||
}
|
&&
|
||||||
})
|
<View style={[Styles.borderAll, Styles.round10, Styles.p10]}>
|
||||||
}} /> */}
|
{
|
||||||
|
divisionMember.map((item: { name: any; Division: any }, index: any) => {
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Text style={[Styles.textDefaultSemiBold]}>{item.name}</Text>
|
||||||
|
{
|
||||||
|
item.Division.map((division: any) => (
|
||||||
|
<View style={[Styles.rowItemsCenter, Styles.mv05]}>
|
||||||
|
<Entypo name="dot-single" size={24} color="black" />
|
||||||
|
<Text style={[Styles.textDefault]}>{division.name}</Text>
|
||||||
|
</View>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</View>
|
||||||
|
}
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
|
<ModalSelectMultiple
|
||||||
|
choose="dinas"
|
||||||
|
title="Pilih Divisi"
|
||||||
|
category="choose-division"
|
||||||
|
open={modalDivisi}
|
||||||
|
close={setModalDivisi}
|
||||||
|
onSelect={(val) => {
|
||||||
|
setDivisionMember(val)
|
||||||
|
setModalDivisi(false)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,43 @@ import ButtonBackHeader from "@/components/buttonBackHeader";
|
|||||||
import InputSearch from "@/components/inputSearch";
|
import InputSearch from "@/components/inputSearch";
|
||||||
import { ColorsStatus } from "@/constants/ColorsStatus";
|
import { ColorsStatus } from "@/constants/ColorsStatus";
|
||||||
import Styles from "@/constants/Styles";
|
import Styles from "@/constants/Styles";
|
||||||
|
import { apiGetAnnouncement } from "@/lib/api";
|
||||||
|
import { useAuthSession } from "@/providers/AuthProvider";
|
||||||
import { MaterialIcons } from "@expo/vector-icons";
|
import { MaterialIcons } from "@expo/vector-icons";
|
||||||
import { router, Stack } from "expo-router";
|
import { router, Stack } from "expo-router";
|
||||||
import { SafeAreaView, ScrollView, View } from "react-native";
|
import { useEffect, useState } from "react";
|
||||||
|
import { SafeAreaView, ScrollView, Text, View } from "react-native";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
id: string,
|
||||||
|
title: string,
|
||||||
|
desc: string,
|
||||||
|
createdAt: string
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export default function Announcement() {
|
export default function Announcement() {
|
||||||
|
const { token, decryptToken } = useAuthSession()
|
||||||
|
const [data, setData] = useState<Props[]>([])
|
||||||
|
const [search, setSearch] = useState('')
|
||||||
|
const entityUser = useSelector((state: any) => state.user)
|
||||||
|
const update = useSelector((state: any) => state.announcementUpdate)
|
||||||
|
|
||||||
|
async function handleLoad() {
|
||||||
|
try {
|
||||||
|
const hasil = await decryptToken(String(token?.current))
|
||||||
|
const response = await apiGetAnnouncement({ user: hasil, search: search })
|
||||||
|
setData(response.data)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
handleLoad()
|
||||||
|
}, [search, update])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaView>
|
<SafeAreaView>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
@@ -16,97 +48,36 @@ export default function Announcement() {
|
|||||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||||
headerTitle: 'Pengumuman',
|
headerTitle: 'Pengumuman',
|
||||||
headerTitleAlign: 'center',
|
headerTitleAlign: 'center',
|
||||||
headerRight: () => <HeaderRightAnnouncementList />
|
headerRight: () => entityUser.role != 'user' && entityUser.role != 'coadmin' ? <HeaderRightAnnouncementList /> : <></>
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ScrollView>
|
<ScrollView>
|
||||||
<View style={[Styles.p15, Styles.mb100]}>
|
<View style={[Styles.p15, Styles.mb100]}>
|
||||||
<InputSearch />
|
<InputSearch onChange={setSearch} />
|
||||||
<BorderBottomItem
|
{
|
||||||
onPress={() => {router.push('/announcement/7493')}}
|
data.length > 0
|
||||||
borderType="bottom"
|
?
|
||||||
icon={
|
data.map((item, index) => {
|
||||||
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
|
return (
|
||||||
<MaterialIcons name="campaign" size={25} color={'#384288'} />
|
<BorderBottomItem
|
||||||
</View>
|
key={index}
|
||||||
}
|
onPress={() => { router.push(`/announcement/${item.id}`) }}
|
||||||
title="Libur Nyepi"
|
borderType="bottom"
|
||||||
desc="Pengumuman terkait libur nyepi"
|
icon={
|
||||||
rightTopInfo="23 Mar 2025"
|
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
|
||||||
/>
|
<MaterialIcons name="campaign" size={25} color={'#384288'} />
|
||||||
<BorderBottomItem
|
</View>
|
||||||
onPress={() => {router.push('/announcement/7493')}}
|
}
|
||||||
borderType="bottom"
|
title={item.title}
|
||||||
icon={
|
desc={item.desc}
|
||||||
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
|
rightTopInfo={item.createdAt}
|
||||||
<MaterialIcons name="campaign" size={25} color={'#384288'} />
|
/>
|
||||||
</View>
|
)
|
||||||
}
|
})
|
||||||
title="Libur Nyepi"
|
:
|
||||||
desc="Pengumuman terkait libur nyepi"
|
<Text style={[Styles.textDefault, Styles.cGray, { textAlign: 'center' }]}>Tidak ada pengumuman</Text>
|
||||||
rightTopInfo="23 Mar 2025"
|
}
|
||||||
/>
|
|
||||||
<BorderBottomItem
|
|
||||||
onPress={() => {router.push('/announcement/7493')}}
|
|
||||||
borderType="bottom"
|
|
||||||
icon={
|
|
||||||
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
|
|
||||||
<MaterialIcons name="campaign" size={25} color={'#384288'} />
|
|
||||||
</View>
|
|
||||||
}
|
|
||||||
title="Libur Nyepi"
|
|
||||||
desc="Pengumuman terkait libur nyepi"
|
|
||||||
rightTopInfo="23 Mar 2025"
|
|
||||||
/>
|
|
||||||
<BorderBottomItem
|
|
||||||
onPress={() => {router.push('/announcement/7493')}}
|
|
||||||
borderType="bottom"
|
|
||||||
icon={
|
|
||||||
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
|
|
||||||
<MaterialIcons name="campaign" size={25} color={'#384288'} />
|
|
||||||
</View>
|
|
||||||
}
|
|
||||||
title="Libur Nyepi"
|
|
||||||
desc="Pengumuman terkait libur nyepi"
|
|
||||||
rightTopInfo="23 Mar 2025"
|
|
||||||
/>
|
|
||||||
<BorderBottomItem
|
|
||||||
onPress={() => {router.push('/announcement/7493')}}
|
|
||||||
borderType="bottom"
|
|
||||||
icon={
|
|
||||||
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
|
|
||||||
<MaterialIcons name="campaign" size={25} color={'#384288'} />
|
|
||||||
</View>
|
|
||||||
}
|
|
||||||
title="Libur Nyepi"
|
|
||||||
desc="Pengumuman terkait libur nyepi"
|
|
||||||
rightTopInfo="23 Mar 2025"
|
|
||||||
/>
|
|
||||||
<BorderBottomItem
|
|
||||||
onPress={() => {router.push('/announcement/7493')}}
|
|
||||||
borderType="bottom"
|
|
||||||
icon={
|
|
||||||
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
|
|
||||||
<MaterialIcons name="campaign" size={25} color={'#384288'} />
|
|
||||||
</View>
|
|
||||||
}
|
|
||||||
title="Libur Nyepi"
|
|
||||||
desc="Pengumuman terkait libur nyepi"
|
|
||||||
rightTopInfo="23 Mar 2025"
|
|
||||||
/>
|
|
||||||
<BorderBottomItem
|
|
||||||
onPress={() => {router.push('/announcement/7493')}}
|
|
||||||
borderType="bottom"
|
|
||||||
icon={
|
|
||||||
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
|
|
||||||
<MaterialIcons name="campaign" size={25} color={'#384288'} />
|
|
||||||
</View>
|
|
||||||
}
|
|
||||||
title="Libur Nyepi"
|
|
||||||
desc="Pengumuman terkait libur nyepi"
|
|
||||||
rightTopInfo="23 Mar 2025"
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import Styles from "@/constants/Styles"
|
import Styles from "@/constants/Styles"
|
||||||
|
import { apiGetDivisionGroup } from "@/lib/api"
|
||||||
|
import { useAuthSession } from "@/providers/AuthProvider"
|
||||||
import { AntDesign } from "@expo/vector-icons"
|
import { AntDesign } from "@expo/vector-icons"
|
||||||
import { useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
import { Pressable, Text, View } from "react-native"
|
import { Pressable, ScrollView, Text, ToastAndroid, View } from "react-native"
|
||||||
import { ButtonForm } from "./buttonForm"
|
import { ButtonForm } from "./buttonForm"
|
||||||
import DrawerBottom from "./drawerBottom"
|
import DrawerBottom from "./drawerBottom"
|
||||||
|
|
||||||
@@ -9,17 +11,97 @@ type Props = {
|
|||||||
open: boolean
|
open: boolean
|
||||||
close: (value: boolean) => void
|
close: (value: boolean) => void
|
||||||
title: string
|
title: string
|
||||||
category: 'share-division' | 'status-task'
|
category: 'share-division' | 'choose-division'
|
||||||
choose: string
|
choose: string
|
||||||
onSelect: (value: { val: string, label: string }[]) => void
|
onSelect: (value: any[]) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
type CheckedState = {
|
||||||
|
[key: string]: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type GroupData = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
Division: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ModalSelectMultiple({ open, close, title, category, choose, onSelect }: Props) {
|
export default function ModalSelectMultiple({ open, close, title, category, choose, onSelect }: Props) {
|
||||||
const [isChoose, setChoose] = useState(choose)
|
const [isChoose, setChoose] = useState(choose)
|
||||||
|
const { token, decryptToken } = useAuthSession()
|
||||||
|
const [data, setData] = useState<any>([])
|
||||||
|
const [checked, setChecked] = useState<CheckedState>({});
|
||||||
|
|
||||||
|
async function handleLoadChooseDivision() {
|
||||||
|
try {
|
||||||
|
const hasil = await decryptToken(String(token?.current))
|
||||||
|
const response = await apiGetDivisionGroup({ user: hasil })
|
||||||
|
setData(response.data)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (category == 'choose-division') {
|
||||||
|
handleLoadChooseDivision()
|
||||||
|
} else if (category == 'share-division') {
|
||||||
|
// handleLoadPosition()
|
||||||
|
}
|
||||||
|
}, [open]);
|
||||||
|
|
||||||
|
const handleCheck = (groupId: string, divisionId: string) => {
|
||||||
|
const newChecked = { ...checked };
|
||||||
|
if (newChecked[groupId]) {
|
||||||
|
if (newChecked[groupId].includes(divisionId)) {
|
||||||
|
newChecked[groupId] = newChecked[groupId].filter(item => item !== divisionId);
|
||||||
|
if (newChecked[groupId].length === 0) {
|
||||||
|
delete newChecked[groupId];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newChecked[groupId].push(divisionId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newChecked[groupId] = [divisionId];
|
||||||
|
}
|
||||||
|
setChecked(newChecked);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const handleGroupCheck = (groupId: string) => {
|
||||||
|
const newChecked = { ...checked };
|
||||||
|
if (newChecked[groupId]) {
|
||||||
|
delete newChecked[groupId];
|
||||||
|
} else {
|
||||||
|
if (data.find((item: { id: string }) => item.id === groupId)?.Division.length == 0) {
|
||||||
|
return ToastAndroid.show('Tidak ada divisi', ToastAndroid.SHORT)
|
||||||
|
}
|
||||||
|
newChecked[groupId] = data.find((item: { id: string }) => item.id === groupId)?.Division.map((item: { id: any }) => item.id) || [];
|
||||||
|
}
|
||||||
|
setChecked(newChecked);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
const selectedGroups: GroupData[] = [];
|
||||||
|
Object.keys(checked).forEach((groupId) => {
|
||||||
|
const group = data.find((item: { id: string }) => item.id === groupId);
|
||||||
|
if (group) {
|
||||||
|
selectedGroups.push({
|
||||||
|
id: group.id,
|
||||||
|
name: group.name,
|
||||||
|
Division: group.Division.filter((division: { id: string }) => checked[groupId].includes(division.id)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
onSelect(selectedGroups);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DrawerBottom animation="slide" isVisible={open} setVisible={close} title={title} height={75}>
|
<DrawerBottom animation="slide" isVisible={open} setVisible={close} title={title} height={75}>
|
||||||
<View>
|
<ScrollView style={[Styles.mb50]}>
|
||||||
{
|
{
|
||||||
category == 'share-division' ?
|
category == 'share-division' ?
|
||||||
<>
|
<>
|
||||||
@@ -41,11 +123,38 @@ export default function ModalSelectMultiple({ open, close, title, category, choo
|
|||||||
</Pressable>
|
</Pressable>
|
||||||
</>
|
</>
|
||||||
:
|
:
|
||||||
<></>
|
data.map((item: any, index: number) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Pressable key={index} style={[Styles.itemSelectModal]} onPress={() => { handleGroupCheck(item.id) }}>
|
||||||
|
<Text style={[Styles.textMediumSemiBold]}>{item.name}</Text>
|
||||||
|
{
|
||||||
|
checked[item.id] && checked[item.id].length === item.Division.length
|
||||||
|
? <AntDesign name="check" size={20} />
|
||||||
|
: (checked[item.id] && checked[item.id].length > 0 && checked[item.id].length < item.Division.length)
|
||||||
|
? <AntDesign name="minus" size={20} />
|
||||||
|
: <></>
|
||||||
|
}
|
||||||
|
</Pressable>
|
||||||
|
{
|
||||||
|
item.Division.map((child: any, v: number) => {
|
||||||
|
return (
|
||||||
|
<Pressable key={v} style={[Styles.itemSelectModal]} onPress={() => { handleCheck(item.id, child.id) }}>
|
||||||
|
<Text style={[Styles.ml10, Styles.textMediumNormal]}>{child.name}</Text>
|
||||||
|
{
|
||||||
|
checked[item.id] && checked[item.id].includes(child.id) && <AntDesign name="check" size={20} />
|
||||||
|
}
|
||||||
|
</Pressable>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
</View>
|
</ScrollView>
|
||||||
<View style={[Styles.absolute0, { width: '100%' }]}>
|
<View style={[Styles.absolute0, { width: '100%' }]}>
|
||||||
<ButtonForm text="Simpan" onPress={() => { onSelect([{ val: 'dinas', label: 'Dinas' }]) }} />
|
<ButtonForm text="PILIH" onPress={() => { handleSubmit() }} />
|
||||||
</View>
|
</View>
|
||||||
</DrawerBottom>
|
</DrawerBottom>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -74,6 +74,9 @@ const Styles = StyleSheet.create({
|
|||||||
mb30: {
|
mb30: {
|
||||||
marginBottom: 30
|
marginBottom: 30
|
||||||
},
|
},
|
||||||
|
mb50: {
|
||||||
|
marginBottom: 50
|
||||||
|
},
|
||||||
mb100: {
|
mb100: {
|
||||||
marginBottom: 100
|
marginBottom: 100
|
||||||
},
|
},
|
||||||
|
|||||||
14
lib/announcementUpdate.ts
Normal file
14
lib/announcementUpdate.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
|
const announcementUpdate = createSlice({
|
||||||
|
name: 'announcementUpdate',
|
||||||
|
initialState: false,
|
||||||
|
reducers: {
|
||||||
|
setUpdateAnnouncement: (state, action) => {
|
||||||
|
return action.payload;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const { setUpdateAnnouncement } = announcementUpdate.actions;
|
||||||
|
export default announcementUpdate.reducer;
|
||||||
19
lib/api.ts
19
lib/api.ts
@@ -203,3 +203,22 @@ export const apiAddMemberDiscussionGeneral = async ({ data, id }: { data: { user
|
|||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const apiGetAnnouncement = async ({ user, search }: { user: string, search: string }) => {
|
||||||
|
const response = await api.get(`mobile/announcement?user=${user}&search=${search}`);
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const apiGetDivisionGroup = async ({ user }: { user: string }) => {
|
||||||
|
const response = await api.get(`mobile/group/get-division?user=${user}`);
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const apiCreateAnnouncement = async ({ data }: { data: { title: string, desc: string, user: string, groups: any[] } }) => {
|
||||||
|
const response = await api.post(`/mobile/announcement/`, data)
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const apiGetAnnouncementOne = async ({ user, id }: { user: string, id: string }) => {
|
||||||
|
const response = await api.get(`mobile/announcement/${id}?user=${user}`);
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { configureStore } from '@reduxjs/toolkit';
|
import { configureStore } from '@reduxjs/toolkit';
|
||||||
|
import announcementUpdate from './announcementUpdate';
|
||||||
import bannerReducer from './bannerSlice';
|
import bannerReducer from './bannerSlice';
|
||||||
import discussionGeneralDetailUpdate from './discussionGeneralDetail';
|
import discussionGeneralDetailUpdate from './discussionGeneralDetail';
|
||||||
import entitiesReducer from './entitiesSlice';
|
import entitiesReducer from './entitiesSlice';
|
||||||
@@ -19,7 +20,8 @@ const store = configureStore({
|
|||||||
memberUpdate: memberUpdate,
|
memberUpdate: memberUpdate,
|
||||||
filterGroup: filterSlice,
|
filterGroup: filterSlice,
|
||||||
discussionGeneralDetailUpdate: discussionGeneralDetailUpdate,
|
discussionGeneralDetailUpdate: discussionGeneralDetailUpdate,
|
||||||
memberChoose: memberChoose
|
memberChoose: memberChoose,
|
||||||
|
announcementUpdate: announcementUpdate
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user