From 51f8cb78f546f52b6053132fc09a1da4f514311e Mon Sep 17 00:00:00 2001 From: amel Date: Tue, 27 May 2025 17:44:05 +0800 Subject: [PATCH] upd: division Deskripsi: - tambah divisi nb: blm selesai No Issues --- app/(application)/division/create.tsx | 143 +++++++++++++----- .../division/create/add-admin-division.tsx | 110 ++++++++++++++ .../division/create/add-member.tsx | 136 +++++++++++++++++ components/buttonNextHeader.tsx | 20 +++ lib/api.ts | 6 + lib/divisionCreate.ts | 20 +++ lib/store.ts | 2 + 7 files changed, 402 insertions(+), 35 deletions(-) create mode 100644 app/(application)/division/create/add-admin-division.tsx create mode 100644 app/(application)/division/create/add-member.tsx create mode 100644 components/buttonNextHeader.tsx create mode 100644 lib/divisionCreate.ts diff --git a/app/(application)/division/create.tsx b/app/(application)/division/create.tsx index f4b1bed..29166e1 100644 --- a/app/(application)/division/create.tsx +++ b/app/(application)/division/create.tsx @@ -1,49 +1,122 @@ -import ButtonBackHeader from "@/components/buttonBackHeader" -import ButtonSaveHeader from "@/components/buttonSaveHeader" -import ButtonSelect from "@/components/buttonSelect" -import { InputForm } from "@/components/inputForm" -import SelectForm from "@/components/selectForm" -import Styles from "@/constants/Styles" -import { router, Stack } from "expo-router" -import { useState } from "react" -import { SafeAreaView, ScrollView, ToastAndroid, View } from "react-native" +import ButtonBackHeader from "@/components/buttonBackHeader"; +import ButtonNextHeader from "@/components/buttonNextHeader"; +import { InputForm } from "@/components/inputForm"; +import ModalSelect from "@/components/modalSelect"; +import SelectForm from "@/components/selectForm"; +import Styles from "@/constants/Styles"; +import { setFormCreateDivision } from "@/lib/divisionCreate"; +import { router, Stack } from "expo-router"; +import { useState } from "react"; +import { SafeAreaView, ScrollView, View } from "react-native"; +import { useDispatch, useSelector } from "react-redux"; export default function CreateDivision() { - const [chooseGroup, setChooseGroup] = useState({ val: '', label: '' }) + const [isSelect, setSelect] = useState(false); + const [chooseGroup, setChooseGroup] = useState({ val: "", label: "" }); + const dispatch = useDispatch(); + const update = useSelector((state: any) => state.divisionCreate); + const [error, setError] = useState({ + idGroup: false, + name: false, + }); + const [dataForm, setDataForm] = useState({ + idGroup: "", + name: "", + desc: "", + }); + + function validationForm(cat: string, val: any, label?: string) { + if (cat == "group") { + setChooseGroup({ val, label: String(label) }); + dispatch(setFormCreateDivision({ ...update, member: [], admin: [] })); + setDataForm({ ...dataForm, idGroup: val }); + if (val == "" || val == "null") { + setError((error) => ({ ...error, group: true })); + } else { + setError((error) => ({ ...error, group: false })); + } + } else if (cat == "name") { + setDataForm({ ...dataForm, name: val }); + if (val == "" || val == "null") { + setError((error) => ({ ...error, name: true })); + } else { + setError((error) => ({ ...error, name: false })); + } + } else if (cat == "desc") { + setDataForm({ ...dataForm, desc: val }); + if (val == "" || val == "null") { + setError((error) => ({ ...error, desc: true })); + } else { + setError((error) => ({ ...error, desc: false })); + } + } + } + + function handleSetData() { + dispatch(setFormCreateDivision({ data: dataForm })) + router.push(`./create/add-member`) + } return ( { router.back() }} />, - headerTitle: 'Tambah Divisi', - headerTitleAlign: 'center', - headerRight: () => { - ToastAndroid.show('Berhasil menambahkan data', ToastAndroid.SHORT) - router.push('/division') - }} /> + headerLeft: () => ( + { + router.back(); + }} + /> + ), + headerTitle: "Tambah Divisi", + headerTitleAlign: "center", + headerRight: () => ( + { handleSetData() }} + disable={error.idGroup || error.name || chooseGroup.val == "" || chooseGroup.val == "null" || dataForm.name == "" || dataForm.name == "null"} + /> + ), }} /> - { }} /> - - - - {/* { - AlertKonfirmasi({ - title: 'Konfirmasi', - desc: 'Apakah anda yakin ingin menambahkan data?', - onPress: () => { - ToastAndroid.show('Berhasil menambahkan data', ToastAndroid.SHORT) - router.push('/division/123') - } - }) - }} /> */} + { setSelect(true) }} + /> + validationForm('name', val)} + error={error.name} + errorText="Nama divisi tidak boleh kosong" + /> + setDataForm({ ...dataForm, desc: val })} + /> + + { + validationForm('group', value.val, value.label); + }} + title="Lembaga Desa" + open={isSelect} + valChoose={chooseGroup.val} + /> - ) -} \ No newline at end of file + ); +} diff --git a/app/(application)/division/create/add-admin-division.tsx b/app/(application)/division/create/add-admin-division.tsx new file mode 100644 index 0000000..58fe5d2 --- /dev/null +++ b/app/(application)/division/create/add-admin-division.tsx @@ -0,0 +1,110 @@ +import ButtonBackHeader from "@/components/buttonBackHeader"; +import ButtonSaveHeader from "@/components/buttonSaveHeader"; +import ImageUser from "@/components/imageNew"; +import Styles from "@/constants/Styles"; +import { setUpdateDivision } from "@/lib/divisionUpdate"; +import { useAuthSession } from "@/providers/AuthProvider"; +import { AntDesign } from "@expo/vector-icons"; +import { router, Stack, useLocalSearchParams } from "expo-router"; +import { useEffect, useState } from "react"; +import { Pressable, SafeAreaView, ScrollView, Text, ToastAndroid, View } from "react-native"; +import { useDispatch, useSelector } from "react-redux"; + +type Props = { + idUser: string, + name: string, + img: string +} + +export default function CreateDivisionAddAdmin() { + const { token, decryptToken } = useAuthSession() + const { id } = useLocalSearchParams<{ id: string }>() + const [dataOld, setDataOld] = useState([]) + const [data, setData] = useState([]) + const [selectMember, setSelectMember] = useState([]) + const update = useSelector((state: any) => state.divisionCreate) + const dispatch = useDispatch() + + async function handleLoadMember() { + setData(update.member) + } + + useEffect(() => { + handleLoadMember() + }, []) + + function onChoose(val: string, label: string, img?: string) { + if (selectMember.some((i: any) => i.idUser == val)) { + setSelectMember(selectMember.filter((i: any) => i.idUser != val)) + } else { + setSelectMember([...selectMember, { idUser: val, name: label, img }]) + } + } + + async function handleAddMember() { + try { + dispatch(setUpdateDivision({ ...update, admin: selectMember })) + // router.push(`./add-admin-division`) + } catch (error) { + console.error(error) + ToastAndroid.show('Gagal menambahkan anggota', ToastAndroid.SHORT) + } + } + + + return ( + + { router.back() }} />, + headerTitle: 'Pilih Admin Divisi', + headerTitleAlign: 'center', + headerRight: () => ( + 0 ? false : true} + onPress={() => { + handleAddMember() + }} + /> + ) + }} + /> + + + { + data.length > 0 ? + data.map((item: any, index: any) => { + const found = dataOld.some((i: any) => i.idUser == item.id) + return ( + { + !found && onChoose(item.id, item.name, item.img) + }} + > + + + + {item.name} + { + found && sudah menjadi anggota + } + + + { + selectMember.some((i: any) => i.idUser == item.id) && + } + + ) + } + ) + : + Tidak ada data + } + + + + ) +} \ No newline at end of file diff --git a/app/(application)/division/create/add-member.tsx b/app/(application)/division/create/add-member.tsx new file mode 100644 index 0000000..689665c --- /dev/null +++ b/app/(application)/division/create/add-member.tsx @@ -0,0 +1,136 @@ +import ButtonBackHeader from "@/components/buttonBackHeader"; +import ButtonNextHeader from "@/components/buttonNextHeader"; +import ImageUser from "@/components/imageNew"; +import ImageWithLabel from "@/components/imageWithLabel"; +import InputSearch from "@/components/inputSearch"; +import Styles from "@/constants/Styles"; +import { apiGetUser } from "@/lib/api"; +import { setUpdateDivision } from "@/lib/divisionUpdate"; +import { useAuthSession } from "@/providers/AuthProvider"; +import { AntDesign } from "@expo/vector-icons"; +import { router, Stack, useLocalSearchParams } from "expo-router"; +import { useEffect, useState } from "react"; +import { Pressable, SafeAreaView, ScrollView, Text, View } from "react-native"; +import { useDispatch, useSelector } from "react-redux"; + +type Props = { + idUser: string, + name: string, + img: string +} + +export default function CreateDivisionAddMember() { + const { token, decryptToken } = useAuthSession() + const { id } = useLocalSearchParams<{ id: string }>() + const [dataOld, setDataOld] = useState([]) + const [data, setData] = useState([]) + const [selectMember, setSelectMember] = useState([]) + const [search, setSearch] = useState('') + const update = useSelector((state: any) => state.divisionCreate) + const dispatch = useDispatch() + + + async function handleLoadMember() { + const hasil = await decryptToken(String(token?.current)) + const response = await apiGetUser({ user: hasil, active: "true", search: search, group: String(update.data.idGroup) }) + setData(response.data.filter((i: any) => i.idUserRole != 'supadmin')) + if (update.member.length > 0) { + setSelectMember(update.member) + } + } + + useEffect(() => { + handleLoadMember() + }, [search]) + + function onChoose(val: string, label: string, img?: string) { + if (selectMember.some((i: any) => i.idUser == val)) { + setSelectMember(selectMember.filter((i: any) => i.idUser != val)) + } else { + setSelectMember([...selectMember, { idUser: val, name: label, img }]) + } + } + + async function handleAddMember() { + dispatch(setUpdateDivision({ ...update, member: selectMember })) + router.push(`./add-admin-division`) + } + + + return ( + + { router.back() }} />, + headerTitle: 'Pilih Anggota', + headerTitleAlign: 'center', + headerRight: () => ( + 0 ? false : true} + onPress={() => { handleAddMember() }} + /> + ) + }} + /> + + setSearch(val)} value={search} /> + + { + selectMember.length > 0 + ? + + + { + selectMember.map((item: any, index: any) => ( + onChoose(item.idUser, item.name, item.img)} + /> + )) + } + + + + : + Tidak ada member yang dipilih + } + + + { + data.length > 0 ? + data.map((item: any, index: any) => { + const found = dataOld.some((i: any) => i.idUser == item.id) + return ( + { + !found && onChoose(item.id, item.name, item.img) + }} + > + + + + {item.name} + { + found && sudah menjadi anggota + } + + + { + selectMember.some((i: any) => i.idUser == item.id) && + } + + ) + } + ) + : + Tidak ada data + } + + + + ) +} \ No newline at end of file diff --git a/components/buttonNextHeader.tsx b/components/buttonNextHeader.tsx new file mode 100644 index 0000000..29e5ad2 --- /dev/null +++ b/components/buttonNextHeader.tsx @@ -0,0 +1,20 @@ +import { Feather } from "@expo/vector-icons" +import { ButtonHeader } from "./buttonHeader" + +type Props = { + onPress?: () => void + disable?: boolean +} + +export default function ButtonNextHeader({ onPress, disable }: Props) { + return ( + <> + } + onPress={() => { + !disable && onPress && onPress() + }} + /> + + ) +} \ No newline at end of file diff --git a/lib/api.ts b/lib/api.ts index 0eb264e..ded905d 100644 --- a/lib/api.ts +++ b/lib/api.ts @@ -399,6 +399,12 @@ export const apiGetDivisionMember = async ({ user, id, search }: { user: string, return response.data; }; +export const apiCreateDivision = async (data: { data: { idGroup: string, name: string, desc: string }, member: [], admin: string[] }) => { + const response = await api.post(`/mobile/division`, data) + return response.data; +}; + + export const apiGetDiscussion = async ({ user, search, division, active }: { user: string, search: string, division: string, active?: string }) => { const response = await api.get(`mobile/discussion?user=${user}&active=${active}&search=${search}&division=${division}`); return response.data; diff --git a/lib/divisionCreate.ts b/lib/divisionCreate.ts new file mode 100644 index 0000000..070b4bb --- /dev/null +++ b/lib/divisionCreate.ts @@ -0,0 +1,20 @@ +import { createSlice } from '@reduxjs/toolkit'; + +const divisionCreate = createSlice({ + name: 'divisionCreate', + initialState: { + data: { + idGroup: "", + name: "", + desc: "", + }, member: [], admin: [], + }, + reducers: { + setFormCreateDivision: (state, action) => { + return action.payload; + }, + }, +}); + +export const { setFormCreateDivision } = divisionCreate.actions; +export default divisionCreate.reducer; \ No newline at end of file diff --git a/lib/store.ts b/lib/store.ts index 3dbd455..a535137 100644 --- a/lib/store.ts +++ b/lib/store.ts @@ -4,6 +4,7 @@ import bannerReducer from './bannerSlice'; import calendarUpdate from './calendarUpdate'; import discussionGeneralDetailUpdate from './discussionGeneralDetail'; import discussionUpdate from './discussionUpdate'; +import divisionCreate from './divisionCreate'; import divisionUpdate from './divisionUpdate'; import entitiesReducer from './entitiesSlice'; import filterSlice from './filterSlice'; @@ -34,6 +35,7 @@ const store = configureStore({ discussionUpdate: discussionUpdate, calendarUpdate: calendarUpdate, taskUpdate: taskUpdate, + divisionCreate: divisionCreate, } });