diff --git a/app/(application)/position/_layout.tsx b/app/(application)/position/_layout.tsx index e45844b..54ba994 100644 --- a/app/(application)/position/_layout.tsx +++ b/app/(application)/position/_layout.tsx @@ -9,22 +9,88 @@ import ModalSelect from "@/components/modalSelect" import SelectForm from "@/components/selectForm" import { Headers } from "@/constants/Headers" import Styles from "@/constants/Styles" +import { apiCreatePosition } from "@/lib/api" +import { setUpdatePosition } from "@/lib/positionSlice" +import { useAuthSession } from "@/providers/AuthProvider" import { AntDesign } from "@expo/vector-icons" import { router, Stack } from "expo-router" import { useState } from "react" import { ToastAndroid, View } from "react-native" +import { useDispatch, useSelector } from "react-redux" export default function RootLayout() { + const dispatch = useDispatch() + const update = useSelector((state: any) => state.positionUpdate) + const { token, decryptToken } = useAuthSession() + const entityUser = useSelector((state: any) => state.user) const [isVisible, setVisible] = useState(false) const [isVisibleTambah, setVisibleTambah] = useState(false) const [isFilter, setFilter] = useState(false) const [isSelect, setSelect] = useState(false) const [choose, setChoose] = useState({ val: '', label: '' }) + const [dataForm, setDataForm] = useState({ + name: "", + idGroup: "", + }) + const [error, setError] = useState({ + name: false, + idGroup: false + }); + + function validationForm(val: any, cat: 'name' | 'idGroup') { + if (cat === 'name') { + setDataForm({ ...dataForm, name: val }) + if (val == "") { + setError({ ...error, name: true }) + } else { + setError({ ...error, name: false }) + } + } else if (cat === "idGroup") { + setDataForm({ ...dataForm, idGroup: val }) + if (val == "") { + setError({ ...error, idGroup: true }) + } else { + setError({ ...error, idGroup: false }) + } + } + } + + function checkAll() { + let nilai = true + if (dataForm.name == "") { + setError(error => ({ ...error, name: true })) + nilai = false + } + + if ((entityUser.role == "supadmin" || entityUser.role == "developer") && (dataForm.idGroup == "" || String(dataForm.idGroup) == "null")) { + setError(error => ({ ...error, idGroup: true })) + nilai = false + } + + return nilai + } + + function onCheck() { + const check = checkAll() + if (!check) + return false + handleTambah() + } + + + async function handleTambah() { + try { + const hasil = await decryptToken(String(token?.current)) + const response = await apiCreatePosition({ user: hasil, name: dataForm.name, idGroup: dataForm.idGroup }) + dispatch(setUpdatePosition(!update)) + } catch (error) { + console.error(error) + } finally { + setVisibleTambah(false) + setVisible(false) + ToastAndroid.show('Berhasil menambahkan data', ToastAndroid.SHORT) + } - function handleTambah() { - setVisibleTambah(false) - setVisible(false) - ToastAndroid.show('Berhasil menambahkan data', ToastAndroid.SHORT) } return ( @@ -34,7 +100,7 @@ export default function RootLayout() { headerLeft: () => { router.back() }} />, headerTitle: 'Jabatan', headerTitleAlign: 'center', - headerRight: () => { setVisible(true) }} /> + headerRight: () => entityUser.role != 'user' ? { setVisible(true) }} /> : <> }} /> @@ -48,25 +114,47 @@ export default function RootLayout() { setVisibleTambah(true) }} /> - } - title="Filter" - onPress={() => { setFilter(true) }} - /> + { + (entityUser.role == 'supadmin' || entityUser.role == 'developer') && + } + title="Filter" + onPress={() => { setFilter(true) }} + /> + } - - + + - { - setVisibleTambah(false) - setSelect(true) - }} /> - + { + (entityUser.role == 'supadmin' || entityUser.role == 'developer') && + { + setVisibleTambah(false) + setSelect(true) + }} + error={error.idGroup} + errorText="Lembaga Desa harus diisi" + /> + } + { validationForm(value, 'name') }} + error={error.name} + errorText="Nama jabatan harus diisi" + /> - - { handleTambah() }} /> + + { onCheck() }} /> @@ -80,12 +168,12 @@ export default function RootLayout() { category="group" close={setSelect} onSelect={(value) => { + validationForm(value.val, 'idGroup') setChoose(value) setSelect(false) setVisibleTambah(true) }} title="Lembaga Desa" - choose={choose.val} open={isSelect} /> diff --git a/app/(application)/position/index.tsx b/app/(application)/position/index.tsx index 5a235fe..f24d018 100644 --- a/app/(application)/position/index.tsx +++ b/app/(application)/position/index.tsx @@ -8,15 +8,49 @@ import InputSearch from "@/components/inputSearch"; import MenuItemRow from "@/components/menuItemRow"; import { ColorsStatus } from "@/constants/ColorsStatus"; import Styles from "@/constants/Styles"; +import { apiGetPosition } from "@/lib/api"; +import { useAuthSession } from "@/providers/AuthProvider"; import { AntDesign, Feather, MaterialCommunityIcons } from "@expo/vector-icons"; import { router, useLocalSearchParams } from "expo-router"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { SafeAreaView, ScrollView, Text, ToastAndroid, View } from "react-native"; +import { useDispatch, useSelector } from "react-redux"; + +type Props = { + name: string; + idGroup: string; + group: string; + id: string; + isActive: boolean +} export default function Index() { - const { active } = useLocalSearchParams<{ active?: string }>() + const { token, decryptToken } = useAuthSession() + const entityUser = useSelector((state: any) => state.user) + const { active, group } = useLocalSearchParams<{ active?: string, group?: string }>() const [isModal, setModal] = useState(false) const [isVisibleEdit, setVisibleEdit] = useState(false) + const [data, setData] = useState([]) + const [search, setSearch] = useState('') + const [nameGroup, setNameGroup] = useState('') + + const dispatch = useDispatch() + const update = useSelector((state: any) => state.positionUpdate) + + async function handleLoad() { + try { + const hasil = await decryptToken(String(token?.current)) + const response = await apiGetPosition({ user: hasil, active: String(active), search: search, group: String(group) }) + setData(response.data) + setNameGroup(response.filter.name) + } catch (error) { + console.error(error) + } + } + + useEffect(() => { + handleLoad() + }, [active, search, group, update]) function handleEdit() { setVisibleEdit(false) @@ -44,77 +78,35 @@ export default function Index() { icon={} n={2} /> - - - Filter : Dinas - + + { + (entityUser.role == "supadmin" || entityUser.role == "developer") && + + Filter : {nameGroup} + + } - { setModal(true) }} - borderType="all" - icon={ - - - - } - title="Anggota" - subtitle="Dinas" - /> - { setModal(true) }} - borderType="all" - icon={ - - - - } - title="Bendahara" - subtitle="Dinas" - /> - { setModal(true) }} - borderType="all" - icon={ - - - - } - title="Ketua" - subtitle="Dinas" - /> - { setModal(true) }} - borderType="all" - icon={ - - - - } - title="Sekretaris" - subtitle="Dinas" - /> - { setModal(true) }} - borderType="all" - icon={ - - - - } - title="Kepala TU" - subtitle="Dinas" - /> - { setModal(true) }} - borderType="all" - icon={ - - - - } - title="Wakil Kepala TU" - subtitle="Dinas" - /> + { + data.length > 0 ? + data.map((item, index) => { + return ( + { setModal(true) }} + borderType="all" + icon={ + + + + } + title={item.name} + subtitle={item.group} + /> + ) + }) + : + Tidak ada data + } diff --git a/components/modalFilter.tsx b/components/modalFilter.tsx index b594800..2b6045c 100644 --- a/components/modalFilter.tsx +++ b/components/modalFilter.tsx @@ -1,9 +1,14 @@ -import { Pressable, Text, View } from "react-native" -import DrawerBottom from "./drawerBottom" -import { AntDesign } from "@expo/vector-icons" import Styles from "@/constants/Styles" -import { ButtonForm } from "./buttonForm" +import { apiGetGroup } from "@/lib/api" +import { setEntityFilterGroup } from "@/lib/filterSlice" +import { useAuthSession } from "@/providers/AuthProvider" +import { AntDesign } from "@expo/vector-icons" import { router } from "expo-router" +import { useEffect, useState } from "react" +import { Pressable, ScrollView, Text, View } from "react-native" +import { useDispatch, useSelector } from "react-redux" +import { ButtonForm } from "./buttonForm" +import DrawerBottom from "./drawerBottom" type Props = { @@ -13,31 +18,50 @@ type Props = { } export default function ModalFilter({ open, close, page }: Props) { + const { token, decryptToken } = useAuthSession() + const dispatch = useDispatch() + const entities = useSelector((state: any) => state.filterGroup) + const [chooseGroup, setChooseGroup] = useState('') + + async function handleLoad() { + const hasil = await decryptToken(String(token?.current)) + const response = await apiGetGroup({ active: 'true', user: hasil, search: '' }) + dispatch(setEntityFilterGroup(response.data)) + } + + useEffect(() => { + if (entities.length == 0) { + handleLoad() + } + }, [dispatch]); + + + + return ( - - - Dinas - - - - Adat - - - Karang Taruna - - - PKK - - + + + { + entities.map((item: any, index: any) => ( + { setChooseGroup(item.id) }}> + {item.name} + { + chooseGroup == item.id && + } + + )) + } + + { close(false) page == 'project' ? router.push(`/${page}?status=0`) : - router.push(`/${page}?active=true`) + router.push(`/${page}?active=true&group=${chooseGroup}`) }} /> diff --git a/components/modalSelect.tsx b/components/modalSelect.tsx index 78b49dc..f754720 100644 --- a/components/modalSelect.tsx +++ b/components/modalSelect.tsx @@ -1,62 +1,78 @@ -import { Pressable, Text, View } from "react-native" -import DrawerBottom from "./drawerBottom" import Styles from "@/constants/Styles" +import { apiGetGroup } from "@/lib/api" +import { setEntityFilterGroup } from "@/lib/filterSlice" +import { useAuthSession } from "@/providers/AuthProvider" import { AntDesign } from "@expo/vector-icons" -import { useState } from "react" +import { useEffect, useState } from "react" +import { Pressable, ScrollView, Text, View } from "react-native" +import { useDispatch, useSelector } from "react-redux" +import DrawerBottom from "./drawerBottom" type Props = { open: boolean close: (value: boolean) => void title: string category: 'group' | 'status-task' - choose: string + onSelect: (value: { val: string, label: string }) => void } -export default function ModalSelect({ open, close, title, category, choose, onSelect }: Props) { - const [isChoose, setChoose] = useState(choose) +export default function ModalSelect({ open, close, title, category, onSelect }: Props) { + // const [isChoose, setChoose] = useState(choose) + const { token, decryptToken } = useAuthSession() + const dispatch = useDispatch() + const entitiesGroup = useSelector((state: any) => state.filterGroup) + const [chooseValue, setChooseValue] = useState({ val: '', label: '' }) + + async function handleLoadGroup() { + const hasil = await decryptToken(String(token?.current)) + const response = await apiGetGroup({ active: 'true', user: hasil, search: '' }) + dispatch(setEntityFilterGroup(response.data)) + } + + useEffect(() => { + if (entitiesGroup.length == 0 && category == 'group') { + handleLoadGroup() + } + }, [dispatch]); + + function onChoose(val: string, label: string) { + setChooseValue({ val, label }) + onSelect({ val, label }) + close(false) + } return ( - - { - category == 'group' ? - <> - { - onSelect({ val: 'dinas', label: 'Dinas' }) - setChoose('dinas') - close(false) - }}> - Dinas - - - - Adat - - - Karang Taruna - - - PKK - - - : - <> - { - onSelect({ val: 'blm-dikerjakan', label: 'Belum Dikerjakan' }) - setChoose('blm-dikerjakan') - close(false) - }}> - Belum Dikerjakan - - - - Selesai - - - } + + + { + category == 'group' ? + entitiesGroup.map((item: any, index: any) => ( + { onChoose(item.id, item.name) }}> + {item.name} + { + chooseValue.val == item.id && + } + + )) + : + <> + { + onSelect({ val: 'blm-dikerjakan', label: 'Belum Dikerjakan' }) + close(false) + }}> + Belum Dikerjakan + + + + Selesai + + + } - + + ) } \ No newline at end of file diff --git a/components/sectionTanggalTugas.tsx b/components/sectionTanggalTugas.tsx index 5b44592..12f5f21 100644 --- a/components/sectionTanggalTugas.tsx +++ b/components/sectionTanggalTugas.tsx @@ -76,7 +76,6 @@ export default function SectionTanggalTugas({ category }: Props) { ToastAndroid.show('Berhasil mengubah data', ToastAndroid.SHORT) }} title="Status" - choose={choose.val} open={isSelect} /> diff --git a/lib/api.ts b/lib/api.ts index 4bc98cc..86d4491 100644 --- a/lib/api.ts +++ b/lib/api.ts @@ -81,6 +81,20 @@ export const apiDeleteGroup = async (data: { user: string, isActive: boolean }, }); }; +export const apiGetPosition = async ({ user, active, search, group }: { user: string, active: string, search: string, group?: string }) => { + const response = await api.get(`mobile/position?user=${user}&active=${active}&group=${group}&search=${search}`); + return response.data; +}; + +export const apiCreatePosition = async (data: { user: string, name: string, idGroup: string }) => { + await api.post('mobile/position', data).then(response => { + return response.data; + }) + .catch(error => { + console.error('Error:', error); + }); +}; + // export const updateEntityById = async (id: any, updatedEntity: any) => { // const response = await api.put(`/entities/${id}`, updatedEntity); diff --git a/lib/filterSlice.ts b/lib/filterSlice.ts new file mode 100644 index 0000000..3461914 --- /dev/null +++ b/lib/filterSlice.ts @@ -0,0 +1,14 @@ +import { createSlice } from '@reduxjs/toolkit'; + +const filterSlice = createSlice({ + name: 'filterGroup', + initialState: [], + reducers: { + setEntityFilterGroup: (state, action) => { + return action.payload; + }, + }, +}); + +export const { setEntityFilterGroup } = filterSlice.actions; +export default filterSlice.reducer; \ No newline at end of file diff --git a/lib/positionSlice.ts b/lib/positionSlice.ts new file mode 100644 index 0000000..c70c707 --- /dev/null +++ b/lib/positionSlice.ts @@ -0,0 +1,14 @@ +import { createSlice } from '@reduxjs/toolkit'; + +const positionUpdate = createSlice({ + name: 'positionUpdate', + initialState: false, + reducers: { + setUpdatePosition: (state, action) => { + return action.payload; + }, + }, +}); + +export const { setUpdatePosition } = positionUpdate.actions; +export default positionUpdate.reducer; \ No newline at end of file diff --git a/lib/store.ts b/lib/store.ts index 4314df1..9138056 100644 --- a/lib/store.ts +++ b/lib/store.ts @@ -1,7 +1,9 @@ import { configureStore } from '@reduxjs/toolkit'; import bannerReducer from './bannerSlice'; import entitiesReducer from './entitiesSlice'; +import filterSlice from './filterSlice'; import groupUpdate from './groupSlice'; +import positionUpdate from './positionSlice'; import userReducer from './userSlice'; @@ -10,7 +12,9 @@ const store = configureStore({ entities: entitiesReducer, banner: bannerReducer, user: userReducer, - groupUpdate: groupUpdate + groupUpdate: groupUpdate, + positionUpdate: positionUpdate, + filterGroup: filterSlice, } });