Compare commits
38 Commits
amalia/20-
...
join
| Author | SHA1 | Date | |
|---|---|---|---|
| 887e787a99 | |||
| 772551a917 | |||
| 555b9e4037 | |||
| d4b4db4251 | |||
| 17d92cba25 | |||
| e1b62be6da | |||
| b2b125c410 | |||
| 1cfecbbdd5 | |||
| 21006e8eee | |||
| 91231d60e4 | |||
| 7174e27be1 | |||
| 9d4b931aa6 | |||
| 166d8f1c16 | |||
| 7060a2d165 | |||
| d6217aecf1 | |||
| 608381673f | |||
| 3cc7f76346 | |||
| 868b712fbb | |||
| a53b99b39d | |||
| 25d521f013 | |||
| aee0823cb1 | |||
| 2a0e1f4c1f | |||
| ef08c821fa | |||
| fd5d582092 | |||
| 7729dc38f8 | |||
| 8c6ff06216 | |||
| 214a243e44 | |||
| 449f6f96cc | |||
| d1dec49784 | |||
| e351f54f6c | |||
| d58a35bde2 | |||
| e2a601c590 | |||
| f0373ef479 | |||
| 700192dd8d | |||
| 27b0b7d51f | |||
| 65278df750 | |||
| 8b98fee632 | |||
| e254cf8ed2 |
@@ -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
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 904 B |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 5.2 KiB |
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -210,7 +214,7 @@ export default function CreateAnnouncement() {
|
||||
<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, { borderColor: colors.icon + '20' }]}>
|
||||
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
|
||||
{
|
||||
fileForm.map((item, index) => (
|
||||
<BorderBottomItem
|
||||
@@ -242,7 +246,7 @@ export default function CreateAnnouncement() {
|
||||
<View style={[Styles.rowSpaceBetween, Styles.mv05]}>
|
||||
<Text style={[Styles.textDefaultSemiBold]}>Divisi</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' }]}>
|
||||
{
|
||||
divisionMember.map((item: { name: any; Division: any }, index: any) => {
|
||||
return (
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -263,7 +268,7 @@ export default function EditAnnouncement() {
|
||||
<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, { borderColor: colors.icon + '20' }]}>
|
||||
<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
|
||||
@@ -306,7 +311,7 @@ export default function EditAnnouncement() {
|
||||
<View style={[Styles.rowSpaceBetween, Styles.mv05]}>
|
||||
<Text style={[Styles.textDefaultSemiBold]}>Divisi</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' }]}>
|
||||
{
|
||||
dataMember.map((item: { name: any; Division: any }, index: any) => {
|
||||
return (
|
||||
|
||||
@@ -106,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)
|
||||
}
|
||||
|
||||
@@ -88,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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -258,7 +260,7 @@ export default function CreateDiscussionGeneral() {
|
||||
<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, { borderColor: colors.icon + '20' }]}>
|
||||
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
|
||||
{
|
||||
fileForm.map((item, index) => (
|
||||
<BorderBottomItem
|
||||
@@ -302,7 +304,7 @@ export default function CreateDiscussionGeneral() {
|
||||
<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 (
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -234,7 +238,7 @@ export default function EditDiscussionGeneral() {
|
||||
<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, { borderColor: colors.icon + '20' }]}>
|
||||
<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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -241,7 +241,6 @@ export default function ListDivision() {
|
||||
</View>
|
||||
}
|
||||
title={item.name}
|
||||
titleWeight="normal"
|
||||
/>
|
||||
)
|
||||
}}
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -185,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)
|
||||
}
|
||||
|
||||
@@ -211,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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -118,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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -151,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)
|
||||
}
|
||||
|
||||
@@ -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]}>
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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
@@ -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>
|
||||
);
|
||||
}
|
||||
121
components/ModalUpdateMaintenance.tsx
Normal 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;
|
||||
@@ -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"
|
||||
/>
|
||||
|
||||
@@ -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"
|
||||
/>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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]}>
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -92,7 +92,7 @@ export default function CaraouselHome2({ refreshing }: { refreshing: boolean })
|
||||
backgroundColor: colors.primary
|
||||
},
|
||||
]}
|
||||
resizeMode="cover"
|
||||
resizeMode="stretch"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -63,7 +63,7 @@ export default function DivisionHome({ refreshing }: { refreshing: boolean }) {
|
||||
<Pressable style={[Styles.wrapPaper, Styles.mb05, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]} key={index} onPress={() => { router.push(`/division/${item.id}`) }}>
|
||||
<View style={[Styles.rowSpaceBetween, { alignItems: 'center' }]}>
|
||||
<View>
|
||||
<Text style={[Styles.textDefaultSemiBold]}>{item.name}</Text>
|
||||
<Text style={[Styles.textDefaultSemiBold]}>{item.name?.charAt(0).toUpperCase() + item.name?.slice(1)}</Text>
|
||||
<Text style={[Styles.textDefault]}>{item.jumlah} Kegiatan</Text>
|
||||
</View>
|
||||
<Feather name="chevron-right" size={20} color={colors.text} />
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Styles from "@/constants/Styles";
|
||||
import { apiGetDataHome } from "@/lib/api";
|
||||
import { useAuthSession } from "@/providers/AuthProvider";
|
||||
import { useTheme } from "@/providers/ThemeProvider";
|
||||
import { router } from "expo-router";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Dimensions, View } from "react-native";
|
||||
@@ -10,7 +11,6 @@ import PaperGridContent from "../paperGridContent";
|
||||
import ProgressBar from "../progressBar";
|
||||
import Skeleton from "../skeleton";
|
||||
import Text from "../Text";
|
||||
import { useTheme } from "@/providers/ThemeProvider";
|
||||
|
||||
type Props = {
|
||||
id: string
|
||||
@@ -52,7 +52,7 @@ export default function ProjectHome({ refreshing }: { refreshing: boolean }) {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View style={[Styles.mb15]}>
|
||||
<View style={[Styles.mb05]}>
|
||||
<Text style={[Styles.textDefaultSemiBold, Styles.mb10]}>Kegiatan Terupdate</Text>
|
||||
{
|
||||
loading ? (<Skeleton width={100} height={150} borderRadius={10} widthType="percent" />)
|
||||
@@ -62,7 +62,7 @@ export default function ProjectHome({ refreshing }: { refreshing: boolean }) {
|
||||
ref={ref}
|
||||
style={{ width: "100%" }}
|
||||
width={width * 0.8}
|
||||
height={235}
|
||||
height={220}
|
||||
data={data}
|
||||
loop={false}
|
||||
autoPlay={false}
|
||||
|
||||
@@ -37,8 +37,11 @@ export default function HeaderRightMemberDetail({ active, id }: Props) {
|
||||
} 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 {
|
||||
setVisible(false)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ export default function PaperGridContent({ content, children, title, headerColor
|
||||
const bgSource = activeTheme === 'light' ? bgLight : bgDark;
|
||||
return (
|
||||
<Pressable onPress={onPress}>
|
||||
<View style={[content == 'carousel' ? Styles.wrapGridCaraousel : Styles.wrapGridContent]}>
|
||||
<View style={[content == 'carousel' ? Styles.wrapGridCaraousel : Styles.wrapGridContent, { backgroundColor: colors.card }]}>
|
||||
{
|
||||
headerColor == 'warning' ? (
|
||||
<View style={[Styles.headerPaperGrid, ColorsStatus.warning]}>
|
||||
@@ -35,13 +35,12 @@ export default function PaperGridContent({ content, children, title, headerColor
|
||||
imageStyle={{ borderTopLeftRadius: 5, borderTopRightRadius: 5 }}
|
||||
style={[Styles.headerPaperGrid, { backgroundColor: colors.primary }]}
|
||||
>
|
||||
<Text numberOfLines={titleTail ? titleTail : undefined} style={[Styles.textSubtitle, Styles.cWhite, { textAlign: 'center' }]}>{title}</Text>
|
||||
<Text numberOfLines={titleTail ? titleTail : undefined} style={[Styles.textSubtitle, Styles.cWhite, { textAlign: 'center' }]}>{title.charAt(0).toUpperCase() + title.slice(1)}</Text>
|
||||
</ImageBackground>
|
||||
)
|
||||
}
|
||||
<View style={[
|
||||
contentPosition && contentPosition == 'top' ? Styles.contentPaperGrid2 : Styles.contentPaperGrid,
|
||||
{ backgroundColor: colors.card },
|
||||
height ? { height: height } : {}
|
||||
]}>
|
||||
{children}
|
||||
|
||||