Compare commits
14 Commits
amalia/23-
...
amalia/03-
| Author | SHA1 | Date | |
|---|---|---|---|
| 7d8b72fdfa | |||
| e9c11a889d | |||
| 73c6a19880 | |||
| 225ed63027 | |||
| f34df12b2f | |||
| a24a698f86 | |||
| 6b55433c02 | |||
| 13cf7ef9c5 | |||
| febb56f6e9 | |||
| 8da7c598a7 | |||
| 6cc5d07017 | |||
| 7a589e11e4 | |||
| c230e0b18b | |||
| 2433cf4bc9 |
153
QWEN.md
Normal file
153
QWEN.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# Desa+ Mobile Application - Project Overview
|
||||
|
||||
## Project Summary
|
||||
Desa+ is a comprehensive village/desa management mobile application built with React Native and Expo. The application serves as a digital platform for village administration, community communication, and information management. It provides various features to facilitate village governance, resident communication, and administrative tasks.
|
||||
|
||||
## Architecture & Technology Stack
|
||||
- **Framework**: React Native with Expo (SDK 53)
|
||||
- **State Management**: Redux Toolkit with React-Redux
|
||||
- **Navigation**: Expo Router with React Navigation
|
||||
- **Backend Services**: Firebase (Authentication, Realtime Database, Cloud Messaging)
|
||||
- **UI Components**: Custom-built components with React Native elements
|
||||
- **Language**: TypeScript for type safety
|
||||
- **Build System**: EAS (Expo Application Service) for builds and deployments
|
||||
|
||||
## Key Features
|
||||
- Announcement and village information system
|
||||
- Community discussion forums
|
||||
- Village event calendar
|
||||
- Document management and archiving
|
||||
- Project and task management
|
||||
- Member and organizational structure management
|
||||
- Push notifications for important updates
|
||||
- Verification and authentication features
|
||||
|
||||
## Project Structure
|
||||
```
|
||||
├── app/ # Application routes and pages (Expo Router)
|
||||
│ ├── (application)/ # Main application screens
|
||||
│ │ ├── announcement/
|
||||
│ │ ├── banner/
|
||||
│ │ ├── discussion/
|
||||
│ │ ├── division/
|
||||
│ │ ├── group/
|
||||
│ │ ├── member/
|
||||
│ │ ├── position/
|
||||
│ │ ├── project/
|
||||
│ │ ├── _layout.tsx
|
||||
│ │ ├── edit-profile.tsx
|
||||
│ │ ├── feature.tsx
|
||||
│ │ ├── home.tsx
|
||||
│ │ ├── notification.tsx
|
||||
│ │ ├── profile.tsx
|
||||
│ │ └── search.tsx
|
||||
│ ├── _layout.tsx # Root layout
|
||||
│ ├── index.tsx # Splash/login screen
|
||||
│ ├── verification.tsx # OTP verification screen
|
||||
├── components/ # Reusable UI components
|
||||
│ ├── announcement/
|
||||
│ ├── auth/
|
||||
│ ├── banner/
|
||||
│ ├── calendar/
|
||||
│ ├── discussion/
|
||||
│ ├── division/
|
||||
│ ├── document/
|
||||
│ ├── group/
|
||||
│ ├── home/
|
||||
│ ├── member/
|
||||
│ ├── position/
|
||||
│ ├── project/
|
||||
│ ├── task/
|
||||
│ ├── alertKonfirmasi.ts
|
||||
│ ├── AppHeader.tsx
|
||||
│ ├── Text.tsx
|
||||
│ └── ... (many more components)
|
||||
├── constants/ # Constants and styles
|
||||
│ ├── Colors.ts
|
||||
│ ├── ColorsStatus.ts
|
||||
│ ├── ConstEnv.ts
|
||||
│ ├── Headers.ts
|
||||
│ ├── RoleUser.ts
|
||||
│ ├── Styles.ts
|
||||
│ └── ... (other constants)
|
||||
├── assets/ # Static assets (images, fonts)
|
||||
├── lib/ # Business logic and API utilities
|
||||
├── providers/ # Context providers (AuthProvider)
|
||||
├── android/ # Android native code
|
||||
├── ios/ # iOS native code
|
||||
├── scripts/ # Build and utility scripts
|
||||
├── index.js # Entry point
|
||||
├── app.config.js # Expo configuration
|
||||
├── package.json # Dependencies and scripts
|
||||
└── eas.json # EAS build configuration
|
||||
```
|
||||
|
||||
## Environment Configuration
|
||||
The application uses environment variables defined in a `.env` file:
|
||||
- `URL_API` - API endpoint
|
||||
- `URL_OTP` - OTP service endpoint
|
||||
- `URL_STORAGE` - Storage endpoint
|
||||
- `URL_FIREBASE_DB` - Firebase database URL
|
||||
- `PASS_ENC` - Encryption password
|
||||
- `WA_SERVER_TOKEN` - WhatsApp server token
|
||||
- `IOS_GOOGLE_SERVICES_FILE` - Path to iOS Google services file
|
||||
|
||||
## Building and Running
|
||||
|
||||
### Development
|
||||
1. Install dependencies:
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
2. Run the development server:
|
||||
```bash
|
||||
npx expo start
|
||||
```
|
||||
|
||||
3. For platform-specific builds:
|
||||
- Android: `npm run android`
|
||||
- iOS: `npm run ios`
|
||||
- Web: `npm run web`
|
||||
|
||||
### Production Builds
|
||||
- Android: `npm run build:android` (uses EAS to build an app bundle)
|
||||
|
||||
### Testing
|
||||
- Run tests: `npm run test`
|
||||
|
||||
### Linting
|
||||
- Check code quality: `npm run lint`
|
||||
|
||||
## Key Dependencies
|
||||
- `@react-native-firebase/*` - Firebase integration
|
||||
- `@react-navigation/*` - Navigation solutions
|
||||
- `@reduxjs/toolkit` - State management
|
||||
- `expo-router` - File-based routing
|
||||
- `react-native-gesture-handler` - Touch gesture support
|
||||
- `react-native-reanimated` - Advanced animations
|
||||
- `react-native-svg` - SVG rendering support
|
||||
|
||||
## Development Conventions
|
||||
- Uses TypeScript for type safety
|
||||
- Implements custom styling through the Styles.ts constant file
|
||||
- Follows Expo's file-based routing convention
|
||||
- Uses Redux Toolkit for centralized state management
|
||||
- Implements custom components in the components directory
|
||||
- Uses absolute imports with @/ alias (e.g., "@/components/...")
|
||||
- Implements Firebase for authentication and real-time data
|
||||
|
||||
## Deployment
|
||||
- Uses EAS for building and submitting to app stores
|
||||
- Supports both Android (APK and App Bundle) and iOS (TestFlight/App Store)
|
||||
- Configured for internal testing, preview, and production distributions
|
||||
|
||||
## Special Features
|
||||
- Background message handling for push notifications
|
||||
- Biometric authentication support
|
||||
- Image picking and media library access
|
||||
- Document picker functionality
|
||||
- Date/time pickers with localization
|
||||
- Custom toast notifications
|
||||
- Carousel components for featured content
|
||||
- Data visualization with charts
|
||||
124
README.md
124
README.md
@@ -1,50 +1,114 @@
|
||||
# Welcome to your Expo app 👋
|
||||
# Desa+
|
||||
|
||||
This is an [Expo](https://expo.dev) project created with [`create-expo-app`](https://www.npmjs.com/package/create-expo-app).
|
||||
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.
|
||||
|
||||
## Get started
|
||||
## Fitur Utama
|
||||
|
||||
1. Install dependencies
|
||||
- 📢 Pengumuman dan informasi desa
|
||||
- 💬 Forum diskusi komunitas
|
||||
- 📅 Kalender kegiatan desa
|
||||
- 📄 Dokumentasi dan arsip desa
|
||||
- 📊 Pengelolaan proyek dan tugas desa
|
||||
- 👥 Manajemen anggota dan struktur organisasi
|
||||
- 📱 Notifikasi push untuk informasi penting
|
||||
- 🎯 Fitur verifikasi dan otentikasi
|
||||
|
||||
## Teknologi yang Digunakan
|
||||
|
||||
- [React Native](https://reactnative.dev/) - Framework mobile cross-platform
|
||||
- [Expo](https://expo.dev/) - Platform pengembangan aplikasi React Native
|
||||
- [Firebase](https://firebase.google.com/) - Backend services (Authentication, Realtime Database, Cloud Messaging)
|
||||
- [Redux Toolkit](https://redux-toolkit.js.org/) - State management
|
||||
- [React Navigation](https://reactnavigation.org/) - Navigasi aplikasi
|
||||
- [TypeScript](https://www.typescriptlang.org/) - Type safety
|
||||
|
||||
## Instalasi
|
||||
|
||||
1. Clone repository ini
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd mobile-darmasaba
|
||||
```
|
||||
|
||||
2. Install dependencies
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
2. Start the app
|
||||
|
||||
```bash
|
||||
npx expo start
|
||||
3. Konfigurasi environment variables
|
||||
Buat file `.env` di root direktori dan tambahkan variabel berikut:
|
||||
```
|
||||
URL_API=<api-endpoint>
|
||||
URL_OTP=<otp-service-endpoint>
|
||||
URL_STORAGE=<storage-endpoint>
|
||||
URL_FIREBASE_DB=<firebase-database-url>
|
||||
PASS_ENC=<encryption-password>
|
||||
WA_SERVER_TOKEN=<whatsapp-server-token>
|
||||
IOS_GOOGLE_SERVICES_FILE=<path-to-ios-google-services>
|
||||
```
|
||||
|
||||
In the output, you'll find options to open the app in a
|
||||
4. Jalankan aplikasi
|
||||
```bash
|
||||
npx expo start
|
||||
```
|
||||
|
||||
- [development build](https://docs.expo.dev/develop/development-builds/introduction/)
|
||||
- [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/)
|
||||
- [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/)
|
||||
- [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo
|
||||
## Struktur Proyek
|
||||
|
||||
You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction).
|
||||
|
||||
## Get a fresh project
|
||||
|
||||
When you're ready, run:
|
||||
|
||||
```bash
|
||||
npm run reset-project
|
||||
```
|
||||
├── app/ # File-file halaman utama
|
||||
├── components/ # Komponen reusable
|
||||
│ ├── announcement/ # Komponen pengumuman
|
||||
│ ├── auth/ # Komponen otentikasi
|
||||
│ ├── discussion/ # Komponen forum diskusi
|
||||
│ ├── document/ # Komponen dokumentasi
|
||||
│ ├── project/ # Komponen pengelolaan proyek
|
||||
│ └── ...
|
||||
├── assets/ # Gambar dan aset statis
|
||||
├── constants/ # Konstanta global
|
||||
├── lib/ # Library dan utilitas
|
||||
└── ...
|
||||
```
|
||||
|
||||
This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing.
|
||||
## Platform Support
|
||||
|
||||
## Learn more
|
||||
Aplikasi ini didukung untuk:
|
||||
- ✅ Android
|
||||
- ✅ iOS
|
||||
- ❌ Web (belum dioptimalkan)
|
||||
|
||||
To learn more about developing your project with Expo, look at the following resources:
|
||||
## Development
|
||||
|
||||
- [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides).
|
||||
- [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web.
|
||||
Untuk menjalankan aplikasi di masing-masing platform:
|
||||
|
||||
## Join the community
|
||||
### Android
|
||||
```bash
|
||||
npm run android
|
||||
```
|
||||
|
||||
Join our community of developers creating universal apps.
|
||||
### iOS
|
||||
```bash
|
||||
npm run ios
|
||||
```
|
||||
|
||||
- [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute.
|
||||
- [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions.
|
||||
### Build Production
|
||||
|
||||
Untuk membuat build production Android:
|
||||
```bash
|
||||
npm run build:android
|
||||
```
|
||||
|
||||
## Kontribusi
|
||||
|
||||
1. Fork repository ini
|
||||
2. Buat branch fitur baru (`git checkout -b fitur/NamaFitur`)
|
||||
3. Commit perubahan Anda (`git commit -m 'Tambahkan fitur NamaFitur'`)
|
||||
4. Push ke branch (`git push origin fitur/NamaFitur`)
|
||||
5. Buat pull request
|
||||
|
||||
## Lisensi
|
||||
|
||||
Proyek ini dilisensikan di bawah lisensi MIT - lihat file [LICENSE](LICENSE) untuk detail selengkapnya.
|
||||
|
||||
## Dukungan
|
||||
|
||||
Jika Anda menemukan masalah atau memiliki pertanyaan, silakan buka issue di repository ini.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import HeaderRightAnnouncementList from "@/components/announcement/headerAnnouncementList";
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import HeaderDiscussionGeneral from "@/components/discussion_general/headerDiscussionGeneral";
|
||||
import HeaderRightDivisionList from "@/components/division/headerDivisionList";
|
||||
import HeaderRightGroupList from "@/components/group/headerGroupList";
|
||||
@@ -8,7 +8,6 @@ import HeaderRightPositionList from "@/components/position/headerRightPositionLi
|
||||
import HeaderRightProjectList from "@/components/project/headerProjectList";
|
||||
import Text from "@/components/Text";
|
||||
import ToastCustom from "@/components/toastCustom";
|
||||
import { Headers } from "@/constants/Headers";
|
||||
import { apiReadOneNotification } from "@/lib/api";
|
||||
import { pushToPage } from "@/lib/pushToPage";
|
||||
import store from "@/lib/store";
|
||||
@@ -91,60 +90,121 @@ export default function RootLayout() {
|
||||
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<Stack screenOptions={Headers.shadow} >
|
||||
<Stack screenOptions={{
|
||||
headerShown: true,
|
||||
animation: "slide_from_right",
|
||||
|
||||
// ⬇️ PENTING BANGET
|
||||
animationTypeForReplace: "pop",
|
||||
fullScreenGestureEnabled: true,
|
||||
gestureEnabled: true,
|
||||
}} >
|
||||
<Stack.Screen name="home" options={{ title: 'Home' }} />
|
||||
<Stack.Screen name="feature" options={{ title: 'Fitur' }} />
|
||||
<Stack.Screen name="search" options={{ title: 'Pencarian' }} />
|
||||
<Stack.Screen name="notification" options={{
|
||||
title: 'Notifikasi',
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Notifikasi',
|
||||
headerTitleAlign: 'center'
|
||||
headerTitleAlign: 'center',
|
||||
header: () => (
|
||||
<AppHeader title="Notifikasi" showBack={true} onPressLeft={() => router.back()} />
|
||||
)
|
||||
}} />
|
||||
<Stack.Screen name="profile" options={{ title: 'Profile' }} />
|
||||
<Stack.Screen name="member/index" options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
title: 'Anggota',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <HeaderMemberList />
|
||||
// headerRight: () => <HeaderMemberList />
|
||||
header: () => (
|
||||
<AppHeader title="Anggota"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={<HeaderMemberList />}
|
||||
/>
|
||||
)
|
||||
}} />
|
||||
<Stack.Screen name="discussion/index" options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
title: 'Diskusi Umum',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <HeaderDiscussionGeneral />
|
||||
// headerRight: () => <HeaderDiscussionGeneral />
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Diskusi Umum"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={<HeaderDiscussionGeneral />}
|
||||
/>
|
||||
)
|
||||
}} />
|
||||
<Stack.Screen name="project/index" options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
title: 'Kegiatan',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <HeaderRightProjectList />
|
||||
// headerRight: () => <HeaderRightProjectList />
|
||||
header: () => (
|
||||
<AppHeader title="Kegiatan"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={<HeaderRightProjectList />}
|
||||
/>
|
||||
)
|
||||
}} />
|
||||
<Stack.Screen name="division/index" options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
title: 'Divisi',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <HeaderRightDivisionList />
|
||||
// headerRight: () => <HeaderRightDivisionList />
|
||||
header: () => (
|
||||
<AppHeader title="Divisi"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={<HeaderRightDivisionList />}
|
||||
/>
|
||||
)
|
||||
}} />
|
||||
<Stack.Screen name="division/[id]/(fitur-division)" options={{ headerShown: false }} />
|
||||
<Stack.Screen name="group/index" options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Lembaga Desa',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <HeaderRightGroupList />
|
||||
// headerRight: () => <HeaderRightGroupList />
|
||||
header: () => (
|
||||
<AppHeader title="Lembaga Desa"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={<HeaderRightGroupList />}
|
||||
/>
|
||||
)
|
||||
}} />
|
||||
<Stack.Screen name="position/index" options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Jabatan',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <HeaderRightPositionList />
|
||||
// headerRight: () => <HeaderRightPositionList />
|
||||
header: () => (
|
||||
<AppHeader title="Jabatan"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={<HeaderRightPositionList />}
|
||||
/>
|
||||
)
|
||||
}} />
|
||||
<Stack.Screen name="announcement/index"
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Pengumuman',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <HeaderRightAnnouncementList />
|
||||
// headerRight: () => <HeaderRightAnnouncementList />
|
||||
header: () => (
|
||||
<AppHeader title="Pengumuman"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={<HeaderRightAnnouncementList />}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import HeaderRightAnnouncementDetail from "@/components/announcement/headerAnnouncementDetail";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import BorderBottomItem from "@/components/borderBottomItem";
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import Skeleton from "@/components/skeleton";
|
||||
import Text from '@/components/Text';
|
||||
import { ConstEnv } from "@/constants/ConstEnv";
|
||||
import { isImageFile } from "@/constants/FileExtensions";
|
||||
import Styles from "@/constants/Styles";
|
||||
import { apiGetAnnouncementOne } from "@/lib/api";
|
||||
import { useAuthSession } from "@/providers/AuthProvider";
|
||||
@@ -13,24 +14,46 @@ import { startActivityAsync } from 'expo-intent-launcher';
|
||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||
import * as Sharing from 'expo-sharing';
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Alert, Dimensions, Platform, RefreshControl, SafeAreaView, ScrollView, View } from "react-native";
|
||||
import { Alert, Dimensions, Platform, Pressable, RefreshControl, SafeAreaView, ScrollView, View } from "react-native";
|
||||
import ImageViewing from 'react-native-image-viewing';
|
||||
import * as mime from 'react-native-mime-types';
|
||||
import RenderHTML from 'react-native-render-html';
|
||||
import Toast from "react-native-toast-message";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
type Props = {
|
||||
id: string
|
||||
title: string
|
||||
desc: string
|
||||
// Define TypeScript interfaces for better type safety
|
||||
interface AnnouncementData {
|
||||
id: string;
|
||||
title: string;
|
||||
desc: string;
|
||||
}
|
||||
|
||||
interface FileData {
|
||||
id: string;
|
||||
idStorage: string;
|
||||
name: string;
|
||||
extension: string;
|
||||
}
|
||||
|
||||
interface MemberData {
|
||||
group: string;
|
||||
division: string;
|
||||
}
|
||||
|
||||
interface ApiResponse {
|
||||
success: boolean;
|
||||
data: AnnouncementData;
|
||||
member: Record<string, MemberData[]>;
|
||||
file: FileData[];
|
||||
message: string;
|
||||
}
|
||||
|
||||
export default function DetailAnnouncement() {
|
||||
const { id } = useLocalSearchParams<{ id: string }>();
|
||||
const { token, decryptToken } = useAuthSession()
|
||||
const [data, setData] = useState<Props>({ id: '', title: '', desc: '' })
|
||||
const [dataMember, setDataMember] = useState<any>({})
|
||||
const [dataFile, setDataFile] = useState<{ id: string; idStorage: string; name: string; extension: string }[]>([])
|
||||
const [data, setData] = useState<AnnouncementData>({ id: '', title: '', desc: '' })
|
||||
const [dataMember, setDataMember] = useState<Record<string, MemberData[]>>({})
|
||||
const [dataFile, setDataFile] = useState<FileData[]>([])
|
||||
const update = useSelector((state: any) => state.announcementUpdate)
|
||||
const entityUser = useSelector((state: any) => state.user)
|
||||
const contentWidth = Dimensions.get('window').width
|
||||
@@ -38,13 +61,24 @@ export default function DetailAnnouncement() {
|
||||
const arrSkeleton = Array.from({ length: 2 }, (_, index) => index)
|
||||
const [refreshing, setRefreshing] = useState(false)
|
||||
const [loadingOpen, setLoadingOpen] = useState(false)
|
||||
const [preview, setPreview] = useState(false)
|
||||
const [chooseFile, setChooseFile] = useState<FileData>()
|
||||
|
||||
/**
|
||||
* Opens the image preview modal for the selected image file
|
||||
* @param item The file data object containing image information
|
||||
*/
|
||||
function handleChooseFile(item: FileData) {
|
||||
setChooseFile(item)
|
||||
setPreview(true)
|
||||
}
|
||||
|
||||
|
||||
async function handleLoad(loading: boolean) {
|
||||
try {
|
||||
setLoading(loading)
|
||||
const hasil = await decryptToken(String(token?.current))
|
||||
const response = await apiGetAnnouncementOne({ id: id, user: hasil })
|
||||
const response: ApiResponse = await apiGetAnnouncementOne({ id: id, user: hasil })
|
||||
if (response.success) {
|
||||
setData(response.data)
|
||||
setDataMember(response.member)
|
||||
@@ -68,30 +102,47 @@ export default function DetailAnnouncement() {
|
||||
handleLoad(true)
|
||||
}, [])
|
||||
|
||||
/**
|
||||
* Checks if a string contains HTML tags
|
||||
* @param text The text to check for HTML tags
|
||||
* @returns True if the text contains HTML tags, false otherwise
|
||||
*/
|
||||
function hasHtmlTags(text: string) {
|
||||
const htmlRegex = /<[a-z][\s\S]*>/i;
|
||||
return htmlRegex.test(text);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles pull-to-refresh functionality
|
||||
* Reloads the announcement data without showing loading indicators
|
||||
*/
|
||||
const handleRefresh = async () => {
|
||||
setRefreshing(true)
|
||||
handleLoad(false)
|
||||
// Simulate network request delay for better UX
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
setRefreshing(false)
|
||||
};
|
||||
|
||||
const openFile = (item: { idStorage: string; name: string; extension: string }) => {
|
||||
if (Platform.OS == 'android') setLoadingOpen(true)
|
||||
let remoteUrl = ConstEnv.url_storage + '/files/' + item.idStorage;
|
||||
const fileName = item.name + '.' + item.extension;
|
||||
let localPath = `${FileSystem.documentDirectory}/${fileName}`;
|
||||
const mimeType = mime.lookup(fileName)
|
||||
const openFile = async (item: FileData) => {
|
||||
try {
|
||||
setLoadingOpen(true);
|
||||
const remoteUrl = ConstEnv.url_storage + '/files/' + item.idStorage;
|
||||
const fileName = item.name + '.' + item.extension;
|
||||
const localPath = `${FileSystem.documentDirectory}/${fileName}`;
|
||||
const mimeType = mime.lookup(fileName);
|
||||
|
||||
// Download the file
|
||||
const downloadResult = await FileSystem.downloadAsync(remoteUrl, localPath);
|
||||
|
||||
if (downloadResult.status !== 200) {
|
||||
throw new Error(`Download failed with status ${downloadResult.status}`);
|
||||
}
|
||||
|
||||
const contentURL = await FileSystem.getContentUriAsync(downloadResult.uri);
|
||||
|
||||
FileSystem.downloadAsync(remoteUrl, localPath).then(async ({ uri }) => {
|
||||
const contentURL = await FileSystem.getContentUriAsync(uri);
|
||||
setLoadingOpen(false)
|
||||
try {
|
||||
if (Platform.OS == 'android') {
|
||||
if (Platform.OS === 'android') {
|
||||
await startActivityAsync(
|
||||
'android.intent.action.VIEW',
|
||||
{
|
||||
@@ -100,25 +151,41 @@ export default function DetailAnnouncement() {
|
||||
type: mimeType as string,
|
||||
}
|
||||
);
|
||||
} else if (Platform.OS == 'ios') {
|
||||
Sharing.shareAsync(localPath);
|
||||
} else if (Platform.OS === 'ios') {
|
||||
await Sharing.shareAsync(localPath);
|
||||
}
|
||||
} catch (error) {
|
||||
Alert.alert('INFO', 'Gagal membuka file, tidak ada aplikasi yang dapat membuka file ini');
|
||||
} finally {
|
||||
if (Platform.OS == 'android') setLoadingOpen(false)
|
||||
} catch (openError) {
|
||||
console.error('Error opening file:', openError);
|
||||
Alert.alert('INFO', 'Tidak ada aplikasi yang dapat membuka file ini');
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error downloading or opening file:', error);
|
||||
Alert.alert('INFO', 'Gagal mengunduh atau membuka file');
|
||||
Toast.show({
|
||||
type: 'error',
|
||||
text1: 'Gagal membuka file',
|
||||
text2: 'Silakan coba lagi nanti'
|
||||
});
|
||||
} finally {
|
||||
setLoadingOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Pengumuman',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => entityUser.role != 'user' && entityUser.role != 'coadmin' ? <HeaderRightAnnouncementDetail id={id} /> : <></>,
|
||||
// headerRight: () => entityUser.role != 'user' && entityUser.role != 'coadmin' ? <HeaderRightAnnouncementDetail id={id} /> : <></>,
|
||||
header: () => (
|
||||
<AppHeader title="Pengumuman"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={entityUser.role != 'user' && entityUser.role != 'coadmin' ? <HeaderRightAnnouncementDetail id={id} /> : <></>}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView
|
||||
@@ -131,7 +198,7 @@ export default function DetailAnnouncement() {
|
||||
/>
|
||||
}
|
||||
>
|
||||
<View style={[Styles.p15]}>
|
||||
<View style={[Styles.p15, Styles.mb50]}>
|
||||
<View style={[Styles.wrapPaper]}>
|
||||
{
|
||||
loading ?
|
||||
@@ -176,12 +243,20 @@ export default function DetailAnnouncement() {
|
||||
</View>
|
||||
{dataFile.map((item, index) => (
|
||||
<BorderBottomItem
|
||||
key={index}
|
||||
key={`${item.id}-${index}`}
|
||||
borderType="bottom"
|
||||
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
|
||||
title={item.name}
|
||||
icon={<MaterialCommunityIcons
|
||||
name={isImageFile(item.extension) ? "file-image-outline" : "file-document-outline"}
|
||||
size={25}
|
||||
color="black"
|
||||
/>}
|
||||
title={item.name + '.' + item.extension}
|
||||
titleWeight="normal"
|
||||
onPress={() => { openFile({ idStorage: item.idStorage, name: item.name, extension: item.extension }) }}
|
||||
onPress={() => {
|
||||
isImageFile(item.extension) ?
|
||||
handleChooseFile(item)
|
||||
: openFile(item)
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
@@ -222,6 +297,45 @@ export default function DetailAnnouncement() {
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
|
||||
<ImageViewing
|
||||
images={[{ uri: `${ConstEnv.url_storage}/files/${chooseFile?.idStorage}` }]}
|
||||
imageIndex={0}
|
||||
visible={preview}
|
||||
onRequestClose={() => setPreview(false)}
|
||||
doubleTapToZoomEnabled
|
||||
HeaderComponent={({ imageIndex }) => (
|
||||
<View style={[Styles.headerModalViewImg]}>
|
||||
{/* CLOSE */}
|
||||
<Pressable
|
||||
onPress={() => setPreview(false)}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Close image viewer"
|
||||
>
|
||||
<Text style={{ color: 'white', fontSize: 26 }}>✕</Text>
|
||||
</Pressable>
|
||||
|
||||
{/* MENU */}
|
||||
<Pressable
|
||||
onPress={() => chooseFile && openFile(chooseFile)}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Download or share image"
|
||||
disabled={loadingOpen}
|
||||
>
|
||||
<Text style={{ color: loadingOpen ? 'gray' : 'white', fontSize: 22 }}>⋯</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
)}
|
||||
FooterComponent={({ imageIndex }) => (
|
||||
<View style={{
|
||||
paddingBottom: 20,
|
||||
paddingHorizontal: 16,
|
||||
alignItems: 'center',
|
||||
}}>
|
||||
<Text style={{ color: 'white', fontSize: 16 }}>{chooseFile?.name}.{chooseFile?.extension}</Text>
|
||||
</View>
|
||||
)}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import BorderBottomItem from "@/components/borderBottomItem";
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import ButtonSelect from "@/components/buttonSelect";
|
||||
import DrawerBottom from "@/components/drawerBottom";
|
||||
@@ -15,7 +15,7 @@ import { useAuthSession } from "@/providers/AuthProvider";
|
||||
import { Entypo, Ionicons, MaterialCommunityIcons } from "@expo/vector-icons";
|
||||
import * as DocumentPicker from "expo-document-picker";
|
||||
import { router, Stack } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { SafeAreaView, ScrollView, StyleSheet, View } from "react-native";
|
||||
import Toast from "react-native-toast-message";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
@@ -132,26 +132,44 @@ export default function CreateAnnouncement() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Tambah Pengumuman",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={disableBtn || divisionMember.length == 0 || loading ? true : false}
|
||||
category="create"
|
||||
onPress={() => {
|
||||
divisionMember.length == 0
|
||||
? Toast.show({ type: 'small', text1: "Anda belum memilih divisi", })
|
||||
: handleCreate();
|
||||
}}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// disable={disableBtn || divisionMember.length == 0 || loading ? true : false}
|
||||
// category="create"
|
||||
// onPress={() => {
|
||||
// divisionMember.length == 0
|
||||
// ? Toast.show({ type: 'small', text1: "Anda belum memilih divisi", })
|
||||
// : handleCreate();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Tambah Pengumuman"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={disableBtn || divisionMember.length == 0 || loading ? true : false}
|
||||
category="create"
|
||||
onPress={() => {
|
||||
divisionMember.length == 0
|
||||
? Toast.show({ type: 'small', text1: "Anda belum memilih divisi", })
|
||||
: handleCreate();
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<LoadingOverlay visible={loading} />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import BorderBottomItem from "@/components/borderBottomItem";
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import ButtonSelect from "@/components/buttonSelect";
|
||||
import DrawerBottom from "@/components/drawerBottom";
|
||||
@@ -183,26 +183,44 @@ export default function EditAnnouncement() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Edit Pengumuman",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={disableBtn || loading ? true : false}
|
||||
category="update"
|
||||
onPress={() => {
|
||||
dataMember.length == 0
|
||||
? Toast.show({ type: 'small', text1: "Anda belum memilih divisi", })
|
||||
: handleEdit();
|
||||
}}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// disable={disableBtn || loading ? true : false}
|
||||
// category="update"
|
||||
// onPress={() => {
|
||||
// dataMember.length == 0
|
||||
// ? Toast.show({ type: 'small', text1: "Anda belum memilih divisi", })
|
||||
// : handleEdit();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Edit Pengumuman"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={disableBtn || loading ? true : false}
|
||||
category="update"
|
||||
onPress={() => {
|
||||
dataMember.length == 0
|
||||
? Toast.show({ type: 'small', text1: "Anda belum memilih divisi", })
|
||||
: handleEdit();
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<LoadingOverlay visible={loading} />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import Text from "@/components/Text";
|
||||
@@ -115,19 +115,32 @@ export default function EditBanner() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Edit Banner",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => <ButtonSaveHeader
|
||||
disable={title == "" || error || loading ? true : false}
|
||||
onPress={() => { handleUpdateEntity() }}
|
||||
category="update" />,
|
||||
// headerRight: () => <ButtonSaveHeader
|
||||
// disable={title == "" || error || loading ? true : false}
|
||||
// onPress={() => { handleUpdateEntity() }}
|
||||
// category="update" />,
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Edit Banner"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={title == "" || error || loading ? true : false}
|
||||
onPress={() => { handleUpdateEntity() }}
|
||||
category="update" />
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView showsVerticalScrollIndicator={false} style={[Styles.h100]}>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import Text from "@/components/Text";
|
||||
@@ -97,24 +97,40 @@ export default function CreateBanner() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Tambah Banner",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={title == "" || selectedImage == undefined || error || loading ? true : false}
|
||||
category="create"
|
||||
onPress={() => {
|
||||
handleCreateEntity();
|
||||
}}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// disable={title == "" || selectedImage == undefined || error || loading ? true : false}
|
||||
// category="create"
|
||||
// onPress={() => {
|
||||
// handleCreateEntity();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Fitur"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={title == "" || selectedImage == undefined || error || loading ? true : false}
|
||||
category="create"
|
||||
onPress={() => {
|
||||
handleCreateEntity();
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView showsVerticalScrollIndicator={false} style={[Styles.h100]}>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import AlertKonfirmasi from "@/components/alertKonfirmasi"
|
||||
import AppHeader from "@/components/AppHeader"
|
||||
import HeaderRightBannerList from "@/components/banner/headerBannerList"
|
||||
import BorderBottomItem from "@/components/borderBottomItem"
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader"
|
||||
import DrawerBottom from "@/components/drawerBottom"
|
||||
import MenuItemRow from "@/components/menuItemRow"
|
||||
import ModalLoading from "@/components/modalLoading"
|
||||
@@ -108,10 +108,20 @@ export default function BannerList() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Banner',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <HeaderRightBannerList />
|
||||
// headerRight: () => <HeaderRightBannerList />
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Banner"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<HeaderRightBannerList />
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ModalLoading isVisible={loadingOpen} setVisible={setLoadingOpen} />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import AlertKonfirmasi from "@/components/alertKonfirmasi";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import BorderBottomItem from "@/components/borderBottomItem";
|
||||
import BorderBottomItem2 from "@/components/borderBottomItem2";
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import HeaderRightDiscussionGeneralDetail from "@/components/discussion_general/headerDiscussionDetail";
|
||||
import DrawerBottom from "@/components/drawerBottom";
|
||||
import ImageUser from "@/components/imageNew";
|
||||
@@ -22,7 +22,7 @@ import { Feather, Ionicons, MaterialCommunityIcons, MaterialIcons } from "@expo/
|
||||
import { ref } from '@react-native-firebase/database';
|
||||
import { useHeaderHeight } from '@react-navigation/elements';
|
||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { KeyboardAvoidingView, Platform, Pressable, RefreshControl, ScrollView, View } from "react-native";
|
||||
import Toast from "react-native-toast-message";
|
||||
import { useSelector } from "react-redux";
|
||||
@@ -225,10 +225,18 @@ export default function DetailDiscussionGeneral() {
|
||||
<>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Diskusi',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <HeaderRightDiscussionGeneralDetail id={id} active={data?.isActive !== undefined ? data.isActive : false} status={data?.status !== undefined ? data.status : 0} />,
|
||||
// headerRight: () => <HeaderRightDiscussionGeneralDetail id={id} active={data?.isActive !== undefined ? data.isActive : false} status={data?.status !== undefined ? data.status : 0} />,
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Diskusi"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={<HeaderRightDiscussionGeneralDetail id={id} active={data?.isActive !== undefined ? data.isActive : false} status={data?.status !== undefined ? data.status : 0} />}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<View style={{ flex: 1 }}>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import ImageUser from "@/components/imageNew";
|
||||
import ImageWithLabel from "@/components/imageWithLabel";
|
||||
@@ -95,16 +95,32 @@ export default function AddMemberDiscussionDetail() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Tambah Anggota Diskusi',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
category="update"
|
||||
disable={selectMember.length == 0 || loading ? true : false}
|
||||
onPress={() => {
|
||||
handleAddMember()
|
||||
}}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// category="update"
|
||||
// disable={selectMember.length == 0 || loading ? true : false}
|
||||
// onPress={() => {
|
||||
// handleAddMember()
|
||||
// }}
|
||||
// />
|
||||
// )
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Tambah Anggota Diskusi"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
category="update"
|
||||
disable={selectMember.length == 0 || loading ? true : false}
|
||||
onPress={() => {
|
||||
handleAddMember()
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import BorderBottomItem from "@/components/borderBottomItem";
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import ButtonSelect from "@/components/buttonSelect";
|
||||
import DrawerBottom from "@/components/drawerBottom";
|
||||
@@ -166,24 +166,42 @@ export default function CreateDiscussionGeneral() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => { handleBack() }}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => { handleBack() }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Tambah Diskusi",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
category="create"
|
||||
disable={disableBtn || loading ? true : false}
|
||||
onPress={() => {
|
||||
entitiesMember.length == 0
|
||||
? Toast.show({ type: 'small', text1: 'Anda belum memilih anggota', })
|
||||
: handleCreate()
|
||||
}}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// category="create"
|
||||
// disable={disableBtn || loading ? true : false}
|
||||
// onPress={() => {
|
||||
// entitiesMember.length == 0
|
||||
// ? Toast.show({ type: 'small', text1: 'Anda belum memilih anggota', })
|
||||
// : handleCreate()
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Tambah Diskusi"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
category="create"
|
||||
disable={disableBtn || loading ? true : false}
|
||||
onPress={() => {
|
||||
entitiesMember.length == 0
|
||||
? Toast.show({ type: 'small', text1: 'Anda belum memilih anggota', })
|
||||
: handleCreate()
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<LoadingOverlay visible={loading} />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import Text from "@/components/Text";
|
||||
import BorderBottomItem from "@/components/borderBottomItem";
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import ButtonSelect from "@/components/buttonSelect";
|
||||
import DrawerBottom from "@/components/drawerBottom";
|
||||
@@ -165,22 +165,36 @@ export default function EditDiscussionGeneral() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Edit Diskusi",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={disableBtn || loading ? true : false}
|
||||
category="update"
|
||||
onPress={() => { handleEdit() }}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// disable={disableBtn || loading ? true : false}
|
||||
// category="update"
|
||||
// onPress={() => { handleEdit() }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Edit Diskusi"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={disableBtn || loading ? true : false}
|
||||
category="update"
|
||||
onPress={() => { handleEdit() }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<LoadingOverlay visible={loading} />
|
||||
|
||||
@@ -121,8 +121,9 @@ export default function Discussion() {
|
||||
<InputSearch onChange={setSearch} />
|
||||
{
|
||||
(entityUser.role == "supadmin" || entityUser.role == "developer") &&
|
||||
<View style={[Styles.mv05]}>
|
||||
<Text>Filter : {nameGroup}</Text>
|
||||
<View style={[Styles.mv05, Styles.rowOnly]}>
|
||||
<Text>Filter :</Text>
|
||||
<LabelStatus size="small" category="secondary" text={nameGroup} style={[Styles.mh05]} />
|
||||
</View>
|
||||
}
|
||||
</View>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import AlertKonfirmasi from "@/components/alertKonfirmasi";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import BorderBottomItem from "@/components/borderBottomItem";
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import DrawerBottom from "@/components/drawerBottom";
|
||||
import ImageUser from "@/components/imageNew";
|
||||
import MenuItemRow from "@/components/menuItemRow";
|
||||
@@ -74,9 +74,16 @@ export default function MemberDiscussionDetail() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Anggota Diskusi',
|
||||
headerTitleAlign: 'center',
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Anggota Diskusi"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader"
|
||||
import AppHeader from "@/components/AppHeader"
|
||||
import HeaderRightDiscussionList from "@/components/discussion/headerDiscussionList"
|
||||
import HeaderRightTaskList from "@/components/task/headerTaskList"
|
||||
import { Headers } from "@/constants/Headers"
|
||||
@@ -9,22 +9,49 @@ export default function RootLayout() {
|
||||
<>
|
||||
<Stack screenOptions={Headers.shadow}>
|
||||
<Stack.Screen name="task/index" options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
title: 'Tugas Divisi',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <HeaderRightTaskList />
|
||||
// headerRight: () => <HeaderRightTaskList />
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Tugas Divisi"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<HeaderRightTaskList />
|
||||
}
|
||||
/>
|
||||
)
|
||||
}} />
|
||||
<Stack.Screen name="discussion/index" options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
title: 'Diskusi Divisi',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <HeaderRightDiscussionList />
|
||||
// headerRight: () => <HeaderRightDiscussionList />
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Diskusi Divisi"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<HeaderRightDiscussionList />
|
||||
}
|
||||
/>
|
||||
)
|
||||
}} />
|
||||
<Stack.Screen name="calendar/history"
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Riwayat Acara',
|
||||
headerTitleAlign: 'center',
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Riwayat Acara"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import ImageUser from "@/components/imageNew";
|
||||
import ImageWithLabel from "@/components/imageWithLabel";
|
||||
@@ -103,16 +103,32 @@ export default function AddMemberCalendarEvent() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Tambah Anggota',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
category="update"
|
||||
disable={selectMember.length == 0 || loading ? true : false}
|
||||
onPress={() => {
|
||||
handleAddMember()
|
||||
}}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// category="update"
|
||||
// disable={selectMember.length == 0 || loading ? true : false}
|
||||
// onPress={() => {
|
||||
// handleAddMember()
|
||||
// }}
|
||||
// />
|
||||
// )
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Tambah Anggota"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
category="update"
|
||||
disable={selectMember.length == 0 || loading ? true : false}
|
||||
onPress={() => {
|
||||
handleAddMember()
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader"
|
||||
import AppHeader from "@/components/AppHeader"
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader"
|
||||
import { InputDate } from "@/components/inputDate"
|
||||
import { InputForm } from "@/components/inputForm"
|
||||
@@ -165,17 +165,33 @@ export default function EditEventCalendar() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Edit Acara',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () =>
|
||||
<ButtonSaveHeader
|
||||
disable={Object.values(error).some((val) => val == true) || data.title == "" || data.dateStart == "" || data.timeStart == "" || data.timeEnd == "" || data.repeatEventTyper == "" || loading}
|
||||
category="update-calendar"
|
||||
onPress={() => {
|
||||
handleUpdate()
|
||||
}}
|
||||
// headerRight: () =>
|
||||
// <ButtonSaveHeader
|
||||
// disable={Object.values(error).some((val) => val == true) || data.title == "" || data.dateStart == "" || data.timeStart == "" || data.timeEnd == "" || data.repeatEventTyper == "" || loading}
|
||||
// category="update-calendar"
|
||||
// onPress={() => {
|
||||
// handleUpdate()
|
||||
// }}
|
||||
// />
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Edit Acara"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={Object.values(error).some((val) => val == true) || data.title == "" || data.dateStart == "" || data.timeStart == "" || data.timeEnd == "" || data.repeatEventTyper == "" || loading}
|
||||
category="update-calendar"
|
||||
onPress={() => {
|
||||
handleUpdate()
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<KeyboardAvoidingView
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import AlertKonfirmasi from "@/components/alertKonfirmasi"
|
||||
import AppHeader from "@/components/AppHeader"
|
||||
import BorderBottomItem from "@/components/borderBottomItem"
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader"
|
||||
import HeaderRightCalendarDetail from "@/components/calendar/headerCalendarDetail"
|
||||
@@ -154,10 +155,20 @@ export default function DetailEventCalendar() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Detail Acara',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => (entityUser.role == "user" || entityUser.role == "coadmin") && !isMemberDivision ? <></> : <HeaderRightCalendarDetail id={String(data?.idCalendar)} idReminder={String(detail)} />
|
||||
// headerRight: () => (entityUser.role == "user" || entityUser.role == "coadmin") && !isMemberDivision ? <></> : <HeaderRightCalendarDetail id={String(data?.idCalendar)} idReminder={String(detail)} />
|
||||
header:()=>(
|
||||
<AppHeader
|
||||
title="Detail Acara"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
(entityUser.role == "user" || entityUser.role == "coadmin") && !isMemberDivision ? <></> : <HeaderRightCalendarDetail id={String(data?.idCalendar)} idReminder={String(detail)} />
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import ImageUser from "@/components/imageNew";
|
||||
import ImageWithLabel from "@/components/imageWithLabel";
|
||||
@@ -93,14 +93,28 @@ export default function CreateCalendarAddMember() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Pilih Anggota',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
category="create"
|
||||
disable={selectMember.length == 0 || loading ? true : false}
|
||||
onPress={() => { handleAddMember() }}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// category="create"
|
||||
// disable={selectMember.length == 0 || loading ? true : false}
|
||||
// onPress={() => { handleAddMember() }}
|
||||
// />
|
||||
// )
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Pilih Anggota"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
category="create"
|
||||
disable={selectMember.length == 0 || loading ? true : false}
|
||||
onPress={() => { handleAddMember() }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import ButtonNextHeader from "@/components/buttonNextHeader";
|
||||
import { InputDate } from "@/components/inputDate";
|
||||
@@ -7,6 +8,7 @@ import SelectForm from "@/components/selectForm";
|
||||
import Styles from "@/constants/Styles";
|
||||
import { setFormCreateCalendar } from "@/lib/calendarCreate";
|
||||
import { stringToDateTime } from "@/lib/fun_stringToDate";
|
||||
import { useHeaderHeight } from '@react-navigation/elements';
|
||||
import { Stack, router, useLocalSearchParams } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
@@ -17,7 +19,6 @@ import {
|
||||
View
|
||||
} from "react-native";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { useHeaderHeight } from '@react-navigation/elements';
|
||||
|
||||
export default function CalendarDivisionCreate() {
|
||||
const { id } = useLocalSearchParams<{ id: string }>()
|
||||
@@ -128,28 +129,44 @@ export default function CalendarDivisionCreate() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Tambah Acara",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonNextHeader
|
||||
onPress={() => { handleSetData() }}
|
||||
disable={Object.values(error).some((val) => val == true) || data.title == "" || data.dateStart == "" || data.timeStart == "" || data.timeEnd == "" || data.repeatEventType == ""}
|
||||
// headerRight: () => (
|
||||
// <ButtonNextHeader
|
||||
// onPress={() => { handleSetData() }}
|
||||
// disable={Object.values(error).some((val) => val == true) || data.title == "" || data.dateStart == "" || data.timeStart == "" || data.timeEnd == "" || data.repeatEventType == ""}
|
||||
// />
|
||||
// ),
|
||||
header:()=>(
|
||||
<AppHeader
|
||||
title="Tambah Acara"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonNextHeader
|
||||
onPress={() => { handleSetData() }}
|
||||
disable={Object.values(error).some((val) => val == true) || data.title == "" || data.dateStart == "" || data.timeStart == "" || data.timeEnd == "" || data.repeatEventType == ""}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<KeyboardAvoidingView
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
|
||||
keyboardVerticalOffset={headerHeight}
|
||||
>
|
||||
<ScrollView>
|
||||
<ScrollView
|
||||
showsVerticalScrollIndicator={false}
|
||||
style={[Styles.h100]}
|
||||
>
|
||||
<View style={[Styles.p15]}>
|
||||
<InputForm
|
||||
label="Nama Acara"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import HeaderRightCalendarList from "@/components/calendar/headerCalendarList";
|
||||
import ItemDateCalendar from "@/components/calendar/itemDateCalendar";
|
||||
import EventItem from "@/components/eventItem";
|
||||
@@ -128,16 +128,24 @@ export default function CalendarDivision() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Kalender",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => <HeaderRightCalendarList />,
|
||||
// headerRight: () => <HeaderRightCalendarList />,
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Kalender"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={<HeaderRightCalendarList />}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import BorderBottomItem from "@/components/borderBottomItem";
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import ButtonSelect from "@/components/buttonSelect";
|
||||
import DrawerBottom from "@/components/drawerBottom";
|
||||
@@ -130,24 +130,40 @@ export default function DiscussionDivisionEdit() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Edit Diskusi",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={data == "" || loading}
|
||||
category="update"
|
||||
onPress={() => {
|
||||
handleUpdate();
|
||||
}}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// disable={data == "" || loading}
|
||||
// category="update"
|
||||
// onPress={() => {
|
||||
// handleUpdate();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Edit Diskusi"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={data == "" || loading}
|
||||
category="update"
|
||||
onPress={() => {
|
||||
handleUpdate();
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<LoadingOverlay visible={loading} />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import AlertKonfirmasi from "@/components/alertKonfirmasi";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import BorderBottomItem from "@/components/borderBottomItem";
|
||||
import BorderBottomItem2 from "@/components/borderBottomItem2";
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import HeaderRightDiscussionDetail from "@/components/discussion/headerDiscussionDetail";
|
||||
import DrawerBottom from "@/components/drawerBottom";
|
||||
import ImageUser from "@/components/imageNew";
|
||||
@@ -272,23 +272,38 @@ export default function DiscussionDetail() {
|
||||
<>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Diskusi",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () =>
|
||||
(entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision || isCreator ?
|
||||
<HeaderRightDiscussionDetail
|
||||
id={detail}
|
||||
status={data?.status}
|
||||
isActive={data?.isActive}
|
||||
/> : (<></>)
|
||||
,
|
||||
// headerRight: () =>
|
||||
// (entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision || isCreator ?
|
||||
// <HeaderRightDiscussionDetail
|
||||
// id={detail}
|
||||
// status={data?.status}
|
||||
// isActive={data?.isActive}
|
||||
// /> : (<></>)
|
||||
// ,
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Diskusi"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
(entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision || isCreator ?
|
||||
<HeaderRightDiscussionDetail
|
||||
id={detail}
|
||||
status={data?.status}
|
||||
isActive={data?.isActive}
|
||||
/> : (<></>)
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<View style={{ flex: 1 }}>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import AppHeader from "@/components/AppHeader"
|
||||
import BorderBottomItem from "@/components/borderBottomItem"
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader"
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader"
|
||||
import ButtonSelect from "@/components/buttonSelect"
|
||||
import DrawerBottom from "@/components/drawerBottom"
|
||||
@@ -91,15 +91,30 @@ export default function CreateDiscussionDivision() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Tambah Diskusi',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <ButtonSaveHeader
|
||||
disable={desc == "" || loading}
|
||||
category="create"
|
||||
onPress={() => {
|
||||
handleCreate()
|
||||
}} />
|
||||
// headerRight: () => <ButtonSaveHeader
|
||||
// disable={desc == "" || loading}
|
||||
// category="create"
|
||||
// onPress={() => {
|
||||
// handleCreate()
|
||||
// }} />
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Tambah Diskusi"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={desc == "" || loading}
|
||||
category="create"
|
||||
onPress={() => {
|
||||
handleCreate()
|
||||
}} />
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<LoadingOverlay visible={loading} />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import AlertKonfirmasi from "@/components/alertKonfirmasi";
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import { ButtonHeader } from "@/components/buttonHeader";
|
||||
import HeaderRightDocument from "@/components/document/headerDocument";
|
||||
import ItemFile from "@/components/document/itemFile";
|
||||
@@ -334,47 +334,81 @@ export default function DocumentDivision() {
|
||||
}, [path]);
|
||||
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<SafeAreaView style={{ flex: 1 }}>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () =>
|
||||
selectedFiles.length > 0 || dariSelectAll ? (
|
||||
<ButtonHeader
|
||||
item={<MaterialIcons name="close" size={20} color="white" />}
|
||||
onPress={() => {
|
||||
handleBatal();
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () =>
|
||||
// selectedFiles.length > 0 || dariSelectAll ? (
|
||||
// <ButtonHeader
|
||||
// item={<MaterialIcons name="close" size={20} color="white" />}
|
||||
// onPress={() => {
|
||||
// handleBatal();
|
||||
// }}
|
||||
// />
|
||||
// ) : (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle:
|
||||
selectedFiles.length > 0 || dariSelectAll
|
||||
? `${selectedFiles.length} item terpilih`
|
||||
: "Dokumen Divisi",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () =>
|
||||
selectedFiles.length > 0 || dariSelectAll ? (
|
||||
<ButtonHeader
|
||||
item={
|
||||
<MaterialIcons name="checklist-rtl" size={20} color="white" />
|
||||
}
|
||||
onPress={() => {
|
||||
handleSelectAll();
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<HeaderRightDocument path={path} isMember={isMemberDivision} />
|
||||
),
|
||||
// headerRight: () =>
|
||||
// selectedFiles.length > 0 || dariSelectAll ? (
|
||||
// <ButtonHeader
|
||||
// item={
|
||||
// <MaterialIcons name="checklist-rtl" size={20} color="white" />
|
||||
// }
|
||||
// onPress={() => {
|
||||
// handleSelectAll();
|
||||
// }}
|
||||
// />
|
||||
// ) : (
|
||||
// <HeaderRightDocument path={path} isMember={isMemberDivision} />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title={
|
||||
selectedFiles.length > 0 || dariSelectAll
|
||||
? `${selectedFiles.length} item terpilih`
|
||||
: "Dokumen Divisi"
|
||||
}
|
||||
showBack={(selectedFiles.length > 0 || dariSelectAll) ? false : true}
|
||||
left={
|
||||
<ButtonHeader
|
||||
item={<MaterialIcons name="close" size={20} color="white" />}
|
||||
onPress={() => {
|
||||
handleBatal();
|
||||
}}
|
||||
/>
|
||||
}
|
||||
onPressLeft={() => {
|
||||
(selectedFiles.length > 0 || dariSelectAll) ? handleBatal() : router.back();
|
||||
}}
|
||||
right={
|
||||
selectedFiles.length > 0 || dariSelectAll ? (
|
||||
<ButtonHeader
|
||||
item={
|
||||
<MaterialIcons name="checklist-rtl" size={20} color="white" />
|
||||
}
|
||||
onPress={() => {
|
||||
handleSelectAll();
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<HeaderRightDocument path={path} isMember={isMemberDivision} />
|
||||
)
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ModalLoading isVisible={loadingOpen} setVisible={setLoadingOpen} />
|
||||
<ScrollView
|
||||
style={[Styles.h100]}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={refreshing}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import BorderBottomItem from "@/components/borderBottomItem";
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import ButtonSelect from "@/components/buttonSelect";
|
||||
import DrawerBottom from "@/components/drawerBottom";
|
||||
@@ -130,22 +130,36 @@ export default function TaskDivisionAddFile() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Tambah File",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
category="create"
|
||||
disable={fileForm.length == 0 || loading ? true : false}
|
||||
onPress={() => { handleAddFile() }}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// category="create"
|
||||
// disable={fileForm.length == 0 || loading ? true : false}
|
||||
// onPress={() => { handleAddFile() }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Tambah File"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
category="create"
|
||||
disable={fileForm.length == 0 || loading ? true : false}
|
||||
onPress={() => { handleAddFile() }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import ImageUser from "@/components/imageNew";
|
||||
import ImageWithLabel from "@/components/imageWithLabel";
|
||||
@@ -97,16 +97,32 @@ export default function AddMemberTask() {
|
||||
<>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Tambah Anggota Kegiatan',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
category="update"
|
||||
disable={selectMember.length == 0 || loading ? true : false}
|
||||
onPress={() => {
|
||||
handleAddMember()
|
||||
}}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// category="update"
|
||||
// disable={selectMember.length == 0 || loading ? true : false}
|
||||
// onPress={() => {
|
||||
// handleAddMember()
|
||||
// }}
|
||||
// />
|
||||
// )
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Tambah Anggota Kegiatan"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
category="update"
|
||||
disable={selectMember.length == 0 || loading ? true : false}
|
||||
onPress={() => {
|
||||
handleAddMember()
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import ModalAddDetailTugasTask from "@/components/task/modalAddDetailTugasTask";
|
||||
@@ -141,24 +141,40 @@ export default function TaskDivisionAddTask() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Tambah Tugas",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
category="create"
|
||||
disable={disable || loading}
|
||||
onPress={() => {
|
||||
handleCreate();
|
||||
}}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// category="create"
|
||||
// disable={disable || loading}
|
||||
// onPress={() => {
|
||||
// handleCreate();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Tambah Tugas"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
category="create"
|
||||
disable={disable || loading}
|
||||
onPress={() => {
|
||||
handleCreate();
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<KeyboardAvoidingView
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import Styles from "@/constants/Styles";
|
||||
@@ -72,24 +72,40 @@ export default function TaskDivisionCancel() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Pembatalan Tugas",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={disable || loading}
|
||||
category="cancel"
|
||||
onPress={() => {
|
||||
handleCancel();
|
||||
}}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// disable={disable || loading}
|
||||
// category="cancel"
|
||||
// onPress={() => {
|
||||
// handleCancel();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Pembatalan Tugas"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={disable || loading}
|
||||
category="cancel"
|
||||
onPress={() => {
|
||||
handleCancel();
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import Styles from "@/constants/Styles";
|
||||
@@ -90,22 +90,35 @@ export default function TaskDivisionEdit() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Edit Judul",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
category="update"
|
||||
disable={disable || loading}
|
||||
onPress={() => { handleUpdate() }}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// category="update"
|
||||
// disable={disable || loading}
|
||||
// onPress={() => { handleUpdate() }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader title="Tambah Kegiatan"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
category="update"
|
||||
disable={disable || loading}
|
||||
onPress={() => { handleUpdate() }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import SectionCancel from "@/components/sectionCancel";
|
||||
import SectionProgress from "@/components/sectionProgress";
|
||||
import HeaderRightTaskDetail from "@/components/task/headerTaskDetail";
|
||||
@@ -100,12 +100,24 @@ export default function DetailTaskDivision() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: loading ? 'Loading... ' : data?.title,
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => (entityUser.role == "user" || entityUser.role == "coadmin") && !isMemberDivision
|
||||
? <></>
|
||||
: <HeaderRightTaskDetail id={detail} division={id} status={data?.status} isAdminDivision={isAdminDivision} />,
|
||||
// headerRight: () => (entityUser.role == "user" || entityUser.role == "coadmin") && !isMemberDivision
|
||||
// ? <></>
|
||||
// : <HeaderRightTaskDetail id={detail} division={id} status={data?.status} isAdminDivision={isAdminDivision} />,
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title={loading ? 'Loading...' : data ? data?.title : ''}
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
(entityUser.role == "user" || entityUser.role == "coadmin") && !isMemberDivision
|
||||
? <></>
|
||||
: <HeaderRightTaskDetail id={detail} division={id} status={data?.status} isAdminDivision={isAdminDivision} />
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import Styles from "@/constants/Styles";
|
||||
@@ -90,22 +90,35 @@ export default function TaskDivisionReport() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Laporan Kegiatan",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
category="update"
|
||||
disable={disable || loading}
|
||||
onPress={() => { handleUpdate() }}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// category="update"
|
||||
// disable={disable || loading}
|
||||
// onPress={() => { handleUpdate() }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader title="Laporan Kegiatan"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
category="update"
|
||||
disable={disable || loading}
|
||||
onPress={() => { handleUpdate() }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import BorderBottomItem from "@/components/borderBottomItem";
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import ButtonSelect from "@/components/buttonSelect";
|
||||
import DrawerBottom from "@/components/drawerBottom";
|
||||
@@ -116,22 +116,36 @@ export default function CreateTaskDivision() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
handleBack();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// handleBack();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: `Tambah Tugas`,
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={title == "" || entitiesMember.length == 0 || taskCreate.length == 0 || loading}
|
||||
category="create"
|
||||
onPress={() => { handleCreate() }}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// disable={title == "" || entitiesMember.length == 0 || taskCreate.length == 0 || loading}
|
||||
// category="create"
|
||||
// onPress={() => { handleCreate() }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Tambah Tugas"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={title == "" || entitiesMember.length == 0 || taskCreate.length == 0 || loading}
|
||||
category="create"
|
||||
onPress={() => { handleCreate() }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import ImageUser from "@/components/imageNew";
|
||||
import ImageWithLabel from "@/components/imageWithLabel";
|
||||
@@ -67,16 +67,32 @@ export default function AddMemberCreateTask() {
|
||||
<>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Pilih Anggota',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
category="create"
|
||||
disable={selectMember.length > 0 ? false : true}
|
||||
onPress={() => {
|
||||
handleAddMember()
|
||||
}}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// category="create"
|
||||
// disable={selectMember.length > 0 ? false : true}
|
||||
// onPress={() => {
|
||||
// handleAddMember()
|
||||
// }}
|
||||
// />
|
||||
// )
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Pilih Anggota"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
category="create"
|
||||
disable={selectMember.length > 0 ? false : true}
|
||||
onPress={() => {
|
||||
handleAddMember()
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import ModalAddDetailTugasTask from "@/components/task/modalAddDetailTugasTask";
|
||||
@@ -121,22 +121,35 @@ export default function CreateTaskAddTugas() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Tambah Tugas",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={disable}
|
||||
category="create"
|
||||
onPress={() => { handleCreate() }}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// disable={disable}
|
||||
// category="create"
|
||||
// onPress={() => { handleCreate() }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader title="Tambah Tugas"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={disable}
|
||||
category="create"
|
||||
onPress={() => { handleCreate() }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<KeyboardAvoidingView
|
||||
|
||||
@@ -31,7 +31,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export default function ListTask() {
|
||||
const { id, status } = useLocalSearchParams<{ id: string; status: string }>()
|
||||
const { id, status, year } = useLocalSearchParams<{ id: string; status: string; year: string }>()
|
||||
const [isList, setList] = useState(false)
|
||||
const { token, decryptToken } = useAuthSession()
|
||||
const [data, setData] = useState<Props[]>([])
|
||||
@@ -43,6 +43,8 @@ export default function ListTask() {
|
||||
const [page, setPage] = useState(1)
|
||||
const [waiting, setWaiting] = useState(false)
|
||||
const [refreshing, setRefreshing] = useState(false)
|
||||
const [isYear, setYear] = useState("")
|
||||
|
||||
|
||||
async function handleLoad(loading: boolean, thisPage: number) {
|
||||
try {
|
||||
@@ -55,8 +57,12 @@ export default function ListTask() {
|
||||
division: id,
|
||||
status: statusFix,
|
||||
search,
|
||||
page: thisPage
|
||||
page: thisPage,
|
||||
year
|
||||
});
|
||||
|
||||
setYear(response.tahun)
|
||||
|
||||
if (thisPage == 1) {
|
||||
setData(response.data);
|
||||
} else if (thisPage > 1 && response.data.length > 0) {
|
||||
@@ -179,7 +185,13 @@ export default function ListTask() {
|
||||
</Pressable>
|
||||
</View>
|
||||
</View>
|
||||
<View style={[{ flex: 2 }, Styles.mt05]}>
|
||||
<View style={[Styles.mv05]}>
|
||||
<View style={[Styles.rowOnly]}>
|
||||
<Text style={[Styles.mr05]}>Filter :</Text>
|
||||
<LabelStatus size="small" category="secondary" text={isYear} style={{ marginRight: 5 }} />
|
||||
</View>
|
||||
</View>
|
||||
<View style={[{ flex: 2 }]}>
|
||||
{
|
||||
loading ?
|
||||
isList ?
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import ModalAddDetailTugasTask from "@/components/task/modalAddDetailTugasTask";
|
||||
@@ -189,24 +189,40 @@ export default function UpdateProjectTaskDivision() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Edit Tanggal dan Tugas",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={disableBtn || loadingSubmit}
|
||||
category="update"
|
||||
onPress={() => {
|
||||
handleEdit()
|
||||
}}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// disable={disableBtn || loadingSubmit}
|
||||
// category="update"
|
||||
// onPress={() => {
|
||||
// handleEdit()
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Edit Tanggal dan Tugas"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={disableBtn || loadingSubmit}
|
||||
category="update"
|
||||
onPress={() => {
|
||||
handleEdit()
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<KeyboardAvoidingView
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import ImageUser from "@/components/imageNew";
|
||||
import ImageWithLabel from "@/components/imageWithLabel";
|
||||
@@ -12,7 +12,7 @@ import { useAuthSession } from "@/providers/AuthProvider";
|
||||
import { AntDesign } from "@expo/vector-icons";
|
||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Pressable, SafeAreaView, ScrollView, View } from "react-native";
|
||||
import { Pressable, ScrollView, View } from "react-native";
|
||||
import Toast from "react-native-toast-message";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
@@ -100,16 +100,32 @@ export default function AddMemberDivision() {
|
||||
<>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Tambah Anggota',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
category="update"
|
||||
disable={selectMember.length == 0 || loading ? true : false}
|
||||
onPress={() => {
|
||||
handleAddMember()
|
||||
}}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// category="update"
|
||||
// disable={selectMember.length == 0 || loading ? true : false}
|
||||
// onPress={() => {
|
||||
// handleAddMember()
|
||||
// }}
|
||||
// />
|
||||
// )
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Tambah Anggota"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
category="update"
|
||||
disable={selectMember.length == 0 || loading ? true : false}
|
||||
onPress={() => {
|
||||
handleAddMember()
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import Styles from "@/constants/Styles";
|
||||
@@ -66,22 +66,36 @@ export default function EditDivision() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Edit Divisi",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={error.name || loading ? true : false}
|
||||
category="update"
|
||||
onPress={() => { handleEdit() }}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// disable={error.name || loading ? true : false}
|
||||
// category="update"
|
||||
// onPress={() => { handleEdit() }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Edit Divisi"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={error.name || loading ? true : false}
|
||||
category="update"
|
||||
onPress={() => { handleEdit() }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader"
|
||||
import AppHeader from "@/components/AppHeader"
|
||||
import DiscussionDivisionDetail from "@/components/division/discussionDivisionDetail"
|
||||
import FileDivisionDetail from "@/components/division/fileDivisionDetail"
|
||||
import FiturDivisionDetail from "@/components/division/fiturDivisionDetail"
|
||||
@@ -57,10 +57,18 @@ export default function DetailDivisionFitur() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: loading ? 'Loading... ' : data?.name,
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <HeaderRightDivisionDetail id={id} />,
|
||||
// headerRight: () => <HeaderRightDivisionDetail id={id} />,
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title={loading ? 'Loading...' : data?.name || ''}
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={<HeaderRightDivisionDetail id={id} />}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView
|
||||
@@ -74,10 +82,10 @@ export default function DetailDivisionFitur() {
|
||||
>
|
||||
<CaraouselHome refreshing={refreshing} />
|
||||
<View style={[Styles.ph15, Styles.mb100]}>
|
||||
<FiturDivisionDetail refreshing={refreshing}/>
|
||||
<TaskDivisionDetail refreshing={refreshing}/>
|
||||
<FileDivisionDetail refreshing={refreshing}/>
|
||||
<DiscussionDivisionDetail refreshing={refreshing}/>
|
||||
<FiturDivisionDetail refreshing={refreshing} />
|
||||
<TaskDivisionDetail refreshing={refreshing} />
|
||||
<FileDivisionDetail refreshing={refreshing} />
|
||||
<DiscussionDivisionDetail refreshing={refreshing} />
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import AlertKonfirmasi from "@/components/alertKonfirmasi"
|
||||
import AppHeader from "@/components/AppHeader"
|
||||
import BorderBottomItem from "@/components/borderBottomItem"
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader"
|
||||
import HeaderRightDivisionInfo from "@/components/division/headerDivisionInfo"
|
||||
import DrawerBottom from "@/components/drawerBottom"
|
||||
import ImageUser from "@/components/imageNew"
|
||||
@@ -164,10 +164,20 @@ export default function InformationDivision() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Informasi Divisi',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => ((entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision) && <HeaderRightDivisionInfo id={id} active={dataDetail?.isActive} />,
|
||||
// headerRight: () => ((entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision) && <HeaderRightDivisionInfo id={id} active={dataDetail?.isActive} />,
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Informasi Divisi"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
((entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision) && <HeaderRightDivisionInfo id={id} active={dataDetail?.isActive} />
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader"
|
||||
import AppHeader from "@/components/AppHeader"
|
||||
import ReportChartDocument from "@/components/division/reportChartDocument"
|
||||
import ReportChartEvent from "@/components/division/reportChartEvent"
|
||||
import ReportChartProgress from "@/components/division/reportChartProgress"
|
||||
@@ -107,9 +107,16 @@ export default function ReportDivision() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Laporan Divisi',
|
||||
headerTitleAlign: 'center',
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Laporan Divisi"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import AlertKonfirmasi from "@/components/alertKonfirmasi";
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonNextHeader from "@/components/buttonNextHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import ModalSelect from "@/components/modalSelect";
|
||||
@@ -102,25 +102,38 @@ export default function CreateDivision() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Tambah Divisi",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonNextHeader
|
||||
onPress={() => { handleCheckName() }}
|
||||
disable={loadingBtn || error.idGroup || error.name || chooseGroup.val == "" || chooseGroup.val == "null" || dataForm.name == "" || dataForm.name == "null"}
|
||||
// headerRight: () => (
|
||||
// <ButtonNextHeader
|
||||
// onPress={() => { handleCheckName() }}
|
||||
// disable={loadingBtn || error.idGroup || error.name || chooseGroup.val == "" || chooseGroup.val == "null" || dataForm.name == "" || dataForm.name == "null"}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader title="Tambah Divisi"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={<ButtonNextHeader
|
||||
onPress={() => { handleCheckName() }}
|
||||
disable={loadingBtn || error.idGroup || error.name || chooseGroup.val == "" || chooseGroup.val == "null" || dataForm.name == "" || dataForm.name == "null"}
|
||||
/>}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView>
|
||||
<View style={[Styles.p15, Styles.mb100]}>
|
||||
<ScrollView
|
||||
showsVerticalScrollIndicator={false}
|
||||
style={[Styles.h100]}
|
||||
>
|
||||
<View style={[Styles.p15]}>
|
||||
{
|
||||
(entityUser.role == "supadmin" || entityUser.role == "developer") &&
|
||||
(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import ImageUser from "@/components/imageNew";
|
||||
import Text from "@/components/Text";
|
||||
@@ -12,7 +12,7 @@ import { AntDesign } from "@expo/vector-icons";
|
||||
import { StackActions, useNavigation } from "@react-navigation/native";
|
||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Pressable, SafeAreaView, ScrollView, View } from "react-native";
|
||||
import { Pressable, ScrollView, View } from "react-native";
|
||||
import Toast from "react-native-toast-message";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
@@ -77,16 +77,29 @@ export default function CreateDivisionAddAdmin() {
|
||||
<>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Pilih Admin Divisi',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
category="create"
|
||||
disable={selectMember.length == 0 || loading ? true : false}
|
||||
onPress={() => {
|
||||
handleAddMember()
|
||||
}}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// category="create"
|
||||
// disable={selectMember.length == 0 || loading ? true : false}
|
||||
// onPress={() => {
|
||||
// handleAddMember()
|
||||
// }}
|
||||
// />
|
||||
// )
|
||||
header: () => (
|
||||
<AppHeader title="Pilih Admin Divisi"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={<ButtonSaveHeader
|
||||
category="create"
|
||||
disable={selectMember.length == 0 || loading ? true : false}
|
||||
onPress={() => {
|
||||
handleAddMember()
|
||||
}}
|
||||
/>}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonNextHeader from "@/components/buttonNextHeader";
|
||||
import ImageUser from "@/components/imageNew";
|
||||
import ImageWithLabel from "@/components/imageWithLabel";
|
||||
@@ -63,13 +63,23 @@ export default function CreateDivisionAddMember() {
|
||||
<>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Pilih Anggota',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => (
|
||||
<ButtonNextHeader
|
||||
disable={selectMember.length > 0 ? false : true}
|
||||
onPress={() => { handleAddMember() }}
|
||||
// headerRight: () => (
|
||||
// <ButtonNextHeader
|
||||
// disable={selectMember.length > 0 ? false : true}
|
||||
// onPress={() => { handleAddMember() }}
|
||||
// />
|
||||
// )
|
||||
header: () => (
|
||||
<AppHeader title="Pilih Anggota"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={<ButtonNextHeader
|
||||
disable={selectMember.length > 0 ? false : true}
|
||||
onPress={() => { handleAddMember() }}
|
||||
/>}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import BorderBottomItem from "@/components/borderBottomItem";
|
||||
import ButtonTab from "@/components/buttonTab";
|
||||
import InputSearch from "@/components/inputSearch";
|
||||
import LabelStatus from "@/components/labelStatus";
|
||||
import PaperGridContent from "@/components/paperGridContent";
|
||||
import Skeleton from "@/components/skeleton";
|
||||
import SkeletonTwoItem from "@/components/skeletonTwoItem";
|
||||
@@ -195,8 +196,9 @@ export default function ListDivision() {
|
||||
</Pressable>
|
||||
</View>
|
||||
{(entityUser.role == "supadmin" || entityUser.role == "developer") && (
|
||||
<View style={[Styles.mv05]}>
|
||||
<Text>Filter : {nameGroup}</Text>
|
||||
<View style={[Styles.mv05, Styles.rowOnly]}>
|
||||
<Text>Filter :</Text>
|
||||
<LabelStatus size="small" category="secondary" text={nameGroup} style={[Styles.mh05]} />
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ReportChartDocument from "@/components/division/reportChartDocument";
|
||||
import ReportChartEvent from "@/components/division/reportChartEvent";
|
||||
import ReportChartProgress from "@/components/division/reportChartProgress";
|
||||
@@ -125,19 +125,28 @@ export default function Report() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Laporan Divisi",
|
||||
headerTitleAlign: "center",
|
||||
header: () => (
|
||||
<AppHeader title="Laporan Divisi"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView>
|
||||
<View style={[Styles.p15, Styles.mb100]}>
|
||||
<ScrollView
|
||||
showsVerticalScrollIndicator={false}
|
||||
style={[Styles.h100]}
|
||||
>
|
||||
<View style={[Styles.p15, Styles.mb50]}>
|
||||
<SelectForm
|
||||
bg="white"
|
||||
label="Lembaga Desa"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import { ButtonFiturMenu } from "@/components/buttonFiturMenu";
|
||||
import Styles from "@/constants/Styles";
|
||||
import { AntDesign, Entypo, Ionicons, MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons";
|
||||
@@ -13,9 +13,11 @@ export default function Feature() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Fitur',
|
||||
headerTitleAlign: 'center'
|
||||
headerTitleAlign: 'center',
|
||||
header: () => (
|
||||
<AppHeader title="Fitur" showBack={true} onPressLeft={() => router.back()} />
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<View style={[Styles.p15]}>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ImageUser from "@/components/imageNew";
|
||||
import ItemDetailMember from "@/components/itemDetailMember";
|
||||
import LabelStatus from "@/components/labelStatus";
|
||||
@@ -11,7 +11,7 @@ import { valueRoleUser } from "@/constants/RoleUser";
|
||||
import Styles from "@/constants/Styles";
|
||||
import { apiGetProfile } from "@/lib/api";
|
||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Pressable, RefreshControl, SafeAreaView, ScrollView, View } from "react-native";
|
||||
import ImageViewing from 'react-native-image-viewing';
|
||||
import Toast from "react-native-toast-message";
|
||||
@@ -77,11 +77,19 @@ export default function MemberDetail() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Anggota',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => (entityUser.role != "user") && isEdit ? <HeaderRightMemberDetail active={data?.isActive} id={id} /> : <></>,
|
||||
headerShadowVisible: false
|
||||
// headerRight: () => (entityUser.role != "user") && isEdit ? <HeaderRightMemberDetail active={data?.isActive} id={id} /> : <></>,
|
||||
header: () => (
|
||||
<AppHeader title="Anggota"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
(entityUser.role != "user") && isEdit ? <HeaderRightMemberDetail active={data?.isActive} id={id} /> : <></>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import ModalSelect from "@/components/modalSelect";
|
||||
@@ -209,22 +209,35 @@ export default function CreateMember() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Tambah Anggota",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={disableBtn || loading}
|
||||
category="create"
|
||||
onPress={() => { handleCreate() }}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// disable={disableBtn || loading}
|
||||
// category="create"
|
||||
// onPress={() => { handleCreate() }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader title="Anggota"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={disableBtn || loading}
|
||||
category="create"
|
||||
onPress={() => { handleCreate() }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<KeyboardAvoidingView
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import ModalSelect from "@/components/modalSelect";
|
||||
@@ -239,24 +239,40 @@ export default function EditMember() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Edit Anggota",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={disableBtn || loading}
|
||||
category="update"
|
||||
onPress={() => {
|
||||
handleEdit()
|
||||
}}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// disable={disableBtn || loading}
|
||||
// category="update"
|
||||
// onPress={() => {
|
||||
// handleEdit()
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Edit Anggota"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={disableBtn || loading}
|
||||
category="update"
|
||||
onPress={() => {
|
||||
handleEdit()
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import BorderBottomItem from "@/components/borderBottomItem";
|
||||
import ButtonTab from "@/components/buttonTab";
|
||||
import ImageUser from "@/components/imageNew";
|
||||
import InputSearch from "@/components/inputSearch";
|
||||
import LabelStatus from "@/components/labelStatus";
|
||||
import SkeletonTwoItem from "@/components/skeletonTwoItem";
|
||||
import Text from "@/components/Text";
|
||||
import { ConstEnv } from "@/constants/ConstEnv";
|
||||
@@ -124,8 +125,9 @@ export default function Index() {
|
||||
<InputSearch onChange={setSearch} />
|
||||
{
|
||||
(entityUser.role == "supadmin" || entityUser.role == "developer") &&
|
||||
<View style={[Styles.mv05]}>
|
||||
<Text>Filter : {nameGroup}</Text>
|
||||
<View style={[Styles.mv05, Styles.rowOnly]}>
|
||||
<Text>Filter :</Text>
|
||||
<LabelStatus size="small" category="secondary" text={nameGroup} style={[Styles.mh05]} />
|
||||
</View>
|
||||
}
|
||||
</View>
|
||||
|
||||
@@ -5,6 +5,7 @@ import ButtonTab from "@/components/buttonTab";
|
||||
import DrawerBottom from "@/components/drawerBottom";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import InputSearch from "@/components/inputSearch";
|
||||
import LabelStatus from "@/components/labelStatus";
|
||||
import MenuItemRow from "@/components/menuItemRow";
|
||||
import SkeletonTwoItem from "@/components/skeletonTwoItem";
|
||||
import Text from "@/components/Text";
|
||||
@@ -166,8 +167,9 @@ export default function Index() {
|
||||
<InputSearch onChange={setSearch} />
|
||||
{
|
||||
(entityUser.role == "supadmin" || entityUser.role == "developer") &&
|
||||
<View style={[Styles.mv05]}>
|
||||
<Text>Filter : {nameGroup}</Text>
|
||||
<View style={[Styles.mv05, Styles.rowOnly]}>
|
||||
<Text>Filter :</Text>
|
||||
<LabelStatus size="small" category="secondary" text={nameGroup} style={[Styles.mh05]} />
|
||||
</View>
|
||||
}
|
||||
</View>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import AlertKonfirmasi from "@/components/alertKonfirmasi";
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import { ButtonHeader } from "@/components/buttonHeader";
|
||||
import ItemDetailMember from "@/components/itemDetailMember";
|
||||
import Text from "@/components/Text";
|
||||
@@ -25,20 +25,37 @@ export default function Profile() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Profile',
|
||||
headerTitleAlign: 'center',
|
||||
headerShadowVisible: false,
|
||||
headerRight: () => <ButtonHeader
|
||||
item={<AntDesign name="logout" size={20} color="white" />}
|
||||
onPress={() => {
|
||||
AlertKonfirmasi({
|
||||
title: 'Keluar',
|
||||
desc: 'Apakah anda yakin ingin keluar?',
|
||||
onPress: () => { signOut() }
|
||||
})
|
||||
}}
|
||||
/>
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Profile"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonHeader
|
||||
item={<AntDesign name="logout" size={20} color="white" />}
|
||||
onPress={() => {
|
||||
AlertKonfirmasi({
|
||||
title: 'Keluar',
|
||||
desc: 'Apakah anda yakin ingin keluar?',
|
||||
onPress: () => { signOut() }
|
||||
})
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
// headerRight: () => <ButtonHeader
|
||||
// item={<AntDesign name="logout" size={20} color="white" />}
|
||||
// onPress={() => {
|
||||
// AlertKonfirmasi({
|
||||
// title: 'Keluar',
|
||||
// desc: 'Apakah anda yakin ingin keluar?',
|
||||
// onPress: () => { signOut() }
|
||||
// })
|
||||
// }}
|
||||
// />
|
||||
}}
|
||||
/>
|
||||
<ScrollView style={[Styles.h100]}>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import AppHeader from "@/components/AppHeader"
|
||||
import BorderBottomItem from "@/components/borderBottomItem"
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader"
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader"
|
||||
import ButtonSelect from "@/components/buttonSelect"
|
||||
import DrawerBottom from "@/components/drawerBottom"
|
||||
@@ -130,13 +130,27 @@ export default function ProjectAddFile() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Tambah File',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <ButtonSaveHeader
|
||||
disable={fileForm.length == 0 || loading ? true : false}
|
||||
category="create"
|
||||
onPress={() => { handleAddFile() }} />
|
||||
// headerRight: () => <ButtonSaveHeader
|
||||
// disable={fileForm.length == 0 || loading ? true : false}
|
||||
// category="create"
|
||||
// onPress={() => { handleAddFile() }} />
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Tambah File"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={fileForm.length == 0 || loading ? true : false}
|
||||
category="create"
|
||||
onPress={() => { handleAddFile() }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import ImageUser from "@/components/imageNew";
|
||||
import ImageWithLabel from "@/components/imageWithLabel";
|
||||
@@ -97,16 +97,32 @@ export default function AddMemberProject() {
|
||||
<>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Tambah Anggota Kegiatan',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
category="update"
|
||||
disable={selectMember.length == 0 || loading ? true : false}
|
||||
onPress={() => {
|
||||
handleAddMember()
|
||||
}}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// category="update"
|
||||
// disable={selectMember.length == 0 || loading ? true : false}
|
||||
// onPress={() => {
|
||||
// handleAddMember()
|
||||
// }}
|
||||
// />
|
||||
// )
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Tambah Anggota Kegiatan"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
category="update"
|
||||
disable={selectMember.length == 0 || loading ? true : false}
|
||||
onPress={() => {
|
||||
handleAddMember()
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import ModalAddDetailTugasProject from "@/components/project/modalAddDetailTugasProject";
|
||||
@@ -136,22 +136,36 @@ export default function ProjectAddTask() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Tambah Tugas",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={disable || loading}
|
||||
category="create"
|
||||
onPress={() => { handleCreate() }}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// disable={disable || loading}
|
||||
// category="create"
|
||||
// onPress={() => { handleCreate() }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Tambah Tugas"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={disable || loading}
|
||||
category="create"
|
||||
onPress={() => { handleCreate() }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<KeyboardAvoidingView
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import Styles from "@/constants/Styles";
|
||||
@@ -6,7 +6,7 @@ import { apiCancelProject } from "@/lib/api";
|
||||
import { setUpdateProject } from "@/lib/projectUpdate";
|
||||
import { useAuthSession } from "@/providers/AuthProvider";
|
||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { SafeAreaView, ScrollView, View } from "react-native";
|
||||
import Toast from "react-native-toast-message";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
@@ -68,24 +68,40 @@ export default function ProjectCancel() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Pembatalan Kegiatan",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={disable || loading}
|
||||
category="cancel"
|
||||
onPress={() => {
|
||||
handleCancel();
|
||||
}}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// disable={disable || loading}
|
||||
// category="cancel"
|
||||
// onPress={() => {
|
||||
// handleCancel();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Pembatalan Kegiatan"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={disable || loading}
|
||||
category="cancel"
|
||||
onPress={() => {
|
||||
handleCancel();
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import Styles from "@/constants/Styles";
|
||||
@@ -43,7 +43,7 @@ export default function EditProject() {
|
||||
setJudul(val)
|
||||
if (val == "" || val == "null") {
|
||||
setError(true)
|
||||
}else{
|
||||
} else {
|
||||
setError(false)
|
||||
}
|
||||
}
|
||||
@@ -89,22 +89,36 @@ export default function EditProject() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Edit Judul Kegiatan",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={disable || loading}
|
||||
category="update"
|
||||
onPress={() => { handleUpdate() }}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// disable={disable || loading}
|
||||
// category="update"
|
||||
// onPress={() => { handleUpdate() }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Edit Judul Kegiatan"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={disable || loading}
|
||||
category="update"
|
||||
onPress={() => { handleUpdate() }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import HeaderRightProjectDetail from "@/components/project/headerProjectDetail";
|
||||
import SectionFile from "@/components/project/sectionFile";
|
||||
import SectionLink from "@/components/project/sectionLink";
|
||||
@@ -11,7 +11,7 @@ import Styles from "@/constants/Styles";
|
||||
import { apiGetProjectOne } from "@/lib/api";
|
||||
import { useAuthSession } from "@/providers/AuthProvider";
|
||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { RefreshControl, SafeAreaView, ScrollView, View } from "react-native";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
@@ -94,10 +94,20 @@ export default function DetailProject() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: loading ? 'Loading... ' : data?.title,
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => (entityUser.role == "user" || entityUser.role == "coadmin") && !isMember ? null : <HeaderRightProjectDetail id={id} status={data?.status} />,
|
||||
// headerRight: () => (entityUser.role == "user" || entityUser.role == "coadmin") && !isMember ? null : <HeaderRightProjectDetail id={id} status={data?.status} />,
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title={loading ? 'Loading...' : data && data?.title || ''}
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
(entityUser.role == "user" || entityUser.role == "coadmin") && !isMember ? null : <HeaderRightProjectDetail id={id} status={data?.status} />
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import Styles from "@/constants/Styles";
|
||||
@@ -89,22 +89,36 @@ export default function ReportProject() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Laporan Kegiatan",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={disable || loading}
|
||||
category="update"
|
||||
onPress={() => { handleUpdate() }}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// disable={disable || loading}
|
||||
// category="update"
|
||||
// onPress={() => { handleUpdate() }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Laporan Kegiatan"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={disable || loading}
|
||||
category="update"
|
||||
onPress={() => { handleUpdate() }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import BorderBottomItem from "@/components/borderBottomItem";
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import ButtonSelect from "@/components/buttonSelect";
|
||||
import DrawerBottom from "@/components/drawerBottom";
|
||||
@@ -193,24 +193,39 @@ export default function CreateProject() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
handleBack();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// handleBack();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Tambah Kegiatan",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={disableBtn || loading}
|
||||
category="create"
|
||||
onPress={() => {
|
||||
handleCreate()
|
||||
}}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// disable={disableBtn || loading}
|
||||
// category="create"
|
||||
// onPress={() => {
|
||||
// handleCreate()
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader title="Tambah Kegiatan"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={disableBtn || loading}
|
||||
category="create"
|
||||
onPress={() => {
|
||||
handleCreate()
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ScrollView
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import ImageUser from "@/components/imageNew";
|
||||
import ImageWithLabel from "@/components/imageWithLabel";
|
||||
@@ -11,8 +11,8 @@ import { setMemberChoose } from "@/lib/memberChoose";
|
||||
import { useAuthSession } from "@/providers/AuthProvider";
|
||||
import { AntDesign } from "@expo/vector-icons";
|
||||
import { router, Stack } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Pressable, SafeAreaView, ScrollView, View } from "react-native";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Pressable, ScrollView, View } from "react-native";
|
||||
import Toast from "react-native-toast-message";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
@@ -74,16 +74,31 @@ export default function AddMemberCreateProject() {
|
||||
<>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Pilih Anggota',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
category="create"
|
||||
disable={selectMember.length > 0 ? false : true}
|
||||
onPress={() => {
|
||||
handleAddMember()
|
||||
}}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// category="create"
|
||||
// disable={selectMember.length > 0 ? false : true}
|
||||
// onPress={() => {
|
||||
// handleAddMember()
|
||||
// }}
|
||||
// />
|
||||
// )
|
||||
header: () => (
|
||||
<AppHeader title="Pilih Anggota"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
category="create"
|
||||
disable={selectMember.length > 0 ? false : true}
|
||||
onPress={() => {
|
||||
handleAddMember()
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import ModalAddDetailTugasProject from "@/components/project/modalAddDetailTugasProject";
|
||||
@@ -12,7 +12,7 @@ import { router, Stack } from "expo-router";
|
||||
import 'intl';
|
||||
import 'intl/locale-data/jsonp/id';
|
||||
import moment from "moment";
|
||||
import { useEffect, useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
KeyboardAvoidingView,
|
||||
Platform,
|
||||
@@ -122,22 +122,36 @@ export default function CreateProjectAddTask() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// headerLeft: () => (
|
||||
// <ButtonBackHeader
|
||||
// onPress={() => {
|
||||
// router.back();
|
||||
// }}
|
||||
// />
|
||||
// ),
|
||||
headerTitle: "Tambah Tugas",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={disable}
|
||||
category="create"
|
||||
onPress={() => { handleCreate() }}
|
||||
// headerRight: () => (
|
||||
// <ButtonSaveHeader
|
||||
// disable={disable}
|
||||
// category="create"
|
||||
// onPress={() => { handleCreate() }}
|
||||
// />
|
||||
// ),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Tambah Tugas"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={disable}
|
||||
category="create"
|
||||
onPress={() => { handleCreate() }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<KeyboardAvoidingView
|
||||
|
||||
@@ -32,16 +32,18 @@ type Props = {
|
||||
};
|
||||
|
||||
export default function ListProject() {
|
||||
const { status, group, cat } = useLocalSearchParams<{
|
||||
const { status, group, cat, year } = useLocalSearchParams<{
|
||||
status?: string;
|
||||
group?: string;
|
||||
cat?: string;
|
||||
year?: string;
|
||||
}>();
|
||||
const [statusFix, setStatusFix] = useState<'0' | '1' | '2' | '3'>('0')
|
||||
const { token, decryptToken } = useAuthSession();
|
||||
const entityUser = useSelector((state: any) => state.user)
|
||||
const [search, setSearch] = useState("")
|
||||
const [nameGroup, setNameGroup] = useState("")
|
||||
const [isYear, setYear] = useState("")
|
||||
const [data, setData] = useState<Props[]>([])
|
||||
const [isList, setList] = useState(false)
|
||||
const update = useSelector((state: any) => state.projectUpdate)
|
||||
@@ -63,11 +65,13 @@ export default function ListProject() {
|
||||
search: search,
|
||||
group: String(group),
|
||||
kategori: String(cat),
|
||||
page: thisPage
|
||||
page: thisPage,
|
||||
year: String(year)
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setNameGroup(response.filter.name);
|
||||
setYear(response.tahun)
|
||||
if (thisPage == 1) {
|
||||
setData(response.data);
|
||||
} else if (thisPage > 1 && response.data.length > 0) {
|
||||
@@ -91,7 +95,7 @@ export default function ListProject() {
|
||||
|
||||
useEffect(() => {
|
||||
handleLoad(true, 1);
|
||||
}, [statusFix, search, group, cat]);
|
||||
}, [statusFix, search, group, cat, year]);
|
||||
|
||||
const loadMoreData = () => {
|
||||
if (waiting) return
|
||||
@@ -194,17 +198,25 @@ export default function ListProject() {
|
||||
</View>
|
||||
<View style={[Styles.mv05]}>
|
||||
{
|
||||
entityUser.role != 'cosupadmin' && entityUser.role != 'admin' &&
|
||||
<Text>Filter :
|
||||
// entityUser.role != 'cosupadmin' && entityUser.role != 'admin' &&
|
||||
<View style={[Styles.rowOnly]}>
|
||||
<Text style={[Styles.mr05]}>Filter :</Text>
|
||||
{
|
||||
(entityUser.role == "supadmin" || entityUser.role == "developer") && nameGroup
|
||||
(entityUser.role == "supadmin" || entityUser.role == "developer") &&
|
||||
<LabelStatus size="small" category="secondary" text={nameGroup} style={{ marginRight: 5 }} />
|
||||
}
|
||||
{
|
||||
(entityUser.role == 'user' || entityUser.role == 'coadmin')
|
||||
? (cat == 'null' || cat == 'undefined' || cat == undefined || cat == '' || cat == 'data-saya') ? 'Kegiatan Saya' : 'Semua Kegiatan'
|
||||
? (cat == 'null' || cat == 'undefined' || cat == undefined || cat == '' || cat == 'data-saya') ? <LabelStatus size="small" category="secondary" text="Kegiatan Saya" style={{ marginRight: 5 }} /> : <LabelStatus size="small" category="secondary" text="Semua Kegiatan" style={{ marginRight: 5 }} />
|
||||
: ''
|
||||
}
|
||||
</Text>
|
||||
<LabelStatus size="small" category="secondary" text={isYear} style={{ marginRight: 5 }} />
|
||||
{/* {
|
||||
(entityUser.role == 'user' || entityUser.role == 'coadmin')
|
||||
? (cat == 'null' || cat == 'undefined' || cat == undefined || cat == '' || cat == 'data-saya') ? <LabelStatus size="small" category="primary" text="Kegiatan Saya" /> : <LabelStatus size="small" category="primary" text="Semua Kegiatan" />
|
||||
: ''
|
||||
} */}
|
||||
</View>
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import ModalAddDetailTugasProject from "@/components/project/modalAddDetailTugasProject";
|
||||
@@ -14,7 +14,7 @@ import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||
import 'intl';
|
||||
import 'intl/locale-data/jsonp/id';
|
||||
import moment from "moment";
|
||||
import { useEffect, useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { KeyboardAvoidingView, Platform, Pressable, SafeAreaView, ScrollView, View } from "react-native";
|
||||
import Toast from "react-native-toast-message";
|
||||
import DateTimePicker, { DateType } from "react-native-ui-datepicker";
|
||||
@@ -172,14 +172,28 @@ export default function UpdateProjectTask() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Edit Tanggal dan Tugas',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <ButtonSaveHeader
|
||||
disable={disableBtn || loadingSubmit}
|
||||
category="update"
|
||||
onPress={() => { handleEdit() }}
|
||||
/>
|
||||
// headerRight: () => <ButtonSaveHeader
|
||||
// disable={disableBtn || loadingSubmit}
|
||||
// category="update"
|
||||
// onPress={() => { handleEdit() }}
|
||||
// />
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="Edit Tanggal dan Tugas"
|
||||
showBack={true}
|
||||
onPressLeft={() => router.back()}
|
||||
right={
|
||||
<ButtonSaveHeader
|
||||
disable={disableBtn || loadingSubmit}
|
||||
category="update"
|
||||
onPress={() => { handleEdit() }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<KeyboardAvoidingView
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import AppHeader from "@/components/AppHeader";
|
||||
import BorderBottomItem from "@/components/borderBottomItem";
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import ImageUser from "@/components/imageNew";
|
||||
import InputSearch from "@/components/inputSearch";
|
||||
import Text from '@/components/Text';
|
||||
@@ -82,9 +82,11 @@ export default function Search() {
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Pencarian',
|
||||
headerTitleAlign: 'center'
|
||||
headerTitleAlign: 'center',
|
||||
header: () => (
|
||||
<AppHeader title="Pencarian" showBack={true} onPressLeft={() => router.back()} />
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<View style={[Styles.p15]}>
|
||||
|
||||
36
components/AppHeader.tsx
Normal file
36
components/AppHeader.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import Styles from '@/constants/Styles';
|
||||
import { useRouter } from 'expo-router';
|
||||
import { Platform, Text, View } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import ButtonBackHeader from './buttonBackHeader';
|
||||
|
||||
type Props = {
|
||||
title: string;
|
||||
right?: React.ReactNode;
|
||||
showBack?: boolean;
|
||||
onPressLeft?: () => void
|
||||
left?: React.ReactNode
|
||||
};
|
||||
|
||||
export default function AppHeader({ title, right, showBack = true, onPressLeft, left }: Props) {
|
||||
const insets = useSafeAreaInsets();
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<View style={[Styles.headerContainer, Platform.OS === 'ios' ? Styles.pb05 : Styles.pb13, { paddingTop: Platform.OS === 'ios' ? insets.top : 10 }]}>
|
||||
<View style={Styles.headerApp}>
|
||||
{showBack ? (
|
||||
<ButtonBackHeader onPress={onPressLeft} />
|
||||
) :
|
||||
left ? left :
|
||||
(
|
||||
<View style={Styles.headerSide} />
|
||||
)}
|
||||
|
||||
<Text style={Styles.headerTitle}>{title}</Text>
|
||||
|
||||
<View style={Styles.headerSide}>{right}</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -1,16 +1,23 @@
|
||||
import { ColorsStatus } from "@/constants/ColorsStatus";
|
||||
import Styles from "@/constants/Styles";
|
||||
import { View } from "react-native";
|
||||
import { View, StyleProp, ViewStyle } from "react-native";
|
||||
import Text from "./Text";
|
||||
|
||||
type Props = {
|
||||
category: 'error' | 'success' | 'warning' | 'primary' | 'secondary'
|
||||
text: string
|
||||
size: 'small' | 'default'
|
||||
style?: StyleProp<ViewStyle>
|
||||
}
|
||||
export default function LabelStatus({ category, text, size }: Props) {
|
||||
export default function LabelStatus({ category, text, size, style }: Props) {
|
||||
return (
|
||||
<View style={[size == "small" ? Styles.labelStatusSmall : Styles.labelStatus, ColorsStatus[category], Styles.round10, Styles.contentItemCenter]}>
|
||||
<View style={[
|
||||
size == "small" ? Styles.labelStatusSmall : Styles.labelStatus,
|
||||
ColorsStatus[category],
|
||||
Styles.round10,
|
||||
Styles.contentItemCenter,
|
||||
style
|
||||
]}>
|
||||
<Text style={[size == "small" ? Styles.textSmallSemiBold : Styles.textMediumSemiBold, Styles.cWhite, { textAlign: 'center' }]}>{text}</Text>
|
||||
</View>
|
||||
)
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
import Styles from "@/constants/Styles"
|
||||
import { apiGetGroup } from "@/lib/api"
|
||||
import { apiGetGroup, apiGetTahunProject, apiGetTahunTask } from "@/lib/api"
|
||||
import { setEntityFilterGroup } from "@/lib/filterSlice"
|
||||
import { useAuthSession } from "@/providers/AuthProvider"
|
||||
import { AntDesign } from "@expo/vector-icons"
|
||||
import { router } from "expo-router"
|
||||
import { useEffect, useState } from "react"
|
||||
import { Pressable, ScrollView, View } from "react-native"
|
||||
import Text from './Text';
|
||||
import { ScrollView, TouchableOpacity, View } from "react-native"
|
||||
import { useDispatch, useSelector } from "react-redux"
|
||||
import { ButtonForm } from "./buttonForm"
|
||||
import DrawerBottom from "./drawerBottom"
|
||||
import Text from './Text'
|
||||
|
||||
|
||||
type Props = {
|
||||
open: boolean,
|
||||
close: (value: boolean) => void
|
||||
page: 'position' | 'member' | 'discussion' | 'project' | 'division'
|
||||
category?: 'filter-group' | 'filter-data'
|
||||
page: 'position' | 'member' | 'discussion' | 'project' | 'division' | 'division/task'
|
||||
category?: 'filter-group' | 'filter-data' | 'year-only',
|
||||
valueGroup?: string,
|
||||
valueYear?: string,
|
||||
dataPassing?: any
|
||||
}
|
||||
|
||||
export default function ModalFilter({ open, close, page, category }: Props) {
|
||||
export default function ModalFilter({ open, close, page, category, valueGroup, valueYear, dataPassing }: Props) {
|
||||
const data = [
|
||||
{
|
||||
id: "data-saya",
|
||||
@@ -34,60 +36,163 @@ export default function ModalFilter({ open, close, page, category }: Props) {
|
||||
const dispatch = useDispatch()
|
||||
const entities = useSelector((state: any) => state.filterGroup)
|
||||
const update = useSelector((state: any) => state.groupUpdate)
|
||||
const [chooseGroup, setChooseGroup] = useState('')
|
||||
const [chooseGroup, setChooseGroup] = useState(valueGroup || '')
|
||||
const [chooseYear, setChooseYear] = useState(valueYear || '')
|
||||
const [dataTahun, setDataTahun] = useState<{ id: string, name: string }[]>([])
|
||||
const [passingData, setPassingData] = useState(dataPassing)
|
||||
|
||||
async function handleLoad() {
|
||||
const hasil = await decryptToken(String(token?.current))
|
||||
const response = await apiGetGroup({ active: 'true', user: hasil, search: '' })
|
||||
dispatch(setEntityFilterGroup(response.data))
|
||||
|
||||
if (page === 'project') {
|
||||
const responseTahun = await apiGetTahunProject({ user: hasil })
|
||||
setDataTahun(responseTahun.data)
|
||||
} else if (page === 'division/task') {
|
||||
const responseTahun = await apiGetTahunTask({ user: hasil, division: passingData })
|
||||
setDataTahun(responseTahun.data)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
handleLoad()
|
||||
handleLoad()
|
||||
}, [dispatch, update]);
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<DrawerBottom animation="slide" isVisible={open} setVisible={close} title="Filter" height={75}>
|
||||
<DrawerBottom animation="slide" isVisible={open} setVisible={close} title="Pilih Preferensi" height={75}>
|
||||
<View style={{ justifyContent: 'space-between', flex: 1 }}>
|
||||
<ScrollView>
|
||||
<View>
|
||||
{
|
||||
category == "filter-data"
|
||||
?
|
||||
data.map((item: any, index: any) => (
|
||||
<Pressable key={index} style={[Styles.itemSelectModal]} onPress={() => { setChooseGroup(item.id) }}>
|
||||
<Text style={[chooseGroup == item.id ? Styles.textDefaultSemiBold : Styles.textDefault]}>{item.name}</Text>
|
||||
{
|
||||
chooseGroup == item.id && <AntDesign name="check" size={20} color={'black'}/>
|
||||
}
|
||||
</Pressable>
|
||||
))
|
||||
:
|
||||
entities.map((item: any, index: any) => (
|
||||
<Pressable key={index} style={[Styles.itemSelectModal]} onPress={() => { setChooseGroup(item.id) }}>
|
||||
<Text style={[chooseGroup == item.id ? Styles.textDefaultSemiBold : Styles.textDefault]}>{item.name}</Text>
|
||||
{
|
||||
chooseGroup == item.id && <AntDesign name="check" size={20} color={'black'}/>
|
||||
}
|
||||
</Pressable>
|
||||
))
|
||||
}
|
||||
</View>
|
||||
{
|
||||
category != "year-only" &&
|
||||
<View>
|
||||
<Text style={[Styles.textDefaultSemiBold, Styles.mb05]}>{category == "filter-data" ? "Filter Data" : "Lembaga Desa"}</Text>
|
||||
<View style={[Styles.rowOnly, { flexWrap: 'wrap' }]}>
|
||||
{
|
||||
category == "filter-data"
|
||||
?
|
||||
data.map((item: any, index: any) => (
|
||||
<TouchableOpacity
|
||||
key={index}
|
||||
style={[
|
||||
Styles.chip,
|
||||
chooseGroup == item.id && Styles.chipSelected,
|
||||
]}
|
||||
activeOpacity={0.8}
|
||||
onPress={() => { setChooseGroup(item.id) }}
|
||||
>
|
||||
{/* {chooseGroup == item.id && (
|
||||
<View style={Styles.checkIcon}>
|
||||
<Ionicons name="checkmark" size={14} color="white" />
|
||||
</View>
|
||||
)} */}
|
||||
|
||||
<Text
|
||||
style={[
|
||||
Styles.chipText,
|
||||
chooseGroup == item.id && Styles.chipTextSelected,
|
||||
]}
|
||||
>
|
||||
{item.name}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
// <Pressable key={index} style={[Styles.itemSelectModal]} onPress={() => { setChooseGroup(item.id) }}>
|
||||
// <Text style={[chooseGroup == item.id ? Styles.textDefaultSemiBold : Styles.textDefault]}>{item.name}</Text>
|
||||
// {
|
||||
// chooseGroup == item.id && <AntDesign name="check" size={20} color={'black'} />
|
||||
// }
|
||||
// </Pressable>
|
||||
))
|
||||
:
|
||||
entities.map((item: any, index: any) => (
|
||||
<TouchableOpacity
|
||||
key={index}
|
||||
style={[
|
||||
Styles.chip,
|
||||
chooseGroup == item.id && Styles.chipSelected,
|
||||
]}
|
||||
activeOpacity={0.8}
|
||||
onPress={() => { setChooseGroup(item.id) }}
|
||||
>
|
||||
{/* {chooseGroup == item.id && (
|
||||
<View style={Styles.checkIcon}>
|
||||
<Ionicons name="checkmark" size={14} color="white" />
|
||||
</View>
|
||||
)} */}
|
||||
|
||||
<Text
|
||||
style={[
|
||||
Styles.chipText,
|
||||
chooseGroup == item.id && Styles.chipTextSelected,
|
||||
]}
|
||||
>
|
||||
{item.name}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
// <Pressable key={index} style={[Styles.itemSelectModal]} onPress={() => { setChooseGroup(item.id) }}>
|
||||
// <Text style={[chooseGroup == item.id ? Styles.textDefaultSemiBold : Styles.textDefault]}>{item.name}</Text>
|
||||
// {
|
||||
// chooseGroup == item.id && <AntDesign name="check" size={20} color={'black'}/>
|
||||
// }
|
||||
// </Pressable>
|
||||
))
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
}
|
||||
|
||||
{(page == "project" || page == "division/task") && (
|
||||
<View>
|
||||
<Text style={[Styles.textDefaultSemiBold, Styles.mb05]}>Tahun</Text>
|
||||
<View style={[Styles.rowOnly, { flexWrap: 'wrap' }]}>
|
||||
{
|
||||
dataTahun.map((item: { id: string, name: string }, index: number) => (
|
||||
<TouchableOpacity
|
||||
key={index}
|
||||
style={[
|
||||
Styles.chip,
|
||||
chooseYear == item.id && Styles.chipSelected,
|
||||
]}
|
||||
activeOpacity={0.8}
|
||||
onPress={() => { setChooseYear(item.id) }}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
Styles.chipText,
|
||||
chooseYear == item.id && Styles.chipTextSelected,
|
||||
]}
|
||||
>
|
||||
{item.name}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
))
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</ScrollView>
|
||||
<View>
|
||||
<ButtonForm text="Terapkan" onPress={() => {
|
||||
close(false)
|
||||
page == 'project' ?
|
||||
category == "filter-data"
|
||||
category == "year-only"
|
||||
?
|
||||
router.replace(`/${page}?status=0&cat=${chooseGroup}`)
|
||||
router.replace(`/${page}?status=0&year=${chooseYear}`)
|
||||
:
|
||||
router.replace(`/${page}?status=0&group=${chooseGroup}`)
|
||||
category == "filter-data"
|
||||
?
|
||||
router.replace(`/${page}?status=0&cat=${chooseGroup}&year=${chooseYear}`)
|
||||
:
|
||||
router.replace(`/${page}?status=0&group=${chooseGroup}&year=${chooseYear}`)
|
||||
:
|
||||
router.replace(`/${page}?active=true&group=${chooseGroup}`)
|
||||
page == "division/task" ?
|
||||
router.replace(`/division/${dataPassing}/task?status=0&year=${chooseYear}`)
|
||||
:
|
||||
router.replace(`/${page}?active=true&group=${chooseGroup}`)
|
||||
}} />
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -31,7 +31,7 @@ export default function HeaderRightProjectList() {
|
||||
/>
|
||||
}
|
||||
{
|
||||
(entityUser.role == "user" || entityUser.role == "coadmin" || entityUser.role == "supadmin" || entityUser.role == "developer") &&
|
||||
// (entityUser.role == "user" || entityUser.role == "coadmin" || entityUser.role == "supadmin" || entityUser.role == "developer") &&
|
||||
<MenuItemRow
|
||||
icon={<AntDesign name="filter" color="black" size={25} />}
|
||||
title="Filter"
|
||||
@@ -50,7 +50,7 @@ export default function HeaderRightProjectList() {
|
||||
close={() => { setFilter(false) }}
|
||||
open={isFilter}
|
||||
page="project"
|
||||
category={entityUser.role == "supadmin" || entityUser.role == "developer" ? "filter-group" : "filter-data"}
|
||||
category={entityUser.role == "admin" || entityUser.role == "cosupadmin" ? 'year-only' : entityUser.role == "supadmin" || entityUser.role == "developer" ? "filter-group" : "filter-data"}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -9,6 +9,7 @@ import { useSelector } from "react-redux"
|
||||
import ButtonMenuHeader from "../buttonMenuHeader"
|
||||
import DrawerBottom from "../drawerBottom"
|
||||
import MenuItemRow from "../menuItemRow"
|
||||
import ModalFilter from "../modalFilter"
|
||||
|
||||
export default function HeaderRightTaskList() {
|
||||
const [isVisible, setVisible] = useState(false)
|
||||
@@ -16,6 +17,8 @@ export default function HeaderRightTaskList() {
|
||||
const { token, decryptToken } = useAuthSession()
|
||||
const { id } = useLocalSearchParams<{ id: string }>();
|
||||
const entityUser = useSelector((state: any) => state.user);
|
||||
const [isFilter, setFilter] = useState(false)
|
||||
|
||||
|
||||
async function handleCheckAdmin() {
|
||||
try {
|
||||
@@ -38,22 +41,44 @@ export default function HeaderRightTaskList() {
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
{/* {
|
||||
(entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision
|
||||
? <ButtonMenuHeader onPress={() => { setVisible(true) }} /> : <></>
|
||||
}
|
||||
} */}
|
||||
<ButtonMenuHeader onPress={() => { setVisible(true) }} />
|
||||
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={setVisible} title="Menu">
|
||||
<View style={Styles.rowItemsCenter}>
|
||||
{
|
||||
(entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision
|
||||
&&
|
||||
<MenuItemRow
|
||||
icon={<AntDesign name="pluscircle" color="black" size={25} />}
|
||||
title="Tambah Tugas Divisi"
|
||||
onPress={() => {
|
||||
setVisible(false)
|
||||
router.push('./task/create')
|
||||
}}
|
||||
/>
|
||||
}
|
||||
<MenuItemRow
|
||||
icon={<AntDesign name="pluscircle" color="black" size={25} />}
|
||||
title="Tambah Tugas Divisi"
|
||||
icon={<AntDesign name="filter" color="black" size={25} />}
|
||||
title="Filter"
|
||||
onPress={() => {
|
||||
setVisible(false)
|
||||
router.push('./task/create')
|
||||
setTimeout(() => {
|
||||
setFilter(true)
|
||||
}, 600)
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</DrawerBottom>
|
||||
<ModalFilter
|
||||
close={() => { setFilter(false) }}
|
||||
open={isFilter}
|
||||
page="division/task"
|
||||
category={"year-only"}
|
||||
dataPassing={id}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
130
constants/FileExtensions.ts
Normal file
130
constants/FileExtensions.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* File Extensions Constants
|
||||
* Categorizes common file extensions for use throughout the application
|
||||
*/
|
||||
|
||||
// Image file extensions
|
||||
export const IMAGE_EXTENSIONS = [
|
||||
'jpg',
|
||||
'jpeg',
|
||||
'png',
|
||||
'gif',
|
||||
'bmp',
|
||||
'webp',
|
||||
'svg',
|
||||
'tiff',
|
||||
'ico'
|
||||
];
|
||||
|
||||
// Document file extensions
|
||||
export const DOCUMENT_EXTENSIONS = [
|
||||
'pdf',
|
||||
'doc',
|
||||
'docx',
|
||||
'xls',
|
||||
'xlsx',
|
||||
'ppt',
|
||||
'pptx',
|
||||
'txt',
|
||||
'rtf',
|
||||
'odt',
|
||||
'ods',
|
||||
'odp',
|
||||
'csv',
|
||||
'xml',
|
||||
'html',
|
||||
'htm'
|
||||
];
|
||||
|
||||
// Video file extensions
|
||||
export const VIDEO_EXTENSIONS = [
|
||||
'mp4',
|
||||
'avi',
|
||||
'mov',
|
||||
'wmv',
|
||||
'flv',
|
||||
'webm',
|
||||
'mkv',
|
||||
'm4v',
|
||||
'3gp',
|
||||
'mpeg',
|
||||
'mpg'
|
||||
];
|
||||
|
||||
// Audio file extensions
|
||||
export const AUDIO_EXTENSIONS = [
|
||||
'mp3',
|
||||
'wav',
|
||||
'flac',
|
||||
'aac',
|
||||
'ogg',
|
||||
'wma',
|
||||
'm4a',
|
||||
'opus'
|
||||
];
|
||||
|
||||
// Archive file extensions
|
||||
export const ARCHIVE_EXTENSIONS = [
|
||||
'zip',
|
||||
'rar',
|
||||
'7z',
|
||||
'tar',
|
||||
'gz',
|
||||
'bz2',
|
||||
'xz',
|
||||
'iso',
|
||||
'dmg'
|
||||
];
|
||||
|
||||
// Combined list of all extensions
|
||||
export const ALL_EXTENSIONS = [
|
||||
...IMAGE_EXTENSIONS,
|
||||
...DOCUMENT_EXTENSIONS,
|
||||
...VIDEO_EXTENSIONS,
|
||||
...AUDIO_EXTENSIONS,
|
||||
...ARCHIVE_EXTENSIONS
|
||||
];
|
||||
|
||||
// Helper function to get file type category based on extension
|
||||
export const getFileTypeCategory = (extension: string): string => {
|
||||
const ext = extension.toLowerCase();
|
||||
|
||||
if (IMAGE_EXTENSIONS.includes(ext)) {
|
||||
return 'image';
|
||||
} else if (DOCUMENT_EXTENSIONS.includes(ext)) {
|
||||
return 'document';
|
||||
} else if (VIDEO_EXTENSIONS.includes(ext)) {
|
||||
return 'video';
|
||||
} else if (AUDIO_EXTENSIONS.includes(ext)) {
|
||||
return 'audio';
|
||||
} else if (ARCHIVE_EXTENSIONS.includes(ext)) {
|
||||
return 'archive';
|
||||
}
|
||||
|
||||
return 'unknown';
|
||||
};
|
||||
|
||||
// Helper function to check if a file is an image
|
||||
export const isImageFile = (extension: string): boolean => {
|
||||
return IMAGE_EXTENSIONS.includes(extension.toLowerCase());
|
||||
};
|
||||
|
||||
// Helper function to check if a file is a document
|
||||
export const isDocumentFile = (extension: string): boolean => {
|
||||
return DOCUMENT_EXTENSIONS.includes(extension.toLowerCase());
|
||||
};
|
||||
|
||||
// Helper function to check if a file is a video
|
||||
export const isVideoFile = (extension: string): boolean => {
|
||||
return VIDEO_EXTENSIONS.includes(extension.toLowerCase());
|
||||
};
|
||||
|
||||
// Helper function to check if a file is audio
|
||||
export const isAudioFile = (extension: string): boolean => {
|
||||
return AUDIO_EXTENSIONS.includes(extension.toLowerCase());
|
||||
};
|
||||
|
||||
// Helper function to check if a file is an archive
|
||||
export const isArchiveFile = (extension: string): boolean => {
|
||||
return ARCHIVE_EXTENSIONS.includes(extension.toLowerCase());
|
||||
};
|
||||
@@ -570,7 +570,7 @@ const Styles = StyleSheet.create({
|
||||
paddingVertical: 10,
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
bottom: 0
|
||||
bottom: 0,
|
||||
},
|
||||
animatedView: {
|
||||
width: '100%',
|
||||
@@ -631,6 +631,61 @@ const Styles = StyleSheet.create({
|
||||
position: 'absolute',
|
||||
opacity: 0,
|
||||
zIndex: -1,
|
||||
},
|
||||
headerContainer: {
|
||||
backgroundColor: '#19345E',
|
||||
},
|
||||
headerApp: {
|
||||
// height: 40,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: 16,
|
||||
},
|
||||
headerTitle: {
|
||||
color: '#fff',
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
},
|
||||
headerSide: {
|
||||
width: 40,
|
||||
alignItems: 'center',
|
||||
},
|
||||
chip: {
|
||||
paddingVertical: 5,
|
||||
paddingHorizontal: 15,
|
||||
borderRadius: 5,
|
||||
backgroundColor: "#F3F4F6",
|
||||
borderWidth: 1,
|
||||
borderColor: "transparent",
|
||||
marginRight: 10,
|
||||
marginBottom: 10,
|
||||
},
|
||||
chipSelected: {
|
||||
backgroundColor: "#FFF5F2",
|
||||
borderColor: "#FF5A3C",
|
||||
},
|
||||
chipText: {
|
||||
fontSize: 16,
|
||||
color: "#222",
|
||||
},
|
||||
chipTextSelected: {
|
||||
color: "#FF5A3C",
|
||||
},
|
||||
checkIcon: {
|
||||
position: "absolute",
|
||||
top: -6,
|
||||
left: -6,
|
||||
backgroundColor: "#FF5A3C",
|
||||
borderRadius: 10,
|
||||
padding: 2,
|
||||
},
|
||||
headerModalViewImg: {
|
||||
paddingTop: 50,
|
||||
paddingHorizontal: 16,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
18
lib/api.ts
18
lib/api.ts
@@ -315,8 +315,13 @@ export const apiDeleteAnnouncement = async (data: { user: string }, id: string)
|
||||
return response.data
|
||||
};
|
||||
|
||||
export const apiGetProject = async ({ user, status, search, group, kategori, page }: { user: string, status: string, search: string, group?: string, kategori?: string, page?: number }) => {
|
||||
const response = await api.get(`mobile/project?user=${user}&status=${status}&group=${group}&search=${search}&cat=${kategori}&page=${page}`);
|
||||
export const apiGetTahunProject = async ({ user }: { user: string }) => {
|
||||
const response = await api.get(`mobile/project/tahun?user=${user}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const apiGetProject = async ({ user, status, search, group, kategori, page, year }: { user: string, status: string, search: string, group?: string, kategori?: string, page?: number, year?: string }) => {
|
||||
const response = await api.get(`mobile/project?user=${user}&status=${status}&group=${group}&search=${search}&cat=${kategori}&page=${page}&year=${year}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
@@ -600,8 +605,13 @@ export const apiUpdateCalendar = async ({ data, id }: { data: { title: string, d
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const apiGetTask = async ({ user, status, search, division, page }: { user: string, status: string, search: string, division: string, page?: number }) => {
|
||||
const response = await api.get(`mobile/task?user=${user}&status=${status}&division=${division}&search=${search}&page=${page}`);
|
||||
export const apiGetTask = async ({ user, status, search, division, page, year }: { user: string, status: string, search: string, division: string, page?: number, year?: string }) => {
|
||||
const response = await api.get(`mobile/task?user=${user}&status=${status}&division=${division}&search=${search}&page=${page}&year=${year}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const apiGetTahunTask = async ({ user, division }: { user: string, division: string }) => {
|
||||
const response = await api.get(`mobile/task/tahun?user=${user}&division=${division}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user