Compare commits

...

39 Commits

Author SHA1 Message Date
887e787a99 Merge pull request 'amalia/17-apr-26' (#37) from amalia/17-apr-26 into join
Reviewed-on: #37
2026-04-17 17:40:04 +08:00
772551a917 upd: page kosong atau data udah di hapus pada pengumuman 2026-04-17 16:46:49 +08:00
555b9e4037 upd: fix laopran grafik divisi 2026-04-17 15:26:06 +08:00
d4b4db4251 upd: fix: jumlah dokumen grafik pada home 2026-04-17 15:01:14 +08:00
17d92cba25 Merge pull request 'amalia/10-mar-26' (#36) from amalia/10-mar-26 into join
Reviewed-on: #36
2026-03-10 16:30:52 +08:00
e1b62be6da upd:build number 2026-03-10 15:31:57 +08:00
b2b125c410 upd: build eas 2026-03-10 15:19:40 +08:00
1cfecbbdd5 upd : border di android 2026-03-10 11:09:19 +08:00
21006e8eee upd: gambar caraousel 2026-03-10 11:02:26 +08:00
91231d60e4 upd: md 2026-03-09 16:43:04 +08:00
7174e27be1 upd: version dan prebuild 2026-03-09 14:17:36 +08:00
9d4b931aa6 Merge pull request 'amalia/05-mar-26' (#35) from amalia/05-mar-26 into join
Reviewed-on: #35
2026-03-05 16:19:03 +08:00
166d8f1c16 upd: notifikasi
Deskripsi:
- update notifikasi android

No Issues
2026-03-05 14:38:45 +08:00
7060a2d165 upd: otp
Deskripsi:
- link otp baru

NOIssues
2026-03-05 14:15:36 +08:00
d6217aecf1 Merge pull request 'upd: notifikasi' (#34) from amalia/04-mar-26 into join
Reviewed-on: #34
2026-03-04 16:39:05 +08:00
608381673f upd: notifikasi
Deskripsi:
- notifikasi saat allowed device
- ios dan android

No Issues
2026-03-04 16:35:59 +08:00
3cc7f76346 Merge pull request 'amalia/03-mar-26' (#33) from amalia/03-mar-26 into join
Reviewed-on: #33
2026-03-03 16:46:19 +08:00
868b712fbb upd: notifikasi
Deskripsi:
- belom selesai notifikasi

No Issues
2026-03-03 16:44:02 +08:00
a53b99b39d version 2026-03-03 10:57:55 +08:00
25d521f013 Merge pull request 'amalia/26-feb-26' (#32) from amalia/26-feb-26 into join
Reviewed-on: #32
2026-02-26 17:48:06 +08:00
aee0823cb1 upd: fiksasi 2026-02-26 17:42:33 +08:00
2a0e1f4c1f upd: bun lock 2026-02-26 14:54:51 +08:00
ef08c821fa Merge pull request 'upd: fiksasi' (#30) from amalia/25-feb-26 into join
Reviewed-on: #30
2026-02-25 16:09:31 +08:00
fd5d582092 upd: fiksasi
Deskripsi:
-tampilan

No Issues
2026-02-25 16:07:17 +08:00
7729dc38f8 Merge pull request 'amalia/24-feb-26' (#29) from amalia/24-feb-26 into join
Reviewed-on: #29
2026-02-24 18:01:29 +08:00
8c6ff06216 upd: toast alert 2026-02-24 17:44:49 +08:00
214a243e44 upd: upd version
Deskripsi:
- tampilan jika update versi terbaru atau sedang maintenance

NO Issues
2026-02-24 15:51:29 +08:00
449f6f96cc Merge pull request 'upd: redesign' (#28) from amalia/23-feb-26 into join
Reviewed-on: #28
2026-02-24 13:36:49 +08:00
d1dec49784 upd: redesign 2026-02-23 14:20:26 +08:00
e351f54f6c Merge pull request 'upd: redesign' (#27) from amalia/20-feb-26 into join
Reviewed-on: #27
2026-02-23 10:17:00 +08:00
3809d382fa upd: redesign 2026-02-20 16:32:35 +08:00
d58a35bde2 Merge pull request 'amalia/19-feb-26' (#26) from amalia/19-feb-26 into join
Reviewed-on: #26
2026-02-20 10:50:38 +08:00
e2a601c590 Merge pull request 'amalia/18-feb-26' (#25) from amalia/18-feb-26 into join
Reviewed-on: #25
2026-02-18 17:32:10 +08:00
f0373ef479 Merge pull request 'upd: redesign' (#24) from amalia/13-feb-26 into join
Reviewed-on: http://wibugit.wibudev.com/wibu/mobile-darmasaba/pulls/24
2026-02-13 17:26:53 +08:00
700192dd8d Merge pull request 'upd: redesign' (#23) from amalia/12-feb-26 into join
Reviewed-on: http://wibugit.wibudev.com/wibu/mobile-darmasaba/pulls/23
2026-02-12 17:53:14 +08:00
27b0b7d51f Merge pull request 'redesign aplikasi' (#22) from amalia/11-feb-26 into join
Reviewed-on: http://wibugit.wibudev.com/wibu/mobile-darmasaba/pulls/22
2026-02-11 17:07:40 +08:00
65278df750 Merge pull request 'upd: redesign aplikasi' (#21) from amalia/10-feb-26 into join
Reviewed-on: http://wibugit.wibudev.com/wibu/mobile-darmasaba/pulls/21
2026-02-10 17:34:54 +08:00
8b98fee632 Merge pull request 'upd: redesign' (#20) from amalia/09-feb-25 into join
Reviewed-on: http://wibugit.wibudev.com/wibu/mobile-darmasaba/pulls/20
2026-02-09 17:50:22 +08:00
e254cf8ed2 Merge pull request 'upd: panduan' (#18) from amalia/06-feb-26 into join
Reviewed-on: http://wibugit.wibudev.com/wibu/mobile-darmasaba/pulls/18
2026-02-06 17:48:37 +08:00
125 changed files with 3929 additions and 651 deletions

View File

@@ -1,6 +1,6 @@
# Desa+
Desa+ adalah aplikasi mobile berbasis React Native yang dikembangkan dengan Expo untuk membantu pengelolaan dan komunikasi di lingkungan desa/kelurahan. Aplikasi ini menyediakan berbagai fitur untuk memudahkan administrasi desa, komunikasi antar warga, dan pengelolaan informasi penting.
Desa+ (Desa Plus) adalah aplikasi mobile berbasis React Native yang dikembangkan dengan Expo untuk membantu pengelolaan dan komunikasi di lingkungan desa/kelurahan. Aplikasi ini menyediakan berbagai fitur untuk memudahkan administrasi desa, komunikasi antar warga, dan pengelolaan informasi penting.
## Fitur Utama

View File

@@ -92,8 +92,8 @@ android {
applicationId 'mobiledarmasaba.app'
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 6
versionName "1.0.2"
versionCode 16
versionName "2.1.0"
}
signingConfigs {
debug {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 904 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -1,9 +1,9 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
<item name="android:windowOptOutEdgeToEdgeEnforcement" tools:targetApi="35">true</item>
<item name="colorPrimary">@color/colorPrimary</item>
<item name="android:statusBarColor">#ffffff</item>
<item name="android:windowOptOutEdgeToEdgeEnforcement" tools:targetApi="35">true</item>
</style>
<style name="Theme.App.SplashScreen" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/splashscreen_background</item>

View File

@@ -4,7 +4,7 @@ export default {
expo: {
name: "Desa+",
slug: "mobile-darmasaba",
version: "2.0.5", // Versi aplikasi (App Store)
version: "2.1.0", // Versi aplikasi (App Store)
jsEngine: "jsc",
orientation: "portrait",
icon: "./assets/images/logo-icon-small.png",
@@ -14,7 +14,7 @@ export default {
ios: {
supportsTablet: true,
bundleIdentifier: "mobiledarmasaba.app",
buildNumber: "7",
buildNumber: "9",
infoPlist: {
ITSAppUsesNonExemptEncryption: false,
CFBundleDisplayName: "Desa+"
@@ -23,7 +23,7 @@ export default {
},
android: {
package: "mobiledarmasaba.app",
versionCode: 15,
versionCode: 16,
adaptiveIcon: {
foregroundImage: "./assets/images/logo-icon-small.png",
backgroundColor: "#ffffff"

View File

@@ -1,5 +1,6 @@
import HeaderRightAnnouncementList from "@/components/announcement/headerAnnouncementList";
import AppHeader from "@/components/AppHeader";
import Styles from "@/constants/Styles";
import HeaderDiscussionGeneral from "@/components/discussion_general/headerDiscussionGeneral";
import HeaderRightDivisionList from "@/components/division/headerDivisionList";
import HeaderRightGroupList from "@/components/group/headerGroupList";
@@ -8,17 +9,19 @@ import HeaderRightPositionList from "@/components/position/headerRightPositionLi
import HeaderRightProjectList from "@/components/project/headerProjectList";
import Text from "@/components/Text";
import ToastCustom from "@/components/toastCustom";
import { apiReadOneNotification } from "@/lib/api";
import ModalUpdateMaintenance from "@/components/ModalUpdateMaintenance";
import { apiGetVersion, apiReadOneNotification } from "@/lib/api";
import { pushToPage } from "@/lib/pushToPage";
import store from "@/lib/store";
import { useAuthSession } from "@/providers/AuthProvider";
import AsyncStorage from "@react-native-async-storage/async-storage";
import Constants from "expo-constants";
import { getApp } from "@react-native-firebase/app";
import { getMessaging, onMessage } from "@react-native-firebase/messaging";
import { Redirect, router, Stack, usePathname } from "expo-router";
import { StatusBar } from 'expo-status-bar';
import { useEffect } from "react";
import { Easing, Notifier } from 'react-native-notifier';
import { StatusBar } from 'expo-status-bar';
import { useEffect, useState } from "react";
import { Easing, Notifier, NotifierComponents } from 'react-native-notifier';
import { Provider } from "react-redux";
import { useTheme } from "@/providers/ThemeProvider";
@@ -26,6 +29,80 @@ export default function RootLayout() {
const { token, decryptToken, isLoading } = useAuthSession()
const pathname = usePathname()
const { colors } = useTheme()
const [modalUpdateMaintenance, setModalUpdateMaintenance] = useState(false)
const [modalType, setModalType] = useState<'update' | 'maintenance'>('update')
const [isForceUpdate, setIsForceUpdate] = useState(false)
const [updateMessage, setUpdateMessage] = useState('')
const currentVersion = Constants.expoConfig?.version ?? '0.0.0'
const compareVersions = (v1: string, v2: string) => {
const parts1 = v1.split('.').map(Number);
const parts2 = v2.split('.').map(Number);
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
const p1 = parts1[i] || 0;
const p2 = parts2[i] || 0;
if (p1 < p2) return -1;
if (p1 > p2) return 1;
}
return 0;
};
useEffect(() => {
const checkVersion = async () => {
try {
const response = await apiGetVersion();
if (response.success && response.data) {
const maintenance = response.data.find((item: any) => item.id === 'mobile_maintenance')?.value === 'true';
const latestVersion = response.data.find((item: any) => item.id === 'mobile_latest_version')?.value || '0.0.0';
const minVersion = response.data.find((item: any) => item.id === 'mobile_minimum_version')?.value || '0.0.0';
const message = response.data.find((item: any) => item.id === 'mobile_message_update')?.value || '';
if (maintenance) {
setModalType('maintenance');
setModalUpdateMaintenance(true);
setIsForceUpdate(true);
return;
}
if (compareVersions(currentVersion, minVersion) === -1) {
setModalType('update');
setIsForceUpdate(true);
setUpdateMessage(message);
setModalUpdateMaintenance(true);
} else if (compareVersions(currentVersion, latestVersion) === -1) {
// Check if this soft update version was already dismissed
const dismissedVersion = await AsyncStorage.getItem('dismissed_update_version');
if (dismissedVersion !== latestVersion) {
setModalType('update');
setIsForceUpdate(false);
setUpdateMessage(message);
setModalUpdateMaintenance(true);
}
}
}
} catch (error) {
console.error('Failed to check version:', error);
}
};
checkVersion();
}, [currentVersion]);
const handleDismissUpdate = async () => {
if (!isForceUpdate) {
try {
const response = await apiGetVersion();
const latestVersion = response.data.find((item: any) => item.id === 'mobile_latest_version')?.value;
if (latestVersion) {
await AsyncStorage.setItem('dismissed_update_version', latestVersion);
}
} catch (e) {
console.error(e);
}
setModalUpdateMaintenance(false);
}
}
async function handleReadNotification(id: string, category: string, idContent: string, title: string) {
try {
@@ -67,12 +144,34 @@ export default function RootLayout() {
} else if (pathname !== `/${category}/${content}`) {
Notifier.showNotification({
title: title,
description: remoteMessage.notification?.body,
description: String(remoteMessage.notification?.body),
duration: 3000,
animationDuration: 300,
showEasing: Easing.ease,
onPress: () => handleReadNotification(String(id), String(category), String(content), String(title)),
hideOnPress: true,
Component: NotifierComponents.Notification,
componentProps: {
containerStyle: [
Styles.shadowBox,
{
backgroundColor: colors.modalBackground,
borderRadius: 5,
marginHorizontal: 15,
marginTop: 10,
padding: 15,
}
],
titleStyle: {
color: colors.text,
fontWeight: 'bold',
fontSize: 16,
},
descriptionStyle: {
color: colors.dimmed,
fontSize: 14,
},
}
});
}
}
@@ -223,6 +322,13 @@ export default function RootLayout() {
</Stack>
<StatusBar style={'light'} translucent={false} backgroundColor="black" />
<ToastCustom />
<ModalUpdateMaintenance
visible={modalUpdateMaintenance}
type={modalType}
isForceUpdate={isForceUpdate}
customDescription={updateMessage}
onDismiss={handleDismissUpdate}
/>
</Provider>
)
}

View File

@@ -3,6 +3,7 @@ import AppHeader from "@/components/AppHeader";
import BorderBottomItem from "@/components/borderBottomItem";
import Skeleton from "@/components/skeleton";
import Text from '@/components/Text';
import ErrorView from "@/components/ErrorView";
import { ConstEnv } from "@/constants/ConstEnv";
import { isImageFile } from "@/constants/FileExtensions";
import Styles from "@/constants/Styles";
@@ -65,6 +66,7 @@ export default function DetailAnnouncement() {
const [loadingOpen, setLoadingOpen] = useState(false)
const [preview, setPreview] = useState(false)
const [chooseFile, setChooseFile] = useState<FileData>()
const [isError, setIsError] = useState(false)
/**
* Opens the image preview modal for the selected image file
@@ -79,6 +81,7 @@ export default function DetailAnnouncement() {
async function handleLoad(loading: boolean) {
try {
setIsError(false)
setLoading(loading)
const hasil = await decryptToken(String(token?.current))
const response: ApiResponse = await apiGetAnnouncementOne({ id: id, user: hasil })
@@ -87,11 +90,15 @@ export default function DetailAnnouncement() {
setDataMember(response.member)
setDataFile(response.file)
} else {
setIsError(true)
Toast.show({ type: 'small', text1: response.message })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Gagal mengambil data' })
} catch (error: any) {
console.error(error);
setIsError(true)
const message = error?.response?.data?.message || "Gagal mengambil data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}
@@ -204,104 +211,110 @@ export default function DetailAnnouncement() {
/>
}
>
<View style={[Styles.p15, Styles.mb50]}>
<View style={[Styles.wrapPaper, Styles.borderAll, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
{
loading ?
<View>
<View style={[Styles.rowOnly]}>
<Skeleton width={30} height={30} borderRadius={10} />
<View style={[Styles.flex1, Styles.ph05]}>
<Skeleton width={100} widthType="percent" height={30} borderRadius={10} />
</View>
</View>
<Skeleton width={100} widthType="percent" height={10} borderRadius={10} />
<Skeleton width={100} widthType="percent" height={10} borderRadius={10} />
<Skeleton width={100} widthType="percent" height={10} borderRadius={10} />
</View>
:
<>
<View style={[Styles.rowOnly, Styles.alignStart]}>
<MaterialIcons name="campaign" size={25} color={colors.text} style={[Styles.mr05]} />
<Text style={[Styles.textDefaultSemiBold, Styles.w90, Styles.mt02]}>{data?.title}</Text>
</View>
<View style={[Styles.mt10]}>
{
hasHtmlTags(data?.desc) ?
<RenderHTML
contentWidth={contentWidth}
source={{ html: data?.desc }}
baseStyle={{ color: colors.text }}
/>
:
<Text>{data?.desc}</Text>
}
</View>
</>
}
{isError && !loading ? (
<View style={[Styles.mv50]}>
<ErrorView />
</View>
{
dataFile.length > 0 && (
<View style={[Styles.wrapPaper, Styles.borderAll, Styles.mt10, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
<View style={[Styles.mb05]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
</View>
{dataFile.map((item, index) => (
<BorderBottomItem
key={`${item.id}-${index}`}
borderType="bottom"
icon={<MaterialCommunityIcons
name={isImageFile(item.extension) ? "file-image-outline" : "file-document-outline"}
size={25}
color={colors.text}
/>}
title={item.name + '.' + item.extension}
titleWeight="normal"
onPress={() => {
isImageFile(item.extension) ?
handleChooseFile(item)
: openFile(item)
}}
/>
))}
</View>
)
}
<View style={[Styles.wrapPaper, Styles.borderAll, Styles.mt10, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
{
loading ?
arrSkeleton.map((item, index) => {
return (
<View key={index}>
<Skeleton width={30} widthType="percent" height={10} borderRadius={10} />
<Skeleton width={100} widthType="percent" height={10} borderRadius={10} />
<Skeleton width={100} widthType="percent" height={10} borderRadius={10} />
) : (
<View style={[Styles.p15, Styles.mb50]}>
<View style={[Styles.wrapPaper, Styles.borderAll, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
{
loading ?
<View>
<View style={[Styles.rowOnly]}>
<Skeleton width={30} height={30} borderRadius={10} />
<View style={[Styles.flex1, Styles.ph05]}>
<Skeleton width={100} widthType="percent" height={30} borderRadius={10} />
</View>
</View>
)
})
:
Object.keys(dataMember).map((v: any, i: any) => {
return (
<View key={i} style={[Styles.mb05]}>
<Text style={[Styles.textDefaultSemiBold]}>{dataMember[v]?.[0].group}</Text>
<Skeleton width={100} widthType="percent" height={10} borderRadius={10} />
<Skeleton width={100} widthType="percent" height={10} borderRadius={10} />
<Skeleton width={100} widthType="percent" height={10} borderRadius={10} />
</View>
:
<>
<View style={[Styles.rowOnly, Styles.alignStart]}>
<MaterialIcons name="campaign" size={25} color={colors.text} style={[Styles.mr05]} />
<Text style={[Styles.textDefaultSemiBold, Styles.w90, Styles.mt02]}>{data?.title}</Text>
</View>
<View style={[Styles.mt10]}>
{
dataMember[v].map((item: any, x: any) => {
return (
<View key={x} style={[Styles.rowItemsCenter, Styles.w90]}>
<Entypo name="dot-single" size={24} color={colors.text} />
<Text style={[Styles.textDefault]} numberOfLines={1} ellipsizeMode='tail'>{item.division}</Text>
</View>
)
})
hasHtmlTags(data?.desc) ?
<RenderHTML
contentWidth={contentWidth}
source={{ html: data?.desc }}
baseStyle={{ color: colors.text }}
/>
:
<Text>{data?.desc}</Text>
}
</View>
)
})
</>
}
</View>
{
dataFile.length > 0 && (
<View style={[Styles.wrapPaper, Styles.borderAll, Styles.mt10, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
<View style={[Styles.mb05]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
</View>
{dataFile.map((item, index) => (
<BorderBottomItem
key={`${item.id}-${index}`}
borderType={index === dataFile.length - 1 ? 'none' : 'bottom'}
icon={<MaterialCommunityIcons
name={isImageFile(item.extension) ? "file-image-outline" : "file-document-outline"}
size={25}
color={colors.text}
/>}
title={item.name + '.' + item.extension}
titleWeight="normal"
onPress={() => {
isImageFile(item.extension) ?
handleChooseFile(item)
: openFile(item)
}}
/>
))}
</View>
)
}
<View style={[Styles.wrapPaper, Styles.borderAll, Styles.mt10, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
{
loading ?
arrSkeleton.map((item, index) => {
return (
<View key={index}>
<Skeleton width={30} widthType="percent" height={10} borderRadius={10} />
<Skeleton width={100} widthType="percent" height={10} borderRadius={10} />
<Skeleton width={100} widthType="percent" height={10} borderRadius={10} />
</View>
)
})
:
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 key={x} style={[Styles.rowItemsCenter, Styles.w90]}>
<Entypo name="dot-single" size={24} color={colors.text} />
<Text style={[Styles.textDefault]} numberOfLines={1} ellipsizeMode='tail'>{item.division}</Text>
</View>
)
})
}
</View>
)
})
}
</View>
</View>
</View>
)}
</ScrollView>
<ImageViewing

View File

@@ -4,7 +4,7 @@ import ButtonSaveHeader from "@/components/buttonSaveHeader";
import ButtonSelect from "@/components/buttonSelect";
import DrawerBottom from "@/components/drawerBottom";
import { InputForm } from "@/components/inputForm";
import LoadingOverlay from "@/components/loadingOverlay";
import LoadingCenter from "@/components/loadingCenter";
import MenuItemRow from "@/components/menuItemRow";
import ModalSelectMultiple from "@/components/modalSelectMultiple";
import Text from "@/components/Text";
@@ -95,17 +95,21 @@ export default function CreateAnnouncement() {
const response = await apiCreateAnnouncement(fd)
// const response = await apiCreateAnnouncement({
// data: { ...dataForm, user: hasil, groups: divisionMember },
// });
if (response.success) {
dispatch(setUpdateAnnouncement(!update))
Toast.show({ type: 'small', text1: 'Berhasil menambahkan data', })
router.back();
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Tidak dapat terhubung ke server"
Toast.show({
type: 'small',
text1: message
})
} finally {
setLoading(false)
}
@@ -174,7 +178,7 @@ export default function CreateAnnouncement() {
)
}}
/>
<LoadingOverlay visible={loading} />
{loading && <LoadingCenter />}
<ScrollView
showsVerticalScrollIndicator={false}
style={[Styles.h100, { backgroundColor: colors.background }]}
@@ -205,22 +209,27 @@ export default function CreateAnnouncement() {
{
fileForm.length > 0
&&
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { borderColor: colors.icon + '20' }]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
{
fileForm.map((item, index) => (
<BorderBottomItem
key={index}
borderType={fileForm.length - 1 == index ? "none" : "bottom"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
bgColor="transparent"
titleWeight="normal"
onPress={() => { setIndexDelFile(index); setModalFile(true) }}
/>
))
}
</View>
<>
<View style={[Styles.rowSpaceBetween, Styles.mv05]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
<Text style={[Styles.textDefault]}>{fileForm.length} file</Text>
</View>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
{
fileForm.map((item, index) => (
<BorderBottomItem
key={index}
borderType={fileForm.length - 1 == index ? "none" : "bottom"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
bgColor="transparent"
titleWeight="normal"
onPress={() => { setIndexDelFile(index); setModalFile(true) }}
/>
))
}
</View>
</>
}
<ButtonSelect
@@ -233,25 +242,30 @@ export default function CreateAnnouncement() {
{
divisionMember.length > 0
&&
<View style={[Styles.borderAll, Styles.round05, Styles.p10, { borderColor: colors.icon + '20' }]}>
{
divisionMember.map((item: { name: any; Division: any }, index: any) => {
return (
<View key={index}>
<Text style={[Styles.textDefaultSemiBold]}>{item.name}</Text>
{
item.Division.map((division: any, i: any) => (
<View key={i} style={[Styles.rowItemsCenter, Styles.w90]}>
<Entypo name="dot-single" size={24} color={colors.text} />
<Text style={[Styles.textDefault]} numberOfLines={1} ellipsizeMode='tail'>{division.name}</Text>
</View>
))
}
</View>
)
})
}
</View>
<>
<View style={[Styles.rowSpaceBetween, Styles.mv05]}>
<Text style={[Styles.textDefaultSemiBold]}>Divisi</Text>
</View>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
{
divisionMember.map((item: { name: any; Division: any }, index: any) => {
return (
<View key={index}>
<Text style={[Styles.textDefaultSemiBold]}>{item.name}</Text>
{
item.Division.map((division: any, i: any) => (
<View key={i} style={[Styles.rowItemsCenter, Styles.w90]}>
<Entypo name="dot-single" size={24} color={colors.text} />
<Text style={[Styles.textDefault]} numberOfLines={1} ellipsizeMode='tail'>{division.name}</Text>
</View>
))
}
</View>
)
})
}
</View>
</>
}
</View>
</ScrollView>

View File

@@ -4,7 +4,7 @@ import ButtonSaveHeader from "@/components/buttonSaveHeader";
import ButtonSelect from "@/components/buttonSelect";
import DrawerBottom from "@/components/drawerBottom";
import { InputForm } from "@/components/inputForm";
import LoadingOverlay from "@/components/loadingOverlay";
import LoadingCenter from "@/components/loadingCenter";
import MenuItemRow from "@/components/menuItemRow";
import ModalSelectMultiple from "@/components/modalSelectMultiple";
import Text from '@/components/Text';
@@ -144,9 +144,14 @@ export default function EditAnnouncement() {
dispatch(setUpdateAnnouncement(!update))
Toast.show({ type: 'small', text1: 'Berhasil mengubah data', })
router.back();
} else {
Toast.show({ type: 'small', text1: 'Gagal mengubah data', })
}
} catch (error) {
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengubah data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}
@@ -225,7 +230,7 @@ export default function EditAnnouncement() {
)
}}
/>
<LoadingOverlay visible={loading} />
{loading && <LoadingCenter />}
<ScrollView
showsVerticalScrollIndicator={false}
style={[Styles.h100, { backgroundColor: colors.background }]}
@@ -258,35 +263,40 @@ export default function EditAnnouncement() {
{
(fileForm.length > 0 || dataFile.filter((val) => !val.delete).length > 0)
&&
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { borderColor: colors.icon + '20' }]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
{
dataFile.filter((val) => !val.delete).map((item, index) => (
<BorderBottomItem
key={index}
borderType={(fileForm.length + dataFile.length) > 1 ? "bottom" : "none"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name + '.' + item.extension}
titleWeight="normal"
bgColor="transparent"
onPress={() => { setIndexDelFile({ id: item.id, cat: "oldFile" }); setModalFile(true) }}
/>
))
}
{
fileForm.map((item, index) => (
<BorderBottomItem
key={index}
borderType={(fileForm.length + dataFile.length) > 1 ? "bottom" : "none"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
titleWeight="normal"
bgColor="transparent"
onPress={() => { setIndexDelFile({ id: index, cat: "newFile" }); setModalFile(true) }}
/>
))
}
</View>
<>
<View style={[Styles.rowSpaceBetween, Styles.mv05]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
<Text style={[Styles.textDefault]}>{fileForm.length + dataFile.filter((val) => !val.delete).length} file</Text>
</View>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
{
dataFile.filter((val) => !val.delete).map((item, index) => (
<BorderBottomItem
key={index}
borderType={dataFile.filter((val) => !val.delete).length - 1 == index && fileForm.length == 0 ? "none" : "bottom"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name + '.' + item.extension}
titleWeight="normal"
bgColor="transparent"
onPress={() => { setIndexDelFile({ id: item.id, cat: "oldFile" }); setModalFile(true) }}
/>
))
}
{
fileForm.map((item, index) => (
<BorderBottomItem
key={index}
borderType={fileForm.length - 1 == index ? "none" : "bottom"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
titleWeight="normal"
bgColor="transparent"
onPress={() => { setIndexDelFile({ id: index, cat: "newFile" }); setModalFile(true) }}
/>
))
}
</View>
</>
}
<ButtonSelect
value="Pilih divisi penerima pengumuman"
@@ -297,25 +307,30 @@ export default function EditAnnouncement() {
{
dataMember.length > 0
&&
<View style={[Styles.borderAll, Styles.round05, Styles.p10, { borderColor: colors.icon + '20' }]}>
{
dataMember.map((item: { name: any; Division: any }, index: any) => {
return (
<View key={index}>
<Text style={[Styles.textDefaultSemiBold]}>{item.name}</Text>
{
item.Division.map((division: any, i: any) => (
<View key={i} style={[Styles.rowItemsCenter, Styles.w90]}>
<Entypo name="dot-single" size={24} color={colors.text} />
<Text style={[Styles.textDefault]} numberOfLines={1} ellipsizeMode='tail'>{division.name}</Text>
</View>
))
}
</View>
)
})
}
</View>
<>
<View style={[Styles.rowSpaceBetween, Styles.mv05]}>
<Text style={[Styles.textDefaultSemiBold]}>Divisi</Text>
</View>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
{
dataMember.map((item: { name: any; Division: any }, index: any) => {
return (
<View key={index}>
<Text style={[Styles.textDefaultSemiBold]}>{item.name}</Text>
{
item.Division.map((division: any, i: any) => (
<View key={i} style={[Styles.rowItemsCenter, Styles.w90]}>
<Entypo name="dot-single" size={24} color={colors.text} />
<Text style={[Styles.textDefault]} numberOfLines={1} ellipsizeMode='tail'>{division.name}</Text>
</View>
))
}
</View>
)
})
}
</View>
</>
}
</View>
</ScrollView>

View File

@@ -1,6 +1,7 @@
import AppHeader from "@/components/AppHeader";
import ButtonSaveHeader from "@/components/buttonSaveHeader";
import { InputForm } from "@/components/inputForm";
import LoadingCenter from "@/components/loadingCenter";
import Text from "@/components/Text";
import { ConstEnv } from "@/constants/ConstEnv";
import Styles from "@/constants/Styles";
@@ -105,9 +106,11 @@ export default function EditBanner() {
} else {
Toast.show({ type: 'small', text1: 'Gagal mengupdate data', })
}
} catch (error) {
} catch (error: any) {
console.error(error);
Toast.show({ type: 'small', text1: 'Gagal mengupdate data', })
const message = error?.response?.data?.message || "Gagal mengupdate data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}
@@ -145,6 +148,7 @@ export default function EditBanner() {
)
}}
/>
{loading && <LoadingCenter />}
<ScrollView showsVerticalScrollIndicator={false} style={[Styles.h100, { backgroundColor: colors.background }]}>
<View style={[Styles.p15, Styles.mb100]}>
<View style={[Styles.mb15]}>

View File

@@ -1,6 +1,7 @@
import AppHeader from "@/components/AppHeader";
import ButtonSaveHeader from "@/components/buttonSaveHeader";
import { InputForm } from "@/components/inputForm";
import LoadingCenter from "@/components/loadingCenter";
import Text from "@/components/Text";
import Styles from "@/constants/Styles";
import { apiCreateBanner, apiGetBanner } from "@/lib/api";
@@ -87,9 +88,11 @@ export default function CreateBanner() {
} else {
Toast.show({ type: 'small', text1: 'Gagal menambahkan data', })
}
} catch (error) {
} catch (error: any) {
console.error(error);
Toast.show({ type: 'small', text1: 'Gagal menambahkan data', })
const message = error?.response?.data?.message || "Gagal menambahkan data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}
@@ -99,24 +102,8 @@ export default function CreateBanner() {
<SafeAreaView style={[Styles.flex1, { backgroundColor: colors.background }]}>
<Stack.Screen
options={{
// headerLeft: () => (
// <ButtonBackHeader
// onPress={() => {
// router.back();
// }}
// />
// ),
headerTitle: "Tambah Banner",
headerTitleAlign: "center",
// headerRight: () => (
// <ButtonSaveHeader
// disable={title == "" || selectedImage == undefined || error || loading ? true : false}
// category="create"
// onPress={() => {
// handleCreateEntity();
// }}
// />
// ),
header: () => (
<AppHeader
title="Fitur"
@@ -135,6 +122,7 @@ export default function CreateBanner() {
)
}}
/>
{loading && <LoadingCenter />}
<ScrollView showsVerticalScrollIndicator={false} style={[Styles.h100, { backgroundColor: colors.background }]}>
<View style={[Styles.p15]}>
<View style={[Styles.mb15]}>
@@ -148,13 +136,13 @@ export default function CreateBanner() {
) : (
<Pressable
onPress={pickImageAsync}
style={[Styles.wrapPaper, Styles.contentItemCenter]}
style={[Styles.wrapPaper, Styles.contentItemCenter, Styles.borderAll, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}
>
<View
style={[Styles.contentItemCenter]}
>
<Entypo name="image" size={50} color={"#aeaeae"} />
<Text style={[Styles.textInformation, Styles.mt05]}>
<Entypo name="image" size={50} color={colors.dimmed} />
<Text style={[Styles.textInformation, Styles.mt05, { color: colors.dimmed }]}>
Mohon unggah gambar dalam resolusi 1650 x 720 pixel untuk
memastikan
</Text>

View File

@@ -56,9 +56,11 @@ export default function BannerList() {
} else {
Toast.show({ type: 'small', text1: 'Gagal menghapus data', })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menghapus data"
Toast.show({ type: 'small', text1: message })
} finally {
setModal(false)
}

View File

@@ -158,8 +158,11 @@ export default function DetailDiscussionGeneral() {
Toast.show({ type: 'small', text1: response.message })
}
}
} catch (error) {
console.error(error)
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menambahkan data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoadingSendKomentar(false)
}
@@ -175,8 +178,11 @@ export default function DetailDiscussionGeneral() {
} else {
Toast.show({ type: 'small', text1: response.message })
}
} catch (error) {
console.error(error)
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengupdate data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoadingSendKomentar(false)
handleViewEditKomentar()
@@ -193,8 +199,11 @@ export default function DetailDiscussionGeneral() {
} else {
Toast.show({ type: 'small', text1: response.message })
}
} catch (error) {
console.error(error)
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menghapus data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoadingSendKomentar(false)
setVisible(false)

View File

@@ -84,9 +84,11 @@ export default function AddMemberDiscussionDetail() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Gagal menambahkan anggota', })
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menambahkan anggota"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}

View File

@@ -5,7 +5,7 @@ import ButtonSelect from "@/components/buttonSelect";
import DrawerBottom from "@/components/drawerBottom";
import ImageUser from "@/components/imageNew";
import { InputForm } from "@/components/inputForm";
import LoadingOverlay from "@/components/loadingOverlay";
import LoadingCenter from "@/components/loadingCenter";
import MenuItemRow from "@/components/menuItemRow";
import ModalSelect from "@/components/modalSelect";
import SelectForm from "@/components/selectForm";
@@ -156,9 +156,11 @@ export default function CreateDiscussionGeneral() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
} catch (error: any) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal menambahkan data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}
@@ -206,7 +208,7 @@ export default function CreateDiscussionGeneral() {
)
}}
/>
<LoadingOverlay visible={loading} />
{loading && <LoadingCenter />}
<ScrollView showsVerticalScrollIndicator={false} style={[Styles.h100, Styles.flex1, { backgroundColor: colors.background }]}>
<View style={[Styles.p15, Styles.mb100]}>
{
@@ -253,22 +255,27 @@ export default function CreateDiscussionGeneral() {
{
fileForm.length > 0
&&
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { borderColor: colors.icon + '20' }]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
{
fileForm.map((item, index) => (
<BorderBottomItem
key={index}
borderType={fileForm.length - 1 == index ? "none" : "bottom"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
bgColor="transparent"
titleWeight="normal"
onPress={() => { setIndexDelFile(index); setModalFile(true) }}
/>
))
}
</View>
<>
<View style={[Styles.rowSpaceBetween, Styles.mv05]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
<Text style={[Styles.textDefault]}>{fileForm.length} file</Text>
</View>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
{
fileForm.map((item, index) => (
<BorderBottomItem
key={index}
borderType={fileForm.length - 1 == index ? "none" : "bottom"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
bgColor="transparent"
titleWeight="normal"
onPress={() => { setIndexDelFile(index); setModalFile(true) }}
/>
))
}
</View>
</>
}
<ButtonSelect
value="Pilih Anggota"
@@ -293,11 +300,11 @@ export default function CreateDiscussionGeneral() {
entitiesMember.length > 0 &&
<View>
<View style={[Styles.rowSpaceBetween, Styles.mv05]}>
<Text>Anggota</Text>
<Text>Total {entitiesMember.length} Anggota</Text>
<Text style={[Styles.textDefaultSemiBold]}>Anggota</Text>
<Text style={[Styles.textDefault]}>{entitiesMember.length} Anggota</Text>
</View>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, { borderColor: colors.icon + '20' }]}>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
{
entitiesMember.map((item: { img: any; name: any; }, index: any) => {
return (

View File

@@ -5,7 +5,7 @@ import ButtonSaveHeader from "@/components/buttonSaveHeader";
import ButtonSelect from "@/components/buttonSelect";
import DrawerBottom from "@/components/drawerBottom";
import { InputForm } from "@/components/inputForm";
import LoadingOverlay from "@/components/loadingOverlay";
import LoadingCenter from "@/components/loadingCenter";
import MenuItemRow from "@/components/menuItemRow";
import Styles from "@/constants/Styles";
import { apiEditDiscussionGeneral, apiGetDiscussionGeneralOne } from "@/lib/api";
@@ -154,10 +154,14 @@ export default function EditDiscussionGeneral() {
dispatch(setUpdateDiscussionGeneralDetail(!update))
Toast.show({ type: 'small', text1: 'Berhasil mengubah data', })
router.back();
} else {
Toast.show({ type: 'small', text1: 'Gagal mengubah data', })
}
} catch (error) {
} catch (error: any) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal mengubah data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}
@@ -199,7 +203,7 @@ export default function EditDiscussionGeneral() {
)
}}
/>
<LoadingOverlay visible={loading} />
{loading && <LoadingCenter />}
<ScrollView showsVerticalScrollIndicator={false} style={[Styles.h100, Styles.flex1, { backgroundColor: colors.background }]}>
<View style={[Styles.p15]}>
<InputForm
@@ -229,35 +233,40 @@ export default function EditDiscussionGeneral() {
{
(fileForm.length > 0 || dataFile.filter((val) => !val.delete).length > 0)
&&
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { borderColor: colors.icon + '20' }]}>
<Text style={[Styles.textDefault]}>File</Text>
{
dataFile.filter((val) => !val.delete).map((item, index) => (
<BorderBottomItem
key={index}
borderType={(fileForm.length + dataFile.length) > 1 ? "bottom" : "none"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name + '.' + item.extension}
titleWeight="normal"
bgColor="transparent"
onPress={() => { setIndexDelFile({ id: item.id, cat: "oldFile" }); setModalFile(true) }}
/>
))
}
{
fileForm.map((item, index) => (
<BorderBottomItem
key={index}
borderType={(fileForm.length + dataFile.length) > 1 ? "bottom" : "none"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
titleWeight="normal"
bgColor="transparent"
onPress={() => { setIndexDelFile({ id: index, cat: "newFile" }); setModalFile(true) }}
/>
))
}
</View>
<>
<View style={[Styles.rowSpaceBetween, Styles.mv05]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
<Text style={[Styles.textDefault]}>{fileForm.length + dataFile.filter((val) => !val.delete).length} file</Text>
</View>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
{
dataFile.filter((val) => !val.delete).map((item, index) => (
<BorderBottomItem
key={index}
borderType={dataFile.filter((val) => !val.delete).length - 1 == index && fileForm.length == 0 ? "none" : "bottom"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name + '.' + item.extension}
titleWeight="normal"
bgColor="transparent"
onPress={() => { setIndexDelFile({ id: item.id, cat: "oldFile" }); setModalFile(true) }}
/>
))
}
{
fileForm.map((item, index) => (
<BorderBottomItem
key={index}
borderType={fileForm.length - 1 == index ? "none" : "bottom"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
titleWeight="normal"
bgColor="transparent"
onPress={() => { setIndexDelFile({ id: index, cat: "newFile" }); setModalFile(true) }}
/>
))
}
</View>
</>
}
</View>
</ScrollView>

View File

@@ -67,8 +67,11 @@ export default function MemberDiscussionDetail() {
await apiDeleteMemberDiscussionGeneral({ user: hasil, idUser: chooseUser.idUser }, id)
Toast.show({ type: 'small', text1: 'Berhasil mengeluarkan anggota dari diskusi', })
handleLoad(false)
} catch (error) {
console.error(error)
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengeluarkan anggota"
Toast.show({ type: 'small', text1: message })
} finally {
setModal(false)
}

View File

@@ -92,9 +92,11 @@ export default function AddMemberCalendarEvent() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menambahkan anggota"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}
@@ -169,7 +171,7 @@ export default function AddMemberCalendarEvent() {
return (
<Pressable
key={index}
style={[Styles.itemSelectModal]}
style={[Styles.itemSelectModal, {borderColor: colors.icon + '20'}]}
onPress={() => {
!found && onChoose(item.idUser, item.name, item.img)
}}

View File

@@ -57,9 +57,11 @@ export default function EditEventCalendar() {
setData({ ...response.data, dateStart: moment(response.data.dateStartFormat, 'DD-MM-YYYY').format('DD-MM-YYYY') })
setIdCalendar(response.data.idCalendar)
setChoose({ val: response.data.repeatEventTyper, label: valueTypeEventRepeat.find((item) => item.id == response.data.repeatEventTyper)?.name || "" })
} catch (error) {
} catch (error: any) {
console.error(error);
Toast.show({ type: 'small', text1: 'Gagal mendapatkan data', })
const message = error?.response?.data?.message || "Gagal mendapatkan data"
Toast.show({ type: 'small', text1: message })
}
}
@@ -154,9 +156,11 @@ export default function EditEventCalendar() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengubah acara"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}

View File

@@ -137,9 +137,11 @@ export default function DetailEventCalendar() {
dispatch(setUpdateCalendar({ ...update, member: !update.member }));
}
Toast.show({ type: 'small', text1: response.message, })
} catch (error) {
} catch (error: any) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal menghapus anggota"
Toast.show({ type: 'small', text1: message })
} finally {
setModalMember(false)
}

View File

@@ -83,9 +83,11 @@ export default function CreateCalendarAddMember() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal membuat acara"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}

View File

@@ -90,7 +90,7 @@ export default function CalendarHistory() {
<View style={[{ flex: 1 }]}>
<FlatList data={item.data}
renderItem={({ item, index }: { item: { title: string, timeStart: string, timeEnd: string }, index: number }) => (
<View key={index} style={[Styles.mb05, Styles.w80]}>
<View key={index} style={[Styles.mb05]}>
<Text style={[Styles.textDefaultSemiBold]} numberOfLines={1} ellipsizeMode="tail">{item.title}</Text>
<Text style={[Styles.textDefault]}>{item.timeStart} | {item.timeEnd}</Text>
</View>

View File

@@ -4,7 +4,7 @@ import ButtonSaveHeader from "@/components/buttonSaveHeader";
import ButtonSelect from "@/components/buttonSelect";
import DrawerBottom from "@/components/drawerBottom";
import { InputForm } from "@/components/inputForm";
import LoadingOverlay from "@/components/loadingOverlay";
import LoadingCenter from "@/components/loadingCenter";
import MenuItemRow from "@/components/menuItemRow";
import Text from "@/components/Text";
import Styles from "@/constants/Styles";
@@ -89,9 +89,11 @@ export default function DiscussionDivisionEdit() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
} catch (error: any) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal mengubah data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}
@@ -168,7 +170,7 @@ export default function DiscussionDivisionEdit() {
)
}}
/>
<LoadingOverlay visible={loading} />
{loading && <LoadingCenter />}
<ScrollView showsVerticalScrollIndicator={false} style={[Styles.h100]}>
<View style={[Styles.p15]}>
<InputForm
@@ -186,33 +188,38 @@ export default function DiscussionDivisionEdit() {
{
(fileForm.length > 0 || dataFile.filter((val) => !val.delete).length > 0)
&&
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { borderColor: colors.background, backgroundColor: colors.card }]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
{
dataFile.filter((val) => !val.delete).map((item, index) => (
<BorderBottomItem
key={index}
borderType={(fileForm.length + dataFile.length) > 1 ? "bottom" : "none"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name + '.' + item.extension}
titleWeight="normal"
onPress={() => { setIndexDelFile({ id: item.id, cat: "oldFile" }); setModalFile(true) }}
/>
))
}
{
fileForm.map((item, index) => (
<BorderBottomItem
key={index}
borderType={fileForm.length > 1 ? "bottom" : "none"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
titleWeight="normal"
onPress={() => { setIndexDelFile({ id: index, cat: "newFile" }); setModalFile(true) }}
/>
))
}
</View>
<>
<View style={[Styles.rowSpaceBetween, Styles.mv05]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
<Text style={[Styles.textDefault]}>{fileForm.length + dataFile.filter((val) => !val.delete).length} file</Text>
</View>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
{
dataFile.filter((val) => !val.delete).map((item, index) => (
<BorderBottomItem
key={index}
borderType={dataFile.filter((val) => !val.delete).length - 1 == index && fileForm.length == 0 ? "none" : "bottom"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name + '.' + item.extension}
titleWeight="normal"
onPress={() => { setIndexDelFile({ id: item.id, cat: "oldFile" }); setModalFile(true) }}
/>
))
}
{
fileForm.map((item, index) => (
<BorderBottomItem
key={index}
borderType={fileForm.length - 1 == index ? "none" : "bottom"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
titleWeight="normal"
onPress={() => { setIndexDelFile({ id: index, cat: "newFile" }); setModalFile(true) }}
/>
))
}
</View>
</>
}
</View>
</ScrollView>

View File

@@ -202,8 +202,11 @@ export default function DiscussionDetail() {
setKomentar("")
updateTrigger()
}
} catch (error) {
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menambahkan komentar"
Toast.show({ type: 'small', text1: message })
} finally {
setLoadingSend(false);
}
@@ -222,8 +225,11 @@ export default function DiscussionDetail() {
} else {
Toast.show({ type: 'small', text1: response.message })
}
} catch (error) {
} catch (error : any ) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengedit komentar"
Toast.show({ type: 'small', text1: message })
} finally {
setLoadingSend(false);
handleViewEditKomentar()
@@ -243,8 +249,11 @@ export default function DiscussionDetail() {
} else {
Toast.show({ type: 'small', text1: response.message })
}
} catch (error) {
} catch (error : any ) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menghapus komentar"
Toast.show({ type: 'small', text1: message })
} finally {
setLoadingSend(false)
setVisible(false)

View File

@@ -4,7 +4,7 @@ import ButtonSaveHeader from "@/components/buttonSaveHeader"
import ButtonSelect from "@/components/buttonSelect"
import DrawerBottom from "@/components/drawerBottom"
import { InputForm } from "@/components/inputForm"
import LoadingOverlay from "@/components/loadingOverlay"
import LoadingCenter from "@/components/loadingCenter"
import MenuItemRow from "@/components/menuItemRow"
import Text from "@/components/Text"
import Styles from "@/constants/Styles"
@@ -81,9 +81,11 @@ export default function CreateDiscussionDivision() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menambahkan data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}
@@ -119,7 +121,7 @@ export default function CreateDiscussionDivision() {
)
}}
/>
<LoadingOverlay visible={loading} />
{loading && <LoadingCenter />}
<ScrollView showsVerticalScrollIndicator={false} style={[Styles.h100]}>
<View style={[Styles.p15, Styles.mb100]}>
<InputForm
@@ -135,21 +137,27 @@ export default function CreateDiscussionDivision() {
{
fileForm.length > 0
&&
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { borderColor: colors.background, backgroundColor: colors.card }]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
{
fileForm.map((item, index) => (
<BorderBottomItem
key={index}
borderType={fileForm.length > 1 ? "bottom" : "none"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
titleWeight="normal"
onPress={() => { setIndexDelFile(index); setModalFile(true) }}
/>
))
}
</View>
<>
<View style={[Styles.rowSpaceBetween, Styles.mv05]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
<Text style={[Styles.textDefault]}>{fileForm.length} file</Text>
</View>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
{
fileForm.map((item, index) => (
<BorderBottomItem
key={index}
borderType={fileForm.length - 1 == index ? "none" : "bottom"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
titleWeight="normal"
onPress={() => { setIndexDelFile(index); setModalFile(true) }}
/>
))
}
</View>
</>
}
</View>
</ScrollView>

View File

@@ -235,9 +235,11 @@ export default function DocumentDivision() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
} catch (error : any ) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal mengubah nama"
Toast.show({ type: 'small', text1: message })
} finally {
setLoadingRename(false)
setRename(false)
@@ -258,9 +260,11 @@ export default function DocumentDivision() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
} catch (error : any ) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal menghapus"
Toast.show({ type: 'small', text1: message })
}
}
@@ -284,9 +288,11 @@ export default function DocumentDivision() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
} catch (error : any ) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal membagikan"
Toast.show({ type: 'small', text1: message })
} finally {
setShare(false);
}

View File

@@ -120,9 +120,11 @@ export default function TaskDivisionAddFile() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
} catch (error : any ) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal menambahkan file"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}

View File

@@ -86,9 +86,11 @@ export default function AddMemberTask() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error : any ) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menambahkan anggota"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}

View File

@@ -133,9 +133,11 @@ export default function TaskDivisionAddTask() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
} catch (error : any ) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal menambahkan data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}

View File

@@ -62,9 +62,11 @@ export default function TaskDivisionCancel() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
} catch (error : any ) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal membatalkan kegiatan"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}

View File

@@ -80,9 +80,11 @@ export default function TaskDivisionEdit() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
} catch (error : any ) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal mengubah data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}

View File

@@ -80,9 +80,11 @@ export default function TaskDivisionReport() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
} catch (error : any ) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal mengubah data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}

View File

@@ -105,9 +105,11 @@ export default function CreateTaskDivision() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error : any ) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menambahkan data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}

View File

@@ -125,9 +125,11 @@ export default function UpdateProjectTaskDivision() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
} catch (error : any ) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal mengubah data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoadingSubmit(false)
}

View File

@@ -89,9 +89,11 @@ export default function AddMemberDivision() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menambahkan anggota"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}

View File

@@ -56,9 +56,11 @@ export default function EditDivision() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengubah data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}

View File

@@ -78,9 +78,11 @@ export default function InformationDivision() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengeluarkan anggota"
Toast.show({ type: 'small', text1: message })
} finally {
setModal(false)
}
@@ -96,9 +98,11 @@ export default function InformationDivision() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengubah status admin"
Toast.show({ type: 'small', text1: message })
} finally {
setModal(false)
}

View File

@@ -94,8 +94,11 @@ export default function ReportDivision() {
} else {
Toast.show({ type: 'small', text1: response.message, });
}
} catch (error) {
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengambil data"
Toast.show({ type: 'small', text1: message })
}
}

View File

@@ -77,9 +77,11 @@ export default function CreateDivision() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menambahkan data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoadingBtn(false)
}

View File

@@ -66,9 +66,11 @@ export default function CreateDivisionAddAdmin() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error : any ) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menambahkan data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}

View File

@@ -241,7 +241,6 @@ export default function ListDivision() {
</View>
}
title={item.name}
titleWeight="normal"
/>
)
}}

View File

@@ -112,8 +112,11 @@ export default function Report() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengambil data"
Toast.show({ type: 'small', text1: message })
}
}

View File

@@ -188,9 +188,14 @@ export default function EditProfile() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Gagal mengupdate data', })
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengupdate data"
Toast.show({
type: 'small',
text1: message
})
} finally {
setLoading(false)
}

View File

@@ -55,9 +55,11 @@ export default function MemberDetail() {
} else {
Toast.show({ type: 'small', text1: response.message })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Gagal mengambil data' })
} catch (error : any ) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengambil data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}

View File

@@ -1,6 +1,7 @@
import AppHeader from "@/components/AppHeader";
import ButtonSaveHeader from "@/components/buttonSaveHeader";
import { InputForm } from "@/components/inputForm";
import LoadingCenter from "@/components/loadingCenter";
import ModalSelect from "@/components/modalSelect";
import SelectForm from "@/components/selectForm";
import Text from "@/components/Text";
@@ -184,9 +185,11 @@ export default function CreateMember() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error : any ) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menambahkan data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}
@@ -228,6 +231,7 @@ export default function CreateMember() {
)
}}
/>
{loading && <LoadingCenter />}
<KeyboardAvoidingView
style={[Styles.h100, { backgroundColor: colors.background }]}
behavior={Platform.OS === 'ios' ? 'padding' : undefined}

View File

@@ -1,6 +1,7 @@
import AppHeader from "@/components/AppHeader";
import ButtonSaveHeader from "@/components/buttonSaveHeader";
import { InputForm } from "@/components/inputForm";
import LoadingCenter from "@/components/loadingCenter";
import ModalSelect from "@/components/modalSelect";
import SelectForm from "@/components/selectForm";
import Text from "@/components/Text";
@@ -210,9 +211,11 @@ export default function EditMember() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error : any ) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menambahkan data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}
@@ -261,7 +264,7 @@ export default function EditMember() {
)
}}
/>
{loading && <LoadingCenter />}
<KeyboardAvoidingView
style={[Styles.h100, { backgroundColor: colors.background }]}
behavior={Platform.OS === 'ios' ? 'padding' : undefined}

View File

@@ -88,8 +88,11 @@ export default function Index() {
const hasil = await decryptToken(String(token?.current))
const response = await apiDeletePosition({ user: hasil, isActive: chooseData.active }, chooseData.id)
dispatch(setUpdatePosition(!update))
} catch (error) {
console.error(error)
} catch (error : any ) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menghapus data"
Toast.show({ type: 'small', text1: message })
} finally {
setModal(false)
Toast.show({ type: 'small', text1: 'Berhasil mengupdate data', })
@@ -107,8 +110,11 @@ export default function Index() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
} catch (error : any ) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengubah data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoadingSubmit(false)
setVisibleEdit(false)

View File

@@ -3,6 +3,7 @@ import BorderBottomItem from "@/components/borderBottomItem"
import ButtonSaveHeader from "@/components/buttonSaveHeader"
import ButtonSelect from "@/components/buttonSelect"
import DrawerBottom from "@/components/drawerBottom"
import LoadingCenter from "@/components/loadingCenter"
import MenuItemRow from "@/components/menuItemRow"
import Styles from "@/constants/Styles"
import { apiAddFileProject, apiCheckFileProject } from "@/lib/api"
@@ -117,9 +118,11 @@ export default function ProjectAddFile() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
} catch (error : any ) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal menambahkan data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}
@@ -155,13 +158,16 @@ export default function ProjectAddFile() {
)
}}
/>
<ScrollView style={[Styles.h100, { backgroundColor: colors.background }]}>
<View style={[Styles.p15, Styles.mb100]}>
{
loading && <LoadingCenter size="large" />
}
<ScrollView style={[Styles.flex1, { backgroundColor: colors.background }]}>
<View style={[Styles.p15]}>
<ButtonSelect value="Upload File" onPress={pickDocumentAsync} />
{
listFile.length > 0 && (
<View style={[Styles.mb15]}>
<Text style={[Styles.textDefaultSemiBold, Styles.mv05]}>File</Text>
<Text style={[Styles.textDefaultSemiBold, Styles.mv05, { color: colors.text }]}>File</Text>
<View style={[Styles.wrapPaper, { backgroundColor: colors.card, borderColor: colors.background }]}>
{
listFile.map((item, index) => (
@@ -182,9 +188,6 @@ export default function ProjectAddFile() {
{
loadingCheck && <ActivityIndicator size="small" />
}
{
loading && <ActivityIndicator size="large" />
}
</View>
</ScrollView>
<DrawerBottom animation="slide" isVisible={isModal} setVisible={setModal} title="Menu">

View File

@@ -45,9 +45,11 @@ export default function AddMemberProject() {
setIdGroup(responseGroup.data.idGroup)
const responsemember = await apiGetUser({ user: hasil, active: "true", search: search, group: String(responseGroup.data.idGroup) })
setData(responsemember.data.filter((i: any) => i.idUserRole != 'supadmin'))
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error : any ) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengambil data"
Toast.show({ type: 'small', text1: message })
}
}
@@ -86,9 +88,11 @@ export default function AddMemberProject() {
dispatch(setUpdateProject({ ...update, member: !update.member }))
router.back()
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error : any ) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menambahkan anggota"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}
@@ -100,7 +104,7 @@ export default function AddMemberProject() {
<Stack.Screen
options={{
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
headerTitle: 'Tambah Anggota Kegiatan',
headerTitle: 'Tambah Anggota',
headerTitleAlign: 'center',
// headerRight: () => (
// <ButtonSaveHeader
@@ -113,7 +117,7 @@ export default function AddMemberProject() {
// )
header: () => (
<AppHeader
title="Tambah Anggota Kegiatan"
title="Tambah Anggota"
showBack={true}
onPressLeft={() => router.back()}
right={
@@ -165,7 +169,7 @@ export default function AddMemberProject() {
return (
<Pressable
key={index}
style={[Styles.itemSelectModal]}
style={[Styles.itemSelectModal, { borderColor: colors.icon + '20' }]}
onPress={() => {
!found && onChoose(item.id, item.name, item.img)
}}

View File

@@ -126,9 +126,11 @@ export default function ProjectAddTask() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
} catch (error : any ) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal menambahkan data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}
@@ -197,7 +199,7 @@ export default function ProjectAddTask() {
/>
</View>
<View style={[Styles.mv10]}>
<View style={[Styles.rowSpaceBetween]}>
<View style={[Styles.rowSpaceBetween, Styles.mb10]}>
<View style={[Styles.w48]}>
<Text style={[Styles.mb05]}>
Tanggal Mulai <Text style={{ color: colors.error }}>*</Text>

View File

@@ -58,9 +58,11 @@ export default function ProjectCancel() {
Toast.show({ type: 'small', text1: 'Berhasil membatalkan kegiatan', })
router.back();
}
} catch (error) {
} catch (error : any ) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal membatalkan kegiatan"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}

View File

@@ -77,9 +77,11 @@ export default function EditProject() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
} catch (error : any ) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal mengubah data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}

View File

@@ -77,9 +77,11 @@ export default function ReportProject() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
} catch (error : any ) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal mengubah data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}

View File

@@ -5,6 +5,7 @@ import ButtonSelect from "@/components/buttonSelect";
import DrawerBottom from "@/components/drawerBottom";
import ImageUser from "@/components/imageNew";
import { InputForm } from "@/components/inputForm";
import LoadingCenter from "@/components/loadingCenter";
import MenuItemRow from "@/components/menuItemRow";
import ModalSelect from "@/components/modalSelect";
import SectionListAddTask from "@/components/project/sectionListAddTask";
@@ -150,9 +151,11 @@ export default function CreateProject() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error : any ) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menambahkan data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoading(false)
}
@@ -230,6 +233,9 @@ export default function CreateProject() {
)
}}
/>
{
loading && <LoadingCenter />
}
<ScrollView
showsVerticalScrollIndicator={false}
style={[Styles.h100, { backgroundColor: colors.background }]}

View File

@@ -183,7 +183,7 @@ export default function CreateProjectAddTask() {
/>
</View>
<View style={[Styles.mv10]}>
<View style={[Styles.rowSpaceBetween]}>
<View style={[Styles.rowSpaceBetween, Styles.mb10]}>
<View style={[{ width: "48%" }]}>
<Text style={[Styles.mb05]}>
Tanggal Mulai <Text style={{ color: colors.error }}>*</Text>

View File

@@ -319,6 +319,7 @@ export default function ListProject() {
content="page"
title={item.title}
headerColor="primary"
titleTail={2}
>
<ProgressBar value={item.progress} category="list" />
<View style={[Styles.rowSpaceBetween]}>

View File

@@ -118,9 +118,11 @@ export default function UpdateProjectTask() {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
} catch (error : any ) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal mengubah data"
Toast.show({ type: 'small', text1: message })
} finally {
setLoadingSubmit(false)
}
@@ -233,7 +235,7 @@ export default function UpdateProjectTask() {
</View>
<View style={[Styles.mv10]}>
<View style={[Styles.rowSpaceBetween]}>
<View style={[Styles.rowSpaceBetween, Styles.mb10]}>
<View style={[{ width: '48%' }]}>
<Text style={[Styles.mb05]}>Tanggal Mulai <Text style={{ color: colors.error }}>*</Text></Text>
<View style={[Styles.wrapPaper, Styles.noShadow, Styles.borderAll, Styles.p10, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>

View File

@@ -65,9 +65,14 @@ export default function Search() {
setDataDivisi([])
setDataProject([])
}
} catch (error) {
console.error(error)
return Toast.show({ type: 'small', text1: 'Gagal melakukan pencarian', })
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal melakukan pencarian"
Toast.show({
type: 'small',
text1: message
})
}
}

View File

@@ -3,13 +3,14 @@ import Text from "@/components/Text";
import ButtonSetting from "@/components/buttonSetting";
import DrawerBottom from "@/components/drawerBottom";
import Styles from "@/constants/Styles";
import { apiRegisteredToken, apiUnregisteredToken } from "@/lib/api";
import { checkPermission, getToken, openSettings, requestPermission } from "@/lib/useNotification";
import { apiGetCheckToken, apiRegisteredToken, apiUnregisteredToken } from "@/lib/api";
import { checkPermission, getToken, openSettings } from "@/lib/useNotification";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { Feather, Ionicons } from "@expo/vector-icons";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { router } from "expo-router";
import { useCallback, useEffect, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import { AppState, AppStateStatus, Pressable, View } from "react-native";
import { useSelector } from "react-redux";
@@ -28,12 +29,14 @@ export default function ListSetting() {
const [showLogoutModal, setShowLogoutModal] = useState(false)
const [showThemeModal, setShowThemeModal] = useState(false)
const prevOsPermission = useRef<boolean | undefined>(undefined);
const registerToken = async () => {
try {
await AsyncStorage.setItem('@notification_permission', "true");
const token = await getToken();
if (token) {
await apiRegisteredToken({ user: entities.id, token });
await apiRegisteredToken({ user: entities.id, token, category: "register" });
}
} catch (error) {
console.warn('Error registering token:', error);
@@ -42,9 +45,10 @@ export default function ListSetting() {
const unregisterToken = async () => {
try {
await AsyncStorage.setItem('@notification_permission', "false");
const token = await getToken();
if (token) {
await apiUnregisteredToken({ user: entities.id, token });
await apiUnregisteredToken({ user: entities.id, token, category: "unregister" });
}
} catch (error) {
console.warn('Error unregistering token:', error);
@@ -52,15 +56,31 @@ export default function ListSetting() {
};
const checkNotif = useCallback(async () => {
const status = await checkPermission();
setIsNotificationEnabled((prev) => {
if (prev === false && status === true) {
registerToken();
} else if (prev === true && status === false) {
unregisterToken();
const osPermission = await checkPermission();
// Jika dari tidak diijinkan sistem kemudian diijinkan (setelah balik dari pengaturan device)
if (prevOsPermission.current === false && osPermission === true) {
await registerToken();
}
prevOsPermission.current = osPermission;
if (!osPermission) {
setIsNotificationEnabled(false);
return;
}
try {
const token = await getToken();
if (token) {
const response = await apiGetCheckToken({ user: entities.id, token });
setIsNotificationEnabled(!!response.data);
} else {
setIsNotificationEnabled(false);
}
return !!status;
});
} catch (error) {
console.warn('Error checking token status:', error);
setIsNotificationEnabled(false);
}
}, [entities.id]);
useEffect(() => {
@@ -78,10 +98,12 @@ export default function ListSetting() {
}, [checkNotif]);
const handleToggleNotif = async () => {
if (isNotificationEnabled) {
const osPermission = await checkPermission();
if (!osPermission) {
setModalConfig({
title: "Matikan Notifikasi?",
message: "Anda akan diarahkan ke pengaturan sistem untuk mematikan notifikasi.",
title: "Aktifkan Notifikasi?",
message: "Izin notifikasi tidak diberikan. Buka pengaturan sistem untuk mengaktifkannya?",
confirmText: "Buka Pengaturan",
onConfirm: () => {
setModalVisible(false);
@@ -90,22 +112,15 @@ export default function ListSetting() {
});
setModalVisible(true);
} else {
const granted = await requestPermission();
if (granted) {
setIsNotificationEnabled(true);
registerToken();
// OS Permission is granted, perform in-app toggle
const targetState = !isNotificationEnabled;
if (targetState) {
await registerToken();
} else {
setModalConfig({
title: "Aktifkan Notifikasi?",
message: "Izin notifikasi tidak diberikan. Buka pengaturan sistem untuk mengaktifkannya?",
confirmText: "Buka Pengaturan",
onConfirm: () => {
setModalVisible(false);
openSettings();
}
});
setModalVisible(true);
await unregisterToken();
}
// UI will be updated by checkNotif (triggered by state change or manually here)
setIsNotificationEnabled(targetState);
}
};

2587
bun.lock Normal file

File diff suppressed because it is too large Load Diff

BIN
bun.lockb

Binary file not shown.

View File

@@ -1,6 +1,5 @@
import Styles from '@/constants/Styles';
import { useTheme } from "@/providers/ThemeProvider";
import { useRouter } from 'expo-router';
import { Platform, Text, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import ButtonBackHeader from './buttonBackHeader';
@@ -15,13 +14,12 @@ type Props = {
export default function AppHeader({ title, right, showBack = true, onPressLeft, left }: Props) {
const insets = useSafeAreaInsets();
const router = useRouter();
const { colors } = useTheme();
return (
<View style={[Styles.headerContainer, Platform.OS === 'ios' ? Styles.pb05 : Styles.pb13, { backgroundColor: colors.header, paddingTop: Platform.OS === 'ios' ? insets.top : 10 }]}>
<View style={Styles.headerApp}>
<View style={[Styles.rowItemsCenter]}>
<View style={[Styles.rowItemsCenter, Styles.flex1]}>
{showBack ? (
<ButtonBackHeader onPress={onPressLeft} />
) :
@@ -30,7 +28,9 @@ export default function AppHeader({ title, right, showBack = true, onPressLeft,
<View style={Styles.headerSide} />
)}
<Text style={[Styles.headerTitle, Styles.ml05]}>{title}</Text>
<Text style={[Styles.headerTitle, Styles.ml05, Styles.flex1, Styles.mr10]} numberOfLines={1} ellipsizeMode="tail">
{title ? title.charAt(0).toUpperCase() + title.slice(1) : ""}
</Text>
</View>
<View style={Styles.headerSide}>{right}</View>
</View>

42
components/ErrorView.tsx Normal file
View File

@@ -0,0 +1,42 @@
import Text from '@/components/Text';
import Styles from '@/constants/Styles';
import { useTheme } from '@/providers/ThemeProvider';
import { MaterialCommunityIcons } from "@expo/vector-icons";
import React from 'react';
import { View } from 'react-native';
interface ErrorViewProps {
title?: string;
message?: string;
icon?: keyof typeof MaterialCommunityIcons.glyphMap;
}
/**
* ErrorView component to display error or empty states.
* Used when data is not found, deleted, or an error occurs during fetching.
*/
export default function ErrorView({
title = "Terjadi Kesalahan",
message = "Data tidak ditemukan atau sudah dihapus.",
icon = "alert-circle-outline"
}: ErrorViewProps) {
const { colors } = useTheme();
return (
<View style={[Styles.flex1, Styles.contentItemCenter, Styles.ph20]}>
<View style={[Styles.mb10]}>
<MaterialCommunityIcons
name={icon}
size={40}
color={colors.dimmed}
/>
</View>
<Text style={[Styles.textDefaultSemiBold, { color: colors.text, textAlign: 'center' }]}>
{title}
</Text>
<Text style={[Styles.textMediumNormal, { color: colors.dimmed, textAlign: 'center', marginTop: 4 }]}>
{message}
</Text>
</View>
);
}

View File

@@ -0,0 +1,121 @@
import React from 'react';
import { Modal, View, Image, TouchableOpacity, BackHandler, Platform } from 'react-native';
import { useTheme } from '@/providers/ThemeProvider';
import Text from './Text';
import * as Linking from 'expo-linking';
import Styles from '@/constants/Styles';
interface ModalUpdateMaintenanceProps {
visible: boolean;
type: 'update' | 'maintenance';
isForceUpdate?: boolean;
onDismiss?: () => void;
appName?: string;
customDescription?: string;
androidStoreUrl?: string;
iosStoreUrl?: string;
}
const ModalUpdateMaintenance: React.FC<ModalUpdateMaintenanceProps> = ({
visible,
type,
isForceUpdate = false,
onDismiss,
appName = 'Desa+',
customDescription,
androidStoreUrl = 'https://play.google.com/store/apps/details?id=mobiledarmasaba.app',
iosStoreUrl = 'https://apps.apple.com/id/app/desa-plus-desa/id6752375538'
}) => {
const { colors } = useTheme();
const handleUpdate = () => {
const storeUrl = Platform.OS === 'ios' ? iosStoreUrl : androidStoreUrl;
Linking.openURL(storeUrl);
};
const handleCloseApp = () => {
// For maintenance mode, we might want to exit the app or just keep the modal.
// React Native doesn't have a built-in "exit" for iOS, but for Android:
if (Platform.OS === 'android') {
BackHandler.exitApp();
}
};
return (
<Modal
visible={visible}
animationType="fade"
transparent={false}
onRequestClose={() => {
if (!isForceUpdate && type === 'update') {
onDismiss?.();
}
}}
>
<View style={[Styles.modalUpdateContainer, { backgroundColor: colors.primary }]}>
{/* Background decorative circles could be added here if we had SVGs or images */}
<View style={Styles.modalUpdateDecorativeCircle1} />
<View style={Styles.modalUpdateDecorativeCircle2} />
<View style={Styles.modalUpdateContent}>
<Image
source={require('@/assets/images/logo-dark.png')}
style={Styles.modalUpdateLogo}
resizeMode="contain"
/>
<View style={Styles.modalUpdateTextContainer}>
<Text style={Styles.modalUpdateTitle}>
{type === 'update' ? 'Update Tersedia' : 'Perbaikan'}
</Text>
<Text style={[Styles.modalUpdateDescription, { opacity: 0.8 }]}>
{customDescription ? customDescription :
(type === 'update'
? `Versi terbaru dari ${appName} tersedia di Store. Silakan buka Store untuk menginstalnya.`
: 'Aplikasi saat ini sedang dalam pemeliharaan untuk peningkatan sistem. Silakan coba kembali beberapa saat lagi.')}
</Text>
</View>
<View style={Styles.modalUpdateButtonContainer}>
{type === 'update' ? (
<>
<TouchableOpacity
style={[Styles.modalUpdatePrimaryButton, { backgroundColor: 'white' }]}
onPress={handleUpdate}
activeOpacity={0.8}
>
<Text style={[Styles.modalUpdatePrimaryButtonText, { color: colors.primary }]}>
Update
</Text>
</TouchableOpacity>
{!isForceUpdate && (
<TouchableOpacity
style={Styles.modalUpdateSecondaryButton}
onPress={onDismiss}
activeOpacity={0.7}
>
<Text style={Styles.modalUpdateSecondaryButtonText}>Nanti</Text>
</TouchableOpacity>
)}
</>
) : (
<></>
// <TouchableOpacity
// style={[Styles.modalUpdatePrimaryButton, { backgroundColor: 'white' }]}
// onPress={handleCloseApp}
// activeOpacity={0.8}
// >
// <Text style={[Styles.modalUpdatePrimaryButtonText, { color: colors.primary }]}>
// {Platform.OS === 'android' ? 'Close App' : 'Please check back later'}
// </Text>
// </TouchableOpacity>
)}
</View>
</View>
</View>
</Modal>
);
};
export default ModalUpdateMaintenance;

View File

@@ -31,15 +31,14 @@ export default function HeaderRightAnnouncementDetail({ id }: Props) {
const hasil = await decryptToken(String(token?.current))
const response = await apiDeleteAnnouncement({ user: hasil }, id)
if (response.success) {
dispatch(setUpdateAnnouncement(!update))
setVisible(false)
Toast.show({ type: 'small', text1: 'Berhasil menghapus data', })
router.back()
dispatch(setUpdateAnnouncement(!update))
return Toast.show({ type: 'small', text1: 'Berhasil menghapus data', })
}
} catch (error) {
console.error(error)
} finally {
setVisible(false)
setShowDeleteModal(false)
}
}

View File

@@ -22,7 +22,7 @@ export default function ViewLogin({ onValidate }: Props) {
const [disableLogin, setDisableLogin] = useState(true)
const [phone, setPhone] = useState('')
const { signIn, encryptToken } = useAuthSession();
const { colors, theme } = useTheme();
const { colors, activeTheme } = useTheme();
const handleCheckPhone = async () => {
try {
@@ -38,13 +38,18 @@ export default function ViewLogin({ onValidate }: Props) {
if (responseOtp == 200) {
await AsyncStorage.setItem('user', response.id)
return onValidate({ phone: `62${phone}`, otp })
} else {
return Toast.show({ type: 'small', text1: 'Gagal mengirim kode verifikasi', position: 'bottom' })
}
}
} else {
return Toast.show({ type: 'small', text1: response.message, position: 'bottom' })
}
} catch (error) {
return Toast.show({ type: 'small', text1: `Terjadi kesalahan, coba lagi`, position: 'bottom' })
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal login"
Toast.show({ type: 'small', text1: message })
} finally {
setLoadingLogin(false)
}
@@ -52,11 +57,11 @@ export default function ViewLogin({ onValidate }: Props) {
return (
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<StatusBar style={theme === 'dark' ? 'light' : 'dark'} translucent={false} backgroundColor={colors.background} />
<StatusBar style={activeTheme === 'dark' ? 'light' : 'dark'} translucent={false} backgroundColor={colors.background} />
<View style={[Styles.p20, Styles.h100]}>
<View style={{ alignItems: "center", marginTop: 70, marginBottom: 50 }}>
<Image
source={theme === 'dark' ? require("../../assets/images/logo-dark.png") : require("../../assets/images/logo.png")}
source={activeTheme === 'dark' ? require("../../assets/images/logo-dark.png") : require("../../assets/images/logo.png")}
style={[{ width: 300, height: 150 }]}
width={270}
height={110}
@@ -82,7 +87,7 @@ export default function ViewLogin({ onValidate }: Props) {
<View style={{ flex: 1 }} />
<View style={{ alignItems: 'center' }}>
<Image
source={theme === 'dark' ? require("../../assets/images/cogniti-dark.png") : require("../../assets/images/cogniti-light.png")}
source={activeTheme === 'dark' ? require("../../assets/images/cogniti-dark.png") : require("../../assets/images/cogniti-light.png")}
style={{ width: 86, height: 27 }}
resizeMode="contain"
/>

View File

@@ -21,7 +21,7 @@ export default function ViewVerification({ phone, otp }: Props) {
const [value, setValue] = useState('');
const [otpFix, setOtpFix] = useState(otp)
const { signIn, encryptToken } = useAuthSession();
const { colors, theme } = useTheme();
const { colors, activeTheme } = useTheme();
const login = async () => {
const valueUser = await AsyncStorage.getItem('user');
@@ -59,11 +59,11 @@ export default function ViewVerification({ phone, otp }: Props) {
return (
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<StatusBar style={theme === 'dark' ? 'light' : 'dark'} translucent={false} backgroundColor={colors.background} />
<StatusBar style={activeTheme === 'dark' ? 'light' : 'dark'} translucent={false} backgroundColor={colors.background} />
<View style={[Styles.p20, Styles.h100]} >
<View style={{ alignItems: "center", marginTop: 70, marginBottom: 50 }}>
<Image
source={theme === 'dark' ? require("../../assets/images/logo-dark.png") : require("../../assets/images/logo.png")}
source={activeTheme === 'dark' ? require("../../assets/images/logo-dark.png") : require("../../assets/images/logo.png")}
style={[{ width: 300, height: 150 }]}
width={270}
height={110}
@@ -101,7 +101,7 @@ export default function ViewVerification({ phone, otp }: Props) {
<View style={{ flex: 1 }} />
<View style={[{ alignItems: 'center' }]}>
<Image
source={theme === 'dark' ? require("../../assets/images/cogniti-dark.png") : require("../../assets/images/cogniti-light.png")}
source={activeTheme === 'dark' ? require("../../assets/images/cogniti-dark.png") : require("../../assets/images/cogniti-light.png")}
style={{ width: 86, height: 27 }}
resizeMode="contain"
/>

View File

@@ -48,7 +48,7 @@ export default function BorderBottomItem({ title, subtitle, icon, desc, onPress,
{icon}
<View style={[Styles.rowSpaceBetween, Styles.flex1]}>
<View style={[Styles.ml10, Styles.flex1, Styles.mr10]}>
<Text style={[titleWeight == 'normal' ? Styles.textDefault : Styles.textDefaultSemiBold, { color: textColorFix }]} numberOfLines={titleShowAll ? 0 : 1} ellipsizeMode='tail'>{title}</Text>
<Text style={[titleWeight == 'normal' ? Styles.textDefault : Styles.textDefaultSemiBold, { color: textColorFix }]} numberOfLines={titleShowAll ? 0 : 1} ellipsizeMode='tail'>{title ? title.charAt(0).toUpperCase() + title.slice(1) : ""}</Text>
{
subtitle &&
typeof subtitle == "string"

View File

@@ -10,7 +10,7 @@ export default function ButtonNextHeader({ onPress, disable }: Props) {
return (
<>
<ButtonHeader
item={<Feather name="chevron-right" size={20} color={disable ? "grey" : "white"} />}
item={<Feather name="chevron-right" size={25} color={disable ? "grey" : "white"} />}
onPress={() => {
!disable && onPress && onPress()
}}

View File

@@ -38,9 +38,11 @@ export default function HeaderRightCalendarDetail({ id, idReminder }: Props) {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
} catch (error : any ) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
const message = error?.response?.data?.message || "Gagal menghapus data"
Toast.show({ type: 'small', text1: message })
} finally {
setVisible(false)
}

View File

@@ -40,9 +40,11 @@ export default function HeaderRightDiscussionDetail({ id, status, isActive }: Pr
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error : any ) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengubah data"
Toast.show({ type: 'small', text1: message })
} finally {
setVisible(false)
}
@@ -59,9 +61,11 @@ export default function HeaderRightDiscussionDetail({ id, status, isActive }: Pr
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error : any ) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengubah data"
Toast.show({ type: 'small', text1: message })
} finally {
setVisible(false)
}

View File

@@ -18,7 +18,7 @@ export default function DiscussionItem({ title, user, date, onPress }: Props) {
<View style={[Styles.rowItemsCenter, Styles.mb10]}>
<Ionicons name="chatbox-ellipses-outline" size={22} color={colors.text} style={Styles.mr10} />
<View style={[{ flex: 1 }]}>
<Text style={{ fontWeight: 'bold' }} numberOfLines={1} ellipsizeMode="tail">{title}</Text>
<Text style={{ fontWeight: 'bold' }} numberOfLines={1} ellipsizeMode="tail">{title?.charAt(0).toUpperCase() + title?.slice(1)}</Text>
</View>
</View>
<View style={[Styles.rowSpaceBetween]}>

View File

@@ -37,9 +37,11 @@ export default function HeaderRightDivisionInfo({ id, active }: Props) {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error : any ) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengubah status"
Toast.show({ type: 'small', text1: message })
} finally {
setVisible(false)
}

View File

@@ -7,10 +7,6 @@ import Text from "../Text";
export default function ReportChartDocument({ data }: { data: { label: string; value: number; }[] }) {
const { colors } = useTheme();
const maxValue = Math.max(...data.map(i => i.value))
const barData = [
{ value: 23, label: 'Gambar', },
{ value: 12, label: 'Dokumen' },
];
const width = Dimensions.get("window").width;
return (

View File

@@ -40,9 +40,11 @@ export default function HeaderRightDocument({ path, isMember }: { path: string,
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error : any ) {
console.error(error);
const message = error?.response?.data?.message || "Gagal membuat folder"
Toast.show({ type: 'small', text1: message })
} finally {
setLoadingFolder(false)
setNewFolder(false)
@@ -93,9 +95,11 @@ export default function HeaderRightDocument({ path, isMember }: { path: string,
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error : any ) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengunggah file"
Toast.show({ type: 'small', text1: message })
} finally {
setVisible(false)
setLoading(false)

View File

@@ -18,7 +18,7 @@ type Props = {
export default function ItemFile({ category, checked, dateTime, title, onChecked, onPress, canChecked }: Props) {
const { colors } = useTheme();
return (
<View style={[Styles.wrapItemBorderBottom, { borderColor: colors.background }]}>
<View style={[Styles.wrapItemBorderBottom, { borderColor: colors.icon + '20' }]}>
<View style={[Styles.rowItemsCenter]}>
<Pressable onPress={onPress}>
{
@@ -56,8 +56,8 @@ export default function ItemFile({ category, checked, dateTime, title, onChecked
<Pressable onPress={onChecked}>
{
checked
? <MaterialCommunityIcons name="checkbox-marked-circle" size={25} color={colors.text} />
: <MaterialCommunityIcons name="checkbox-blank-circle-outline" size={25} color={colors.icon} />
? <MaterialCommunityIcons name="checkbox-marked-circle" size={25} color={colors.icon} />
: <MaterialCommunityIcons name="checkbox-blank-circle-outline" size={25} color={colors.icon + '90'} />
}
</Pressable>

View File

@@ -71,9 +71,11 @@ export default function ModalMore({
} else {
Toast.show({ type: 'small', text1: response.message, });
}
} catch (error) {
} catch (error : any ) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', });
const message = error?.response?.data?.message || "Gagal memindahkan file"
Toast.show({ type: 'small', text1: message })
} finally {
setIsCut(false);
onClose();
@@ -95,9 +97,11 @@ export default function ModalMore({
} else {
Toast.show({ type: 'small', text1: response.message, });
}
} catch (error) {
} catch (error : any ) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', });
const message = error?.response?.data?.message || "Gagal menyalin file"
Toast.show({ type: 'small', text1: message })
} finally {
setIsCopy(false);
onClose();

View File

@@ -29,9 +29,11 @@ export function ModalNewFolder({ path, onCreated }: { path: string, onCreated: (
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error)
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} catch (error : any ) {
console.error(error);
const message = error?.response?.data?.message || "Gagal membuat folder"
Toast.show({ type: 'small', text1: message })
} finally {
onCreated()
setLoadingFolder(false)

View File

@@ -13,20 +13,20 @@ type Props = {
}
export default function EventItem({ category, title, user, jamAwal, jamAkhir, onPress }: Props) {
const { theme, colors } = useTheme();
const { activeTheme, colors } = useTheme();
const getBackgroundColor = (cat: 'purple' | 'orange') => {
if (theme === 'dark') {
if (activeTheme === 'dark') {
return cat === 'orange' ? '#547792' : '#1D546D';
}
return cat === 'orange' ? '#D6E6F2' : '#A9B5DF';
};
const getStickColor = (cat: 'purple' | 'orange') => {
if (theme === 'dark') {
if (activeTheme === 'dark') {
return cat === 'orange' ? '#94B4C1' : '#5F9598';
}
return cat === 'orange' ? '#F5F5F5' : '#7886C7' ;
return cat === 'orange' ? '#F5F5F5' : '#7886C7';
};
return (

View File

@@ -92,7 +92,7 @@ export default function CaraouselHome2({ refreshing }: { refreshing: boolean })
backgroundColor: colors.primary
},
]}
resizeMode="cover"
resizeMode="stretch"
/>
)}
/>

View File

@@ -20,6 +20,7 @@ export default function ChartDokumenHome({ refreshing }: { refreshing: boolean }
const { colors } = useTheme();
const [data, setData] = useState<Props>([])
const [maxValue, setMaxValue] = useState(5)
const [chartKey, setChartKey] = useState(0)
const barData = [
{ value: 23, label: 'Gambar', frontColor: '#fac858' },
{ value: 12, label: 'Dokumen', frontColor: '#92cc76' },
@@ -32,8 +33,8 @@ export default function ChartDokumenHome({ refreshing }: { refreshing: boolean }
setLoading(loading)
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
const maxVal = response.data.reduce((max: number, obj: { value: number; }) => Math.max(max, Number(obj.value)), 0);
const roundUp = maxVal > 0 ? Math.ceil(maxVal / 10) * 10 : 10;
setMaxValue(roundUp)
const convertedArray = response.data.map((item: { color: any; label: any; value: any; }) => ({
frontColor: item.color,
@@ -41,6 +42,7 @@ export default function ChartDokumenHome({ refreshing }: { refreshing: boolean }
value: Number(item.value)
}));
setData(convertedArray)
setChartKey((prev: number) => prev + 1)
} catch (error) {
console.error(error)
} finally {
@@ -49,8 +51,9 @@ export default function ChartDokumenHome({ refreshing }: { refreshing: boolean }
}
useEffect(() => {
if (refreshing)
if (refreshing) {
handleData(false)
}
}, [refreshing]);
useEffect(() => {
@@ -64,6 +67,7 @@ export default function ChartDokumenHome({ refreshing }: { refreshing: boolean }
loading ? <Skeleton width={100} height={200} borderRadius={10} widthType="percent" />
:
<BarChart
key={chartKey}
showFractionalValues={false}
showYAxisIndices
noOfSections={4}

Some files were not shown because too many files have changed in this diff Show More