From a253adca357582a179716cae60078ddb503ad32f Mon Sep 17 00:00:00 2001 From: amel Date: Mon, 28 Apr 2025 16:37:01 +0800 Subject: [PATCH] upd: home Deskripsi: - integrasi api kegiatan terupdate - integrasi api divisi teraktif - integrasi api progres kegiatan - integrasi api jumlah dokumen - integrasi api event hari ini - integrasi api diskusi No Issues --- app/(application)/banner/create.tsx | 46 +++++++++++++------- app/(application)/banner/index.tsx | 57 ++++++++++--------------- components/home/chartDokumenHome.tsx | 39 ++++++++++++++++- components/home/chartProgresHome.tsx | 63 ++++++++++++++++++++++++---- components/home/discussionHome.tsx | 42 +++++++++++++++++-- components/home/divisionHome.tsx | 33 +++++++++++++-- components/home/eventHome.tsx | 46 +++++++++++++++++++- components/home/projectHome.tsx | 57 +++++++++++++++++++++---- constants/Styles.ts | 12 ++++++ lib/api.ts | 21 ++++++++-- 10 files changed, 337 insertions(+), 79 deletions(-) diff --git a/app/(application)/banner/create.tsx b/app/(application)/banner/create.tsx index 68d9ff4..bb555ce 100644 --- a/app/(application)/banner/create.tsx +++ b/app/(application)/banner/create.tsx @@ -2,14 +2,22 @@ import ButtonBackHeader from "@/components/buttonBackHeader"; import ButtonSaveHeader from "@/components/buttonSaveHeader"; import { InputForm } from "@/components/inputForm"; import Styles from "@/constants/Styles"; +import { apiCreateBanner } from "@/lib/api"; +import { addEntity } from "@/lib/bannerSlice"; +import { useAuthSession } from "@/providers/AuthProvider"; import { Entypo } from "@expo/vector-icons"; import * as ImagePicker from 'expo-image-picker'; import { router, Stack } from "expo-router"; import { useState } from "react"; import { Image, Pressable, SafeAreaView, ScrollView, Text, View } from "react-native"; +import { useDispatch } from "react-redux"; export default function CreateBanner() { + const { decryptToken, token } = useAuthSession() + const dispatch = useDispatch() const [selectedImage, setSelectedImage] = useState(undefined) + const [imgForm, setImgForm] = useState() + const [title, setTitle] = useState('') const pickImageAsync = async () => { let result = await ImagePicker.launchImageLibraryAsync({ @@ -20,11 +28,31 @@ export default function CreateBanner() { if (!result.canceled) { setSelectedImage(result.assets[0].uri); + setImgForm(result.assets[0]) } else { alert('Tidak ada gambar yang dipilih'); } }; + + const handleCreateEntity = async () => { + const hasil = await decryptToken(String(token?.current)) + const fd = new FormData() + fd.append("file", JSON.stringify({ + uri: imgForm.uri, + type: 'image/jpeg', // or response.assets[0].type + name: imgForm.fileName, + })) + fd.append("data", JSON.stringify( + { + title: title, + user: hasil + } + )) + const createdEntity = await apiCreateBanner(fd); + dispatch(addEntity(createdEntity)); + }; + return ( { router.back() }} />, headerTitle: 'Tambah Banner', headerTitleAlign: 'center', - headerRight: () => + headerRight: () => { handleCreateEntity() }} /> }} /> @@ -47,25 +75,13 @@ export default function CreateBanner() { - Mohon unggah gambar dalam resolusi 1535 x 450 piksel untuk memastikan + Mohon unggah gambar dalam resolusi 1535 x 450 pixel untuk memastikan ) } - - {/* { - AlertKonfirmasi({ - title: 'Konfirmasi', - desc: 'Apakah anda yakin ingin menambahkan data?', - onPress: () => { - ToastAndroid.show('Berhasil menambahkan data', ToastAndroid.SHORT) - router.push('/banner') - } - }) - }} /> */} + diff --git a/app/(application)/banner/index.tsx b/app/(application)/banner/index.tsx index 27bf918..8422d2c 100644 --- a/app/(application)/banner/index.tsx +++ b/app/(application)/banner/index.tsx @@ -9,9 +9,13 @@ import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons" import { router, Stack } from "expo-router" import { useState } from "react" import { Image, SafeAreaView, ScrollView, ToastAndroid, View } from "react-native" +import { useSelector } from "react-redux" export default function BannerList() { const [isModal, setModal] = useState(false) + const entities = useSelector((state: any) => state.banner) + const [dataId, setDataId] = useState('') + const [dataStorage, setDataStorage] = useState('') return ( @@ -26,39 +30,24 @@ export default function BannerList() { - { setModal(true) }} - borderType="all" - icon={ - - } - title="Banner 1" - /> - { setModal(true) }} - borderType="all" - icon={ - - } - title="Banner 2" - /> - { setModal(true) }} - borderType="all" - icon={ - - } - title="Banner 3" - /> + {entities.map((index: any, key: number) => ( + { + setDataId(index.id) + setDataStorage(index.image) + setModal(true) + }} + borderType="all" + icon={ + + } + title={index.title} + /> + ))} @@ -69,7 +58,7 @@ export default function BannerList() { title="Edit" onPress={() => { setModal(false) - router.push('/banner/784') + router.push(`/banner/${dataId}`) }} /> ([]) + const [maxValue, setMaxValue] = useState(5) const barData = [ { value: 23, label: 'Gambar', frontColor: '#fac858' }, { value: 12, label: 'Dokumen', frontColor: '#92cc76' }, ]; const width = Dimensions.get("window").width; + + async function handleData() { + try { + const hasil = await decryptToken(String(token?.current)) + const response = await apiGetDataHome({ cat: "dokumen", user: hasil }) + const maxValue = response.data.reduce((max: number, obj: { value: number; }) => Math.max(max, obj.value), -Infinity); + const roundUp = Math.ceil(maxValue / 10) * 10 + setMaxValue(roundUp) + const convertedArray = response.data.map((item: { color: any; label: any; value: any; }) => ({ + frontColor: item.color, + label: item.label, + value: Number(item.value) + })); + setData(convertedArray) + } catch (error) { + console.error(error) + } + } + + useEffect(() => { + handleData() + }, []); + return ( JUMLAH DOKUMEN @@ -16,8 +51,8 @@ export default function ChartDokumenHome() { showFractionalValues={false} showYAxisIndices noOfSections={4} - maxValue={25} - data={barData} + maxValue={maxValue} + data={data} isAnimated width={width - 140} barWidth={width * 0.25} diff --git a/components/home/chartProgresHome.tsx b/components/home/chartProgresHome.tsx index d8a39dd..933eb5b 100644 --- a/components/home/chartProgresHome.tsx +++ b/components/home/chartProgresHome.tsx @@ -1,20 +1,44 @@ import Styles from "@/constants/Styles"; +import { apiGetDataHome } from "@/lib/api"; +import { useAuthSession } from "@/providers/AuthProvider"; +import { useEffect, useState } from "react"; import { Text, View } from "react-native"; import { PieChart } from "react-native-gifted-charts"; +type Props = { + value: number; + text: string; + color: string; +}[] + export default function ChartProgresHome() { - const pieData = [ - { value: 54, text: "54%", color: '#177AD5' }, - { value: 40, text: "40%", color: '#92cc76' }, - { value: 20, text: "20%", color: '#ED6665' }, - { value: 0, text: "0%", color: '#fac858' }, - ]; + const { decryptToken, token } = useAuthSession() + const [data, setData] = useState([]) + + async function handleData() { + try { + const hasil = await decryptToken(String(token?.current)) + const response = await apiGetDataHome({ cat: "progress", user: hasil }) + const convertedArray = response.data.map((item: { color: any; text: any; value: any; }) => ({ + color: item.color, + text: item.text, + value: Number(item.value) + })); + setData(convertedArray) + } catch (error) { + console.error(error) + } + } + + useEffect(() => { + handleData() + }, []); return ( PROGRES KEGIATAN + + + + + + Segera Dikerjakan + + + + + Selesai + + + + + + Dikerjakan + + + + + Dibatalkan + + + ) } \ No newline at end of file diff --git a/components/home/discussionHome.tsx b/components/home/discussionHome.tsx index b4e6ac6..ce764f7 100644 --- a/components/home/discussionHome.tsx +++ b/components/home/discussionHome.tsx @@ -1,15 +1,51 @@ import Styles from "@/constants/Styles"; +import { apiGetDataHome } from "@/lib/api"; +import { useAuthSession } from "@/providers/AuthProvider"; +import { useEffect, useState } from "react"; import { Text, View } from "react-native"; import DiscussionItem from "../discussionItem"; +type Props = { + id: string + idDivision: string + desc: string + title: string + date: string + user: string +} + export default function DisccussionHome() { + const { decryptToken, token } = useAuthSession() + const [data, setData] = useState([]) + + + async function handleData() { + try { + const hasil = await decryptToken(String(token?.current)) + const response = await apiGetDataHome({ cat: "discussion", user: hasil }) + setData(response.data) + } catch (error) { + console.error(error) + } + } + + useEffect(() => { + handleData() + }, []); + return ( Diskusi - - - + { + data.length > 0 ? + data.map((item, index) => { + return ( + + ) + }) + : Tidak ada acara hari ini + } ) diff --git a/components/home/divisionHome.tsx b/components/home/divisionHome.tsx index 1654ac9..772feed 100644 --- a/components/home/divisionHome.tsx +++ b/components/home/divisionHome.tsx @@ -1,13 +1,38 @@ import Styles from "@/constants/Styles"; -import React from "react"; +import { apiGetDataHome } from "@/lib/api"; +import { useAuthSession } from "@/providers/AuthProvider"; +import { router } from "expo-router"; +import React, { useEffect, useState } from "react"; import { Dimensions, Text, View } from "react-native"; import Carousel, { ICarouselInstance } from "react-native-reanimated-carousel"; import PaperGridContent from "../paperGridContent"; +type Props = { + id: string + name: string + jumlah: number +} + export default function DivisionHome() { - const data = [...new Array(6).keys()]; + const { decryptToken, token } = useAuthSession() const ref = React.useRef(null); const width = Dimensions.get("window").width; + const [data, setData] = useState([]) + + async function handleData() { + try { + const hasil = await decryptToken(String(token?.current)) + const response = await apiGetDataHome({ cat: "division", user: hasil }) + setData(response.data) + } catch (error) { + console.error(error) + } + } + + useEffect(() => { + handleData() + }, []); + return ( @@ -26,9 +51,9 @@ export default function DivisionHome() { snapEnabled={true} vertical={false} renderItem={({ index }) => ( - + { router.push(`/division/${data[index].id}`) }} content="carousel" title={data[index].name} headerColor="warning"> - 12 + {data[index].jumlah} KEGIATAN diff --git a/components/home/eventHome.tsx b/components/home/eventHome.tsx index ece6feb..6b3bad1 100644 --- a/components/home/eventHome.tsx +++ b/components/home/eventHome.tsx @@ -1,14 +1,56 @@ import Styles from "@/constants/Styles"; +import { apiGetDataHome } from "@/lib/api"; +import { useAuthSession } from "@/providers/AuthProvider"; +import { useEffect, useState } from "react"; import { Text, View } from "react-native"; import EventItem from "../eventItem"; +import { router } from "expo-router"; + +type Props = { + id: string + idDivision: string + title: string + desc: string + status: number + timeStart: string + timeEnd: string + dateStart: string + dateEnd: string + createdAt: string + user_name: string +} export default function EventHome() { + const { decryptToken, token } = useAuthSession() + const [data, setData] = useState([]) + + async function handleData() { + try { + const hasil = await decryptToken(String(token?.current)) + const response = await apiGetDataHome({ cat: "event", user: hasil }) + setData(response.data) + } catch (error) { + console.error(error) + } + } + + useEffect(() => { + handleData() + }, []); + return ( Acara Hari Ini - - + { + data.length > 0 ? + data.map((item, index) => { + return ( + {router.push(`/division/${item.idDivision}/calendar/${item.id}`)}} title={item.title} user={item.user_name} jamAwal={item.timeStart} jamAkhir={item.timeEnd} /> + ) + }) + : Tidak ada acara hari ini + } ) diff --git a/components/home/projectHome.tsx b/components/home/projectHome.tsx index f35bdd1..b33f653 100644 --- a/components/home/projectHome.tsx +++ b/components/home/projectHome.tsx @@ -1,15 +1,42 @@ +import { ColorsStatus } from "@/constants/ColorsStatus"; import Styles from "@/constants/Styles"; -import React from "react"; +import { apiGetDataHome } from "@/lib/api"; +import { useAuthSession } from "@/providers/AuthProvider"; +import { router } from "expo-router"; +import React, { useEffect, useState } from "react"; import { Dimensions, Text, View } from "react-native"; import Carousel, { ICarouselInstance } from "react-native-reanimated-carousel"; -import ProgressBar from "../progressBar"; -import { ColorsStatus } from "@/constants/ColorsStatus"; import PaperGridContent from "../paperGridContent"; +import ProgressBar from "../progressBar"; + +type Props = { + id: string + title: string + desc: string + status: number + progress: number + createdAt: string +} export default function ProjectHome() { - const data = [...new Array(6).keys()]; + const { decryptToken, token } = useAuthSession() const ref = React.useRef(null); const width = Dimensions.get("window").width; + const [data, setData] = useState([]) + + async function handleData() { + try { + const hasil = await decryptToken(String(token?.current)) + const response = await apiGetDataHome({ cat: "kegiatan", user: hasil }) + setData(response.data) + } catch (error) { + console.error(error) + } + } + + useEffect(() => { + handleData() + }, []); return ( @@ -27,12 +54,26 @@ export default function ProjectHome() { snapEnabled={true} vertical={false} renderItem={({ index }) => ( - + { router.push(`/project/${data[index].id}`) }} title={data[index].title} headerColor="primary"> - 13 Februari 2025 - - DIKERJAKAN + {data[index].createdAt} + + + { + data[index].status === 0 ? 'SEGERA' : + data[index].status === 1 ? 'DIKERJAKAN' : + data[index].status === 2 ? 'SELESAI' : + data[index].status === 3 ? 'DIBATALKAN' : + "SEGERA" + } + diff --git a/constants/Styles.ts b/constants/Styles.ts index 212b806..34b0dc9 100644 --- a/constants/Styles.ts +++ b/constants/Styles.ts @@ -158,6 +158,18 @@ const Styles = StyleSheet.create({ w100: { width: '100%' }, + w90: { + width: '90%' + }, + w80: { + width: '80%' + }, + w70: { + width: '70%' + }, + w60: { + width: '60%' + }, w50: { width: '50%' }, diff --git a/lib/api.ts b/lib/api.ts index f46e780..c3555ce 100644 --- a/lib/api.ts +++ b/lib/api.ts @@ -31,10 +31,23 @@ export const apiGetBanner = async ({ user }: { user: string }) => { }; -// export const createEntity = async (newEntity: any) => { -// const response = await api.post('/entities', newEntity); -// return response.data; -// }; +export const apiCreateBanner = async (data: FormData) => { + await api.post('/banner', data, { + headers: { + 'Content-Type': 'multipart/form-data', + }, + }).then(response => { + return response.data; + }) + .catch(error => { + console.error('Error:', error); + }); +}; + +export const apiGetDataHome = async ({ cat, user }: { cat: 'kegiatan' | 'division' | 'progress' | 'dokumen' | 'event' | 'discussion' | 'header' | 'check-late-project', user: string }) => { + const response = await api.get(`mobile/home?user=${user}&cat=${cat}`); + return response.data; +}; // export const updateEntityById = async (id: any, updatedEntity: any) => { // const response = await api.put(`/entities/${id}`, updatedEntity);