Compare commits

...

17 Commits

Author SHA1 Message Date
4df0a44ac9 upd: redesign 2026-02-12 17:52:19 +08:00
8012f7f322 redesign aplikasi
Deskripsi:
- update tema mode light dan dark pada fitur banner, lembaga desa, jabatan, anggota, dan diskusi umum
2026-02-11 17:04:57 +08:00
064a8ccaad upd: redesign aplikasi
Deskripsi:
- update home, profile dll
- blm selesai

NO Issues
2026-02-10 17:32:56 +08:00
d3802ca26c upd: redesign
Deskripsi:
- fitur ganti mode tema
- penerapan tema pada semua fitur

NO Issues
2026-02-09 17:49:25 +08:00
ddfee00410 upd: panduan 2026-02-06 17:47:22 +08:00
1aa51adab0 Merge pull request 'amalia/04-feb-26' (#17) from amalia/04-feb-26 into join
Reviewed-on: http://wibugit.wibudev.com/wibu/mobile-darmasaba/pulls/17
2026-02-04 17:32:49 +08:00
ebe8380829 upd: panduan penggunaan by QWEN AI 2026-02-04 13:58:15 +08:00
c421d267b9 upd: warna select pada filter 2026-02-04 11:41:18 +08:00
bbacd40ae9 upd: view file
Deskripsi:
- view file pada pengumuman, diskusi divisi dan diskusi umum

No Issues
2026-02-04 11:37:57 +08:00
9bab420f91 Merge pull request 'amalia/03-feb-26' (#16) from amalia/03-feb-26 into join
Reviewed-on: http://wibugit.wibudev.com/wibu/mobile-darmasaba/pulls/16
2026-02-03 17:37:07 +08:00
7d8b72fdfa upd: modal view pengumuman
Deskripsi:
- modal view image pada detail pengumuman

NO Issues
2026-02-03 17:34:14 +08:00
e9c11a889d fix: tampilan pengumuman
Deskripsi:
- jarak bawah pada detail pengumuman

No Issues
2026-02-03 16:46:06 +08:00
10b74ccde9 Merge pull request 'revisi: tahun' (#15) from amalia/03-feb-26 into join
Reviewed-on: http://wibugit.wibudev.com/wibu/mobile-darmasaba/pulls/15
2026-02-03 12:26:12 +08:00
73c6a19880 revisi: tahun
Deskripsi:
- pengaplikasian api filter tahun pada fitur tugas divisi
No Issues
2026-02-03 12:21:34 +08:00
225ed63027 Merge pull request 'rev: filter tahun' (#14) from amalia/02-feb-26 into join
Reviewed-on: http://wibugit.wibudev.com/wibu/mobile-darmasaba/pulls/14
2026-02-02 17:43:21 +08:00
f34df12b2f rev: filter tahun
Deskripsi:
- tampilan modal filter
- tampilan filter disemua fitur yg ada filter nya
- pengaplikasian api

No Issues
2026-02-02 17:29:24 +08:00
a24a698f86 Merge pull request 'amalia/29-jan-26' (#13) from amalia/29-jan-26 into join
Reviewed-on: http://wibugit.wibudev.com/wibu/mobile-darmasaba/pulls/13
2026-01-29 17:23:13 +08:00
175 changed files with 2693 additions and 1054 deletions

86
GEMINI.md Normal file
View File

@@ -0,0 +1,86 @@
# Project Overview: Desa+
Desa+ is a mobile application built with React Native and Expo, designed to facilitate management and communication within villages/communities. It aims to streamline village administration, inter-community communication, and the management of essential information.
## Key Features:
- Village announcements and information
- Community discussion forum
- Village activity calendar
- Village documentation and archives
- Project and task management
- Member and organizational structure management
- Push notifications for important updates
- Verification and authentication features
## Technologies Used:
- **React Native**: Cross-platform mobile development framework.
- **Expo**: Platform for React Native application development.
- **Firebase**: Backend services including Authentication, Realtime Database, and Cloud Messaging.
- **Redux Toolkit**: State management.
- **React Navigation**: Application navigation.
- **TypeScript**: For type safety.
## Building and Running:
### Installation
1. **Clone the repository:**
```bash
git clone <repository-url>
cd mobile-darmasaba
```
2. **Install dependencies:**
```bash
npm install
```
3. **Configure environment variables:**
Create a `.env` file in the root directory and add the following variables:
```
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>
```
### Running the Application
- **Start development server:**
```bash
npx expo start
```
- **Run on Android emulator/device:**
```bash
npm run android
```
- **Run on iOS simulator/device:**
```bash
npm run ios
```
### Build Production
- **Build Android production package:**
```bash
npm run build:android
```
## Development Conventions:
### Project Structure:
- `app/`: Main page files.
- `components/`: Reusable UI components, categorized by feature (e.g., `announcement/`, `auth/`, `discussion/`).
- `assets/`: Images and static assets.
- `constants/`: Global constants.
- `lib/`: Libraries and utilities.
### Contribution Guidelines:
1. Fork the repository.
2. Create a new feature branch (`git checkout -b feature/FeatureName`).
3. Commit your changes (`git commit -m 'Add FeatureName feature'`).
4. Push to the branch (`git push origin feature/FeatureName`).
5. Create a pull request.
## Platform Support:
- ✅ Android
- ✅ iOS
- ❌ Web (not yet optimized)

View File

@@ -0,0 +1,249 @@
# Panduan Aplikasi Desa+
## Daftar Isi
1. [Gambaran Umum Aplikasi](#gambaran-umum-aplikasi)
2. [User Roles dan Hak Akses](#user-roles-dan-hak-akses)
3. [Fitur-fitur Aplikasi](#fitur-fitur-aplikasi)
4. [Troubleshooting](#troubleshooting)
## Gambaran Umum Aplikasi
Aplikasi Desa+ adalah platform digital berbasis mobile yang dirancang untuk khusus untuk pegawai desa dalam mengelola data dan memantau progres kegiatan internal. Aplikasi ini menyediakan berbagai fitur seperti pengelolaan data per divisi, pemantauan kegiatan umum, forum diskusi, pengumuman, hingga manajemen folder dokumen, aplikasi ini membantu meningkatkan efisiensi kerja, koordinasi, serta transparansi di lingkungan desa.
### Teknologi yang Digunakan
- React Native dengan Expo
- Firebase (Authentication, Realtime Database, Cloud Messaging)
- Redux Toolkit untuk manajemen state
- TypeScript untuk type safety
## User Roles dan Hak Akses
Aplikasi Desa+ memiliki sistem hierarki peran pengguna sebagai berikut:
### 1. Super Admin
- **Hak akses:**
- Semua fitur dan fungsi dalam aplikasi
- Manajemen pengguna dengan role Wakil Super Admin, Admin, Wakil Admin, dan User
- Akses ke semua data dan fungsi administratif
### 2. Wakil Super Admin
- **Hak akses:**
- Manajemen pengguna dengan role Admin, Wakil Admin, dan User
- Akses ke sebagian besar fitur administratif
- Dapat mengelola banner
### 3. Admin
- **Hak akses:**
- Manajemen pengguna dengan role Wakil Admin dan User
- Akses ke fitur-fitur administratif dasar
- Tidak dapat mengelola Wakil Super Admin dan Super Admin
### 4. Wakil Admin
- **Hak akses:**
- Manajemen pengguna dengan role User
- Akses terbatas ke fitur-fitur administratif
- Tidak dapat mengelola Admin ke atas
### 5. User
- **Hak akses:**
- Akses ke fitur-fitur umum
- Tidak dapat mengelola pengguna lain
- Tidak dapat mengakses fungsi administratif (kecuali dalam divisi dimana pengguna tersebut adalah anggota)
## Fitur-fitur Aplikasi
### 1. Otentikasi (Login & Verifikasi)
**Deskripsi:** Sistem login menggunakan nomor telepon dan verifikasi OTP (One Time Password)
- **Fungsi:** Memverifikasi identitas pengguna sebelum mengakses aplikasi
- **Siapa yang bisa mengakses:** Semua pengguna yang terdaftar
### 2. Dashboard/Home Screen
**Deskripsi:** Tampilan utama aplikasi yang menampilkan informasi dan akses cepat ke berbagai fitur
- **Fungsi:** Menyediakan ringkasan informasi desa dan akses cepat ke fitur-fitur utama
- **Siapa yang bisa mengakses:** Semua pengguna yang telah login
- **Komponen:**
- Carousel banner untuk promosi atau informasi penting
- Fitur untuk mengakses semua fitur aplikasi
- Grafik progres kegiatan
- Grafik jumlah dokumen
- Daftar kegiatan terupdate
- Daftar divisi aktif
- Daftar acara mendatang
- Diskusi terbaru
### 3. Pencarian
**Deskripsi:** Fitur untuk mencari anggota, kegiatan dan divisi
- **Fungsi:** Mencari anggota, kegiatan dan divisi
- **Siapa yang bisa mengakses:** Semua pengguna
### 4. Notifikasi
**Deskripsi:** Sistem notifikasi untuk memberitahu pengguna tentang aktivitas penting
- **Fungsi:** Memberitahu pengguna tentang pengumuman, komentar, atau aktivitas lainnya
- **Siapa yang bisa mengakses:** Semua pengguna
### 5. Profil
**Deskripsi:** Fitur untuk melihat dan mengedit informasi pribadi pengguna
- **Fungsi:** Menampilkan dan mengelola informasi akun pengguna
- **Siapa yang bisa mengakses:** Pengguna yang bersangkutan
### 6. Banner
**Deskripsi:** Fitur untuk mengelola banner promosi atau informasi penting di halaman utama
- **Fungsi:** Menampilkan informasi atau promosi penting di tampilan awal
- **Siapa yang bisa mengakses:** Super Admin, Wakil Super Admin
### 7. Lembaga Desa
**Deskripsi:** Fitur untuk mengelola berbagai lembaga dalam desa
- **Fungsi:** Mengorganisir struktur organisasi desa berdasarkan lembaga
- **Siapa yang bisa mengakses:**
- Pembuatan/Edit/Hapus: Super Admin
- Melihat: Super Admin
### 8. Jabatan
**Deskripsi:** Fitur untuk mengelola posisi atau jabatan
- **Fungsi:** Mengelola data jabatan
- **Siapa yang bisa mengakses:**
- Pembuatan/Edit/Hapus: Super Admin, Wakil Super Admin, Admin, Wakil Admin
- Melihat: Semua pengguna
### 9. Anggota
**Deskripsi:** Fitur untuk mengelola data pengguna
- **Fungsi:** Menyimpan dan mengelola informasi tentang pengguna
- **Siapa yang bisa mengakses:**
- Pembuatan/Edit/Hapus: Super Admin, Wakil Super Admin, Admin, Wakil Admin
- Melihat: Semua pengguna
### 10. Diskusi Umum
**Deskripsi:** Forum diskusi untuk komunikasi anggota terpilih
- **Fungsi:** Tempat berdiskusi mengenai berbagai topik yang berkaitan dengan desa
- **Siapa yang bisa mengakses:**
- Pembuatan/Edit/Hapus: Super Admin, Wakil Super Admin, Admin
- Melihat: Semua pengguna
- Berkomentar: Pengguna terpilih
### 11. Kegiatan/Proyek
**Deskripsi:** Fitur untuk mengelola dan melacak proyek atau kegiatan desa
- **Fungsi:** Mengelola dan memonitor kemajuan proyek-proyek desa
- **Siapa yang bisa mengakses:**
- Pembuatan/Edit/Hapus/Membatalkan/Mengelola anggota: Super Admin, Wakil Super Admin, Admin
- Mengelola detail (file, task, link, laporan) : Super Admin, Wakil Super Admin, Admin, Anggota dari kegiatan
- Melihat: Semua pengguna
- **Status Kegiatan:**
- Segera: Proyek yang akan segera dimulai
- Dikerjakan: Proyek yang sedang dalam proses pengerjaan
- Selesai: Proyek yang telah selesai
- Batal: Proyek yang dibatalkan
### 12. Pengumuman
**Deskripsi:** Fitur untuk membuat, melihat, dan mengelola pengumuman desa
- **Fungsi:** Menyebarkan informasi penting kepada anggota divisi terpilih
- **Siapa yang bisa mengakses:**
- Pembuatan/Edit/Hapus: Super Admin, Wakil Super Admin, Admin
- Melihat:
- Super admin: Semua pengumuman
- Wakil super admin & admin : Pengumuman sesuai lembaga desa
- Lainnya: Pengumuman yang ditujukan ke divisi mereka
### 13. Divisi
**Deskripsi:** Fitur untuk mengelola data desa berdasarkan divisi
- **Fungsi:** Mengorganisir tugas-tugas berdasarkan divisi-divisi tertentu
- **Catatan:** Anggota divisi (role : Wakil Admin dan User) yg diangkat menjadi "Admin Divisi", mendapat akses khusus untuk mengelola divisi tersebut
- **Siapa yang bisa mengakses:**
- Pembuatan/Edit/Hapus: Super Admin, Wakil Super Admin, Admin
- Edit Divisi / Non aktifkan Divisi tertentu / Mengelola Anggota divisi tertentu : Super Admin, Wakil Super Admin, Admin, Admin Divisi
- Laporan semua divisi : Super Admin, Wakil Super Admin
- Laporan divisi tertentu : semua pengguna
- Melihat: Semua pengguna
### 14. Diskusi Divisi
**Deskripsi:** Forum diskusi khusus untuk masing-masing divisi
- **Fungsi:** Tempat berdiskusi secara internal dalam divisi
- **Siapa yang bisa mengakses:**
- Pembuatan/Edit/Hapus: Super Admin, Wakil Super Admin, Admin, Admin Divisi
- Memberi komentar : Super Admin, Wakil Super Admin, Admin, Anggota divisi
- Melihat: Semua pengguna
### 15. Tugas Divisi
**Deskripsi:** Fitur untuk mengelola tugas-tugas dalam masing-masing divisi
- **Fungsi:** Menetapkan dan melacak tugas-tugas yang harus diselesaikan oleh anggota divisi
- **Siapa yang bisa mengakses:**
- Pembuatan/Edit/Hapus: Super Admin, Wakil Super Admin, Admin, Admin Divisi
- Mengelola detail (file, task, link, laporan) : Super Admin, Wakil Super Admin, Admin, Anggota divisi
- Melihat: Semua pengguna
### 16. Dokumen Divisi
**Deskripsi:** Sistem manajemen dokumen untuk menyimpan dan mengelola file-file disetiap divisi
- **Fungsi:** Menyimpan dokumen penting dalam struktur folder disetiap divisi
- **Siapa yang bisa mengakses:**
- Pembuatan/Edit/Hapus: Super Admin, Wakil Super Admin, Admin, Anggota divisi
- Melihat: Semua pengguna
### 17. Kalender/Acara Divisi
**Deskripsi:** Fitur untuk menjadwalkan dan mengelola acara-acara desa disetiap divisi
- **Fungsi:** Menjadwalkan kegiatan dan acara penting desa disetiap divisi
- **Siapa yang bisa mengakses:**
- Pembuatan/Edit/Hapus: Super Admin, Wakil Super Admin, Admin, Anggota divisi
- Melihat: Semua pengguna
- Riwayat: Semua pengguna
## Troubleshooting
### Masalah Login
- Pastikan nomor telepon yang dimasukkan sudah benar dan terdaftar
- Pastikan koneksi internet stabil saat menerima OTP
- Jika tidak menerima OTP, coba kirim ulang setelah beberapa menit
### Tidak Bisa Mengakses Fitur Tertentu
- Pastikan peran Anda memiliki hak akses ke fitur tersebut
- Beberapa fitur hanya tersedia untuk peran tertentu (misalnya Admin ke atas)
### Lupa Password
- Aplikasi ini menggunakan sistem login OTP, jadi tidak ada password yang disimpan
- Cukup gunakan nomor telepon dan minta OTP kembali
## Dukungan dan Bantuan
Jika Anda mengalami masalah atau memiliki pertanyaan tentang penggunaan aplikasi, silakan hubungi tim pengembang aplikasi.

View File

@@ -1,37 +1,61 @@
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";
import { useTheme } from "@/providers/ThemeProvider";
import { Entypo, MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons";
import * as FileSystem from 'expo-file-system';
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 { 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 { colors } = useTheme();
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
@@ -39,13 +63,25 @@ 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)
@@ -69,30 +105,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',
{
@@ -101,19 +154,30 @@ 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);
Toast.show({
type: 'error',
text1: 'Tidak ada aplikasi yang dapat membuka file ini'
});
}
});
} catch (error) {
console.error('Error downloading or opening file:', error);
Toast.show({
type: 'error',
text1: 'Gagal membuka file',
text2: 'Silakan coba lagi nanti'
});
} finally {
setLoadingOpen(false);
}
};
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
@@ -131,16 +195,17 @@ export default function DetailAnnouncement() {
/>
<ScrollView
showsVerticalScrollIndicator={false}
style={[Styles.h100]}
style={[Styles.h100, { backgroundColor: colors.background }]}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={() => handleRefresh()}
tintColor={colors.primary}
/>
}
>
<View style={[Styles.p15]}>
<View style={[Styles.wrapPaper]}>
<View style={[Styles.p15, Styles.mb50]}>
<View style={[Styles.wrapPaper, { backgroundColor: colors.card, borderColor: colors.background }]}>
{
loading ?
<View>
@@ -157,7 +222,7 @@ export default function DetailAnnouncement() {
:
<>
<View style={[Styles.rowItemsCenter, { alignItems: 'flex-start' }]}>
<MaterialIcons name="campaign" size={25} color="black" style={[Styles.mr05]} />
<MaterialIcons name="campaign" size={25} color={colors.text} style={[Styles.mr05]} />
<Text style={[Styles.textDefaultSemiBold, Styles.w90, Styles.mt02]}>{data?.title}</Text>
</View>
<View style={[Styles.mt10]}>
@@ -166,7 +231,7 @@ export default function DetailAnnouncement() {
<RenderHTML
contentWidth={contentWidth}
source={{ html: data?.desc }}
baseStyle={{ color: 'black' }}
baseStyle={{ color: colors.text }}
/>
:
<Text>{data?.desc}</Text>
@@ -178,24 +243,32 @@ export default function DetailAnnouncement() {
</View>
{
dataFile.length > 0 && (
<View style={[Styles.wrapPaper, Styles.mt10]}>
<View style={[Styles.wrapPaper, Styles.mt10, { backgroundColor: colors.card, borderColor: colors.background }]}>
<View style={[Styles.mb05]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
</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={colors.text}
/>}
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>
)
}
<View style={[Styles.wrapPaper, Styles.mt10]}>
<View style={[Styles.wrapPaper, Styles.mt10, { backgroundColor: colors.card, borderColor: colors.background }]}>
{
loading ?
arrSkeleton.map((item, index) => {
@@ -216,7 +289,7 @@ export default function DetailAnnouncement() {
dataMember[v].map((item: any, x: any) => {
return (
<View key={x} style={[Styles.rowItemsCenter, Styles.w90]}>
<Entypo name="dot-single" size={24} color="black" />
<Entypo name="dot-single" size={24} color={colors.text} />
<Text style={[Styles.textDefault]} numberOfLines={1} ellipsizeMode='tail'>{item.division}</Text>
</View>
)
@@ -230,6 +303,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: 26 }}></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>
)
}

View File

@@ -12,6 +12,7 @@ import Styles from "@/constants/Styles";
import { setUpdateAnnouncement } from "@/lib/announcementUpdate";
import { apiCreateAnnouncement } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { Entypo, Ionicons, MaterialCommunityIcons } from "@expo/vector-icons";
import * as DocumentPicker from "expo-document-picker";
import { router, Stack } from "expo-router";
@@ -24,6 +25,7 @@ export default function CreateAnnouncement() {
const dispatch = useDispatch()
const update = useSelector((state: any) => state.announcementUpdate)
const { token, decryptToken } = useAuthSession()
const { colors } = useTheme();
const [disableBtn, setDisableBtn] = useState(true);
const [modalDivisi, setModalDivisi] = useState(false);
const [divisionMember, setDivisionMember] = useState<any>([])
@@ -129,7 +131,7 @@ export default function CreateAnnouncement() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -158,15 +160,15 @@ export default function CreateAnnouncement() {
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();
}}
/>
<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();
}}
/>
}
/>
)
@@ -175,7 +177,7 @@ export default function CreateAnnouncement() {
<LoadingOverlay visible={loading} />
<ScrollView
showsVerticalScrollIndicator={false}
style={[Styles.h100]}
style={[Styles.h100, { backgroundColor: colors.background }]}
>
<View style={[Styles.p15]}>
<InputForm
@@ -184,6 +186,7 @@ export default function CreateAnnouncement() {
placeholder="Judul Pengumuman"
required
error={error.title}
bg={colors.card}
errorText="Judul harus diisi"
onChange={(val) => validationForm("title", val)}
/>
@@ -193,6 +196,7 @@ export default function CreateAnnouncement() {
placeholder="Deskripsi Pengumuman"
required
error={error.desc}
bg={colors.card}
errorText="Pengumuman harus diisi"
onChange={(val) => validationForm("desc", val)}
multiline
@@ -201,15 +205,16 @@ export default function CreateAnnouncement() {
{
fileForm.length > 0
&&
<View style={[Styles.borderAll, Styles.round10, Styles.p10, Styles.mb10]}>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { borderColor: colors.icon + '20' }]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
{
fileForm.map((item, index) => (
<BorderBottomItem
key={index}
borderType={fileForm.length > 1 ? "bottom" : "none"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
borderType={fileForm.length - 1 == index ? "none" : "bottom"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
bgColor="transparent"
titleWeight="normal"
onPress={() => { setIndexDelFile(index); setModalFile(true) }}
/>
@@ -228,7 +233,7 @@ export default function CreateAnnouncement() {
{
divisionMember.length > 0
&&
<View style={[Styles.borderAll, Styles.round10, Styles.p10]}>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, { borderColor: colors.icon + '20' }]}>
{
divisionMember.map((item: { name: any; Division: any }, index: any) => {
return (
@@ -237,7 +242,7 @@ export default function CreateAnnouncement() {
{
item.Division.map((division: any, i: any) => (
<View key={i} style={[Styles.rowItemsCenter, Styles.w90]}>
<Entypo name="dot-single" size={24} color="black" />
<Entypo name="dot-single" size={24} color={colors.text} />
<Text style={[Styles.textDefault]} numberOfLines={1} ellipsizeMode='tail'>{division.name}</Text>
</View>
))
@@ -266,7 +271,7 @@ export default function CreateAnnouncement() {
<DrawerBottom animation="slide" isVisible={isModalFile} setVisible={setModalFile} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<Ionicons name="trash" color="black" size={25} />}
icon={<Ionicons name="trash-outline" color={colors.text} size={25} />}
title="Hapus"
onPress={() => { deleteFile(indexDelFile) }}
/>

View File

@@ -12,6 +12,7 @@ import Styles from "@/constants/Styles";
import { setUpdateAnnouncement } from "@/lib/announcementUpdate";
import { apiEditAnnouncement, apiGetAnnouncementOne } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { Entypo, Ionicons, MaterialCommunityIcons } from "@expo/vector-icons";
import * as DocumentPicker from "expo-document-picker";
import { router, Stack, useLocalSearchParams } from "expo-router";
@@ -35,6 +36,7 @@ export default function EditAnnouncement() {
const dispatch = useDispatch()
const update = useSelector((state: any) => state.announcementUpdate)
const { token, decryptToken } = useAuthSession();
const { colors } = useTheme();
const [modalDivisi, setModalDivisi] = useState(false);
const [disableBtn, setDisableBtn] = useState(true);
const [dataMember, setDataMember] = useState<any>([]);
@@ -180,7 +182,7 @@ export default function EditAnnouncement() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -226,7 +228,7 @@ export default function EditAnnouncement() {
<LoadingOverlay visible={loading} />
<ScrollView
showsVerticalScrollIndicator={false}
style={[Styles.h100]}
style={[Styles.h100, { backgroundColor: colors.background }]}
>
<View style={[Styles.p15]}>
<InputForm
@@ -235,6 +237,7 @@ export default function EditAnnouncement() {
placeholder="Judul Pengumuman"
required
error={error.title}
bg={colors.card}
errorText="Judul harus diisi"
onChange={(val) => validationForm("title", val)}
value={dataForm.title}
@@ -245,6 +248,7 @@ export default function EditAnnouncement() {
placeholder="Deskripsi Pengumuman"
required
error={error.desc}
bg={colors.card}
errorText="Pengumuman harus diisi"
onChange={(val) => validationForm("desc", val)}
value={dataForm.desc}
@@ -254,16 +258,17 @@ export default function EditAnnouncement() {
{
(fileForm.length > 0 || dataFile.filter((val) => !val.delete).length > 0)
&&
<View style={[Styles.borderAll, Styles.round10, Styles.p10, Styles.mb10]}>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { borderColor: colors.icon + '20' }]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
{
dataFile.filter((val) => !val.delete).map((item, index) => (
<BorderBottomItem
key={index}
borderType={(fileForm.length + dataFile.length) > 1 ? "bottom" : "none"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name + '.' + item.extension}
titleWeight="normal"
bgColor="transparent"
onPress={() => { setIndexDelFile({ id: item.id, cat: "oldFile" }); setModalFile(true) }}
/>
))
@@ -273,9 +278,10 @@ export default function EditAnnouncement() {
<BorderBottomItem
key={index}
borderType={(fileForm.length + dataFile.length) > 1 ? "bottom" : "none"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
titleWeight="normal"
bgColor="transparent"
onPress={() => { setIndexDelFile({ id: index, cat: "newFile" }); setModalFile(true) }}
/>
))
@@ -291,7 +297,7 @@ export default function EditAnnouncement() {
{
dataMember.length > 0
&&
<View style={[Styles.borderAll, Styles.round10, Styles.p10]}>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, { borderColor: colors.icon + '20' }]}>
{
dataMember.map((item: { name: any; Division: any }, index: any) => {
return (
@@ -300,7 +306,7 @@ export default function EditAnnouncement() {
{
item.Division.map((division: any, i: any) => (
<View key={i} style={[Styles.rowItemsCenter, Styles.w90]}>
<Entypo name="dot-single" size={24} color="black" />
<Entypo name="dot-single" size={24} color={colors.text} />
<Text style={[Styles.textDefault]} numberOfLines={1} ellipsizeMode='tail'>{division.name}</Text>
</View>
))
@@ -330,7 +336,7 @@ export default function EditAnnouncement() {
<DrawerBottom animation="slide" isVisible={isModalFile} setVisible={setModalFile} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<Ionicons name="trash" color="black" size={25} />}
icon={<Ionicons name="trash-outline" color={colors.text} size={25} />}
title="Hapus"
onPress={() => { deleteFile(indexDelFile.id, indexDelFile.cat) }}
/>

View File

@@ -6,6 +6,7 @@ import { ColorsStatus } from "@/constants/ColorsStatus";
import Styles from "@/constants/Styles";
import { apiGetAnnouncement } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { MaterialIcons } from "@expo/vector-icons";
import { router } from "expo-router";
import { useEffect, useState } from "react";
@@ -22,6 +23,7 @@ type Props = {
export default function Announcement() {
const { token, decryptToken } = useAuthSession()
const { colors } = useTheme();
const [data, setData] = useState<Props[]>([])
const [search, setSearch] = useState('')
const update = useSelector((state: any) => state.announcementUpdate)
@@ -83,7 +85,7 @@ export default function Announcement() {
})
return (
<View style={[Styles.p15, { flex: 1 }]}>
<View style={[Styles.p15, { flex: 1, backgroundColor: colors.background }]}>
<View>
<InputSearch onChange={setSearch} />
</View>
@@ -108,9 +110,10 @@ export default function Announcement() {
key={index}
onPress={() => { router.push(`/announcement/${item.id}`) }}
borderType="bottom"
bgColor="transparent"
icon={
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
<MaterialIcons name="campaign" size={25} color={'#384288'} />
<View style={[Styles.iconContent]}>
<MaterialIcons name="campaign" size={25} color={'black'} />
</View>
}
title={item.title}
@@ -127,6 +130,7 @@ export default function Announcement() {
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
tintColor={colors.primary}
/>
}
/>

View File

@@ -7,6 +7,7 @@ import Styles from "@/constants/Styles";
import { apiEditBanner, apiGetBanner, apiGetBannerOne } from "@/lib/api";
import { setEntities } from "@/lib/bannerSlice";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { Entypo } from "@expo/vector-icons";
import * as ImagePicker from "expo-image-picker";
import { router, Stack, useLocalSearchParams } from "expo-router";
@@ -24,6 +25,7 @@ import { useDispatch } from "react-redux";
export default function EditBanner() {
const dispatch = useDispatch();
const { decryptToken, token } = useAuthSession();
const { colors } = useTheme();
const { id } = useLocalSearchParams<{ id: string }>();
const [selectedImage, setSelectedImage] = useState<
string | undefined | { uri: string }
@@ -112,7 +114,7 @@ export default function EditBanner() {
};
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -143,7 +145,7 @@ export default function EditBanner() {
)
}}
/>
<ScrollView showsVerticalScrollIndicator={false} style={[Styles.h100]}>
<ScrollView showsVerticalScrollIndicator={false} style={[Styles.h100, { backgroundColor: colors.background }]}>
<View style={[Styles.p15, Styles.mb100]}>
<View style={[Styles.mb15]}>
{selectedImage != undefined ? (
@@ -179,7 +181,7 @@ export default function EditBanner() {
type="default"
placeholder="Judul"
required
bg="white"
bg={colors.card}
value={title}
error={error}
onChange={onValidate}

View File

@@ -6,6 +6,7 @@ import Styles from "@/constants/Styles";
import { apiCreateBanner, apiGetBanner } from "@/lib/api";
import { setEntities } from "@/lib/bannerSlice";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { Entypo } from "@expo/vector-icons";
import * as ImagePicker from "expo-image-picker";
import { router, Stack } from "expo-router";
@@ -22,6 +23,7 @@ import { useDispatch } from "react-redux";
export default function CreateBanner() {
const { decryptToken, token } = useAuthSession();
const { colors } = useTheme();
const dispatch = useDispatch();
const [selectedImage, setSelectedImage] = useState<string | undefined>(
undefined
@@ -94,7 +96,7 @@ export default function CreateBanner() {
};
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -133,7 +135,7 @@ export default function CreateBanner() {
)
}}
/>
<ScrollView showsVerticalScrollIndicator={false} style={[Styles.h100]}>
<ScrollView showsVerticalScrollIndicator={false} style={[Styles.h100, { backgroundColor: colors.background }]}>
<View style={[Styles.p15]}>
<View style={[Styles.mb15]}>
{selectedImage != undefined ? (
@@ -165,7 +167,7 @@ export default function CreateBanner() {
type="default"
placeholder="Judul"
required
bg="white"
bg={colors.card}
onChange={onValidate}
error={error}
errorText="Judul harus diisi"

View File

@@ -11,6 +11,7 @@ import Styles from "@/constants/Styles"
import { apiDeleteBanner, apiGetBanner } from "@/lib/api"
import { setEntities } from "@/lib/bannerSlice"
import { useAuthSession } from "@/providers/AuthProvider"
import { useTheme } from "@/providers/ThemeProvider"
import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons"
import * as FileSystem from 'expo-file-system'
import { startActivityAsync } from 'expo-intent-launcher'
@@ -32,6 +33,7 @@ type Props = {
export default function BannerList() {
const { decryptToken, token } = useAuthSession()
const { colors } = useTheme()
const [isModal, setModal] = useState(false)
const entities = useSelector((state: any) => state.banner)
const [dataId, setDataId] = useState('')
@@ -105,7 +107,7 @@ export default function BannerList() {
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
@@ -130,9 +132,10 @@ export default function BannerList() {
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
tintColor={colors.primary}
/>
}
style={[Styles.h100]}
style={[Styles.h100, { backgroundColor: colors.background }]}
>
{
entities.length > 0
@@ -160,7 +163,7 @@ export default function BannerList() {
</View>
:
<View style={[Styles.p15, Styles.mb100]}>
<Text style={[Styles.textDefault, Styles.cGray, { textAlign: 'center' }]}>Tidak ada data</Text>
<Text style={[Styles.textDefault, { textAlign: 'center' }]}>Tidak ada data</Text>
</View>
}
@@ -170,7 +173,7 @@ export default function BannerList() {
<DrawerBottom animation="slide" isVisible={isModal} setVisible={() => setModal(false)} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<MaterialCommunityIcons name="pencil-outline" color="black" size={25} />}
icon={<MaterialCommunityIcons name="pencil-outline" color={colors.text} size={25} />}
title="Edit"
onPress={() => {
setModal(false)
@@ -178,7 +181,7 @@ export default function BannerList() {
}}
/>
<MenuItemRow
icon={<MaterialCommunityIcons name="file-eye" color="black" size={25} />}
icon={<MaterialCommunityIcons name="file-eye" color={colors.text} size={25} />}
title="Lihat"
onPress={() => {
setModal(false)
@@ -189,7 +192,7 @@ export default function BannerList() {
}}
/>
<MenuItemRow
icon={<Ionicons name="trash" color="black" size={25} />}
icon={<Ionicons name="trash-outline" color={colors.text} size={25} />}
title="Hapus"
onPress={() => {
setModal(false)

View File

@@ -18,6 +18,7 @@ import Styles from "@/constants/Styles";
import { apiDeleteDiscussionGeneralCommentar, apiGetDiscussionGeneralOne, apiSendDiscussionGeneralCommentar, apiUpdateDiscussionGeneralCommentar } from "@/lib/api";
import { getDB } from "@/lib/firebaseDatabase";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { Feather, Ionicons, MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons";
import { ref } from '@react-native-firebase/database';
import { useHeaderHeight } from '@react-navigation/elements';
@@ -56,6 +57,7 @@ type PropsFile = {
export default function DetailDiscussionGeneral() {
const { token, decryptToken } = useAuthSession()
const { colors } = useTheme();
const entityUser = useSelector((state: any) => state.user)
const entities = useSelector((state: any) => state.entities)
const { id } = useLocalSearchParams<{ id: string }>();
@@ -80,8 +82,6 @@ export default function DetailDiscussionGeneral() {
})
const [viewEdit, setViewEdit] = useState(false)
useEffect(() => {
const onValueChange = reference.on('value', snapshot => {
if (snapshot.val() == null) {
@@ -239,14 +239,15 @@ export default function DetailDiscussionGeneral() {
)
}}
/>
<View style={{ flex: 1 }}>
<View style={{ flex: 1, backgroundColor: colors.background }}>
<ScrollView
showsVerticalScrollIndicator={false}
style={[Styles.h100]}
style={[Styles.h100, { backgroundColor: colors.background }]}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={() => handleRefresh()}
tintColor={colors.primary}
/>
}
>
@@ -260,8 +261,8 @@ export default function DetailDiscussionGeneral() {
descEllipsize={false}
borderType="bottom"
icon={
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
<MaterialIcons name="chat" size={25} color={'#384288'} />
<View style={[Styles.iconContent]}>
<MaterialIcons name="chat" size={25} color={'black'} />
</View>
}
title={data?.title}
@@ -275,13 +276,13 @@ export default function DetailDiscussionGeneral() {
desc={data?.desc}
leftBottomInfo={
<View style={[Styles.rowItemsCenter]}>
<Ionicons name="chatbox-ellipses-outline" size={18} color="grey" style={Styles.mr05} />
<Text style={[Styles.textInformation, Styles.cGray, Styles.mb05]}>{dataKomentar.length} Komentar</Text>
<Ionicons name="chatbox-ellipses-outline" size={18} color={colors.dimmed} style={Styles.mr05} />
<Text style={[Styles.textInformation, { color: colors.dimmed }, Styles.mb05]}>{dataKomentar.length} Komentar</Text>
</View>
}
rightBottomInfo={
<View style={[Styles.rowItemsCenter]}>
<Text style={[Styles.textInformation, Styles.cGray, Styles.mb05]}>{data?.createdAt}</Text>
<Text style={[Styles.textInformation, { color: colors.dimmed }, Styles.mb05]}>{data?.createdAt}</Text>
</View>
}
/>
@@ -309,6 +310,7 @@ export default function DetailDiscussionGeneral() {
desc={item.comment}
rightBottomInfo={item.isEdited ? "Edited" : ""}
descEllipsize={detailMore.includes(item.id) ? false : true}
bgColor="transparent"
onPress={() => {
setDetailMore((prev: any) => {
if (prev.includes(item.id)) {
@@ -335,7 +337,7 @@ export default function DetailDiscussionGeneral() {
<View style={[
Styles.contentItemCenter,
Styles.w100,
{ backgroundColor: "#f4f4f4" },
{ backgroundColor: colors.background },
viewEdit && Styles.borderTop
]}>
{
@@ -343,11 +345,11 @@ export default function DetailDiscussionGeneral() {
<>
<View style={[Styles.w90, Styles.rowSpaceBetween, Styles.pv05]}>
<View style={[Styles.rowItemsCenter]}>
<Feather name="edit-3" color="black" size={22} style={[Styles.mh05]} />
<Feather name="edit-3" color={colors.text} size={22} style={[Styles.mh05]} />
<Text style={[Styles.textMediumSemiBold]}>Edit Komentar</Text>
</View>
<Pressable onPress={() => handleViewEditKomentar()}>
<MaterialIcons name="close" color="black" size={22} />
<MaterialIcons name="close" color={colors.text} size={22} />
</Pressable>
</View>
<InputForm
@@ -355,7 +357,6 @@ export default function DetailDiscussionGeneral() {
type="default"
round
placeholder="Kirim Komentar"
bg="white"
onChange={(val: string) => setSelectKomentar({ ...selectKomentar, comment: val })}
value={selectKomentar.comment}
multiline
@@ -369,7 +370,7 @@ export default function DetailDiscussionGeneral() {
Platform.OS == 'android' && Styles.mb12,
]}
>
<MaterialIcons name="send" size={25} style={(loadingSendKomentar || selectKomentar.comment == '' || regexOnlySpacesOrEnter.test(selectKomentar.comment) || data?.status === 2 || !data?.isActive || (!memberDiscussion && (entityUser.role == "user" || entityUser.role == "coadmin"))) ? Styles.cGray : Styles.cDefault} />
<MaterialIcons name="send" size={25} style={(loadingSendKomentar || selectKomentar.comment == '' || regexOnlySpacesOrEnter.test(selectKomentar.comment) || data?.status === 2 || !data?.isActive || (!memberDiscussion && (entityUser.role == "user" || entityUser.role == "coadmin"))) ? {color:colors.dimmed} : {color:colors.tint}} />
</Pressable>
}
/>
@@ -382,7 +383,6 @@ export default function DetailDiscussionGeneral() {
type="default"
round
placeholder="Kirim Komentar"
bg="white"
onChange={setKomentar}
value={komentar}
multiline
@@ -396,7 +396,7 @@ export default function DetailDiscussionGeneral() {
Platform.OS == 'android' && Styles.mb12,
]}
>
<MaterialIcons name="send" size={25} style={(loadingSendKomentar || komentar == '' || regexOnlySpacesOrEnter.test(komentar) || data?.status === 2 || !data?.isActive || (!memberDiscussion && (entityUser.role == "user" || entityUser.role == "coadmin"))) ? Styles.cGray : Styles.cDefault} />
<MaterialIcons name="send" size={25} style={(loadingSendKomentar || komentar == '' || regexOnlySpacesOrEnter.test(komentar) || data?.status === 2 || !data?.isActive || (!memberDiscussion && (entityUser.role == "user" || entityUser.role == "coadmin"))) ? {color: colors.dimmed} : {color:colors.tint}} />
</Pressable>
}
/>
@@ -417,12 +417,12 @@ export default function DetailDiscussionGeneral() {
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={setVisible} title="Komentar">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<MaterialCommunityIcons name="pencil-outline" color="black" size={25} />}
icon={<MaterialCommunityIcons name="pencil-outline" color={colors.text} size={25} />}
title="Edit"
onPress={() => { handleViewEditKomentar() }}
/>
<MenuItemRow
icon={<MaterialIcons name="delete" color="black" size={25} />}
icon={<Ionicons name="trash-outline" color={colors.text} size={25} />}
title="Hapus"
onPress={() => {
AlertKonfirmasi({

View File

@@ -9,6 +9,7 @@ import Styles from "@/constants/Styles";
import { apiAddMemberDiscussionGeneral, apiGetDiscussionGeneralOne, apiGetUser } from "@/lib/api";
import { setUpdateDiscussionGeneralDetail } from "@/lib/discussionGeneralDetail";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { AntDesign } from "@expo/vector-icons";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
@@ -26,6 +27,7 @@ export default function AddMemberDiscussionDetail() {
const dispatch = useDispatch()
const update = useSelector((state: any) => state.discussionGeneralDetailUpdate)
const { token, decryptToken } = useAuthSession()
const { colors } = useTheme();
const { id } = useLocalSearchParams<{ id: string }>()
const [dataOld, setDataOld] = useState<Props[]>([])
const [data, setData] = useState<Props[]>([])
@@ -125,7 +127,7 @@ export default function AddMemberDiscussionDetail() {
)
}}
/>
<View style={[Styles.p15]}>
<View style={[Styles.p15, { backgroundColor: colors.background }]}>
<InputSearch onChange={setSearch} value={search} />
{
@@ -147,7 +149,7 @@ export default function AddMemberDiscussionDetail() {
</View>
:
<Text style={[Styles.textDefault, Styles.cGray, Styles.pv05, { textAlign: 'center' }]}>Tidak ada member yang dipilih</Text>
<Text style={[Styles.textDefault, Styles.pv05, { textAlign: 'center', color: colors.dimmed }]}>Tidak ada member yang dipilih</Text>
}
<ScrollView
showsVerticalScrollIndicator={false}
@@ -160,7 +162,7 @@ export default function AddMemberDiscussionDetail() {
return (
<Pressable
key={index}
style={[Styles.itemSelectModal]}
style={[Styles.itemSelectModal, { borderColor: colors.icon + '20' }]}
onPress={() => {
!found && onChoose(item.id, item.name, item.img)
}}
@@ -170,12 +172,12 @@ export default function AddMemberDiscussionDetail() {
<View style={[Styles.ml10]}>
<Text style={[Styles.textDefault]}>{item.name}</Text>
{
found && <Text style={[Styles.textInformation, Styles.cGray]}>sudah menjadi anggota</Text>
found && <Text style={[Styles.textInformation, {color: colors.dimmed}]}>sudah menjadi anggota</Text>
}
</View>
</View>
{
selectMember.some((i: any) => i.idUser == item.id) && <AntDesign name="check" size={20} color={'black'} />
selectMember.some((i: any) => i.idUser == item.id) && <AntDesign name="check" size={20} color={colors.text} />
}
</Pressable>
)

View File

@@ -16,6 +16,7 @@ import { apiCreateDiscussionGeneral } from "@/lib/api";
import { setUpdateDiscussionGeneralDetail } from "@/lib/discussionGeneralDetail";
import { setMemberChoose } from "@/lib/memberChoose";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons";
import * as DocumentPicker from "expo-document-picker";
import { router, Stack } from "expo-router";
@@ -27,6 +28,7 @@ import { useDispatch, useSelector } from "react-redux";
export default function CreateDiscussionGeneral() {
const { token, decryptToken } = useAuthSession()
const { colors } = useTheme();
const entityUser = useSelector((state: any) => state.user);
const userLogin = useSelector((state: any) => state.entities)
const [chooseGroup, setChooseGroup] = useState({ val: "", label: "" });
@@ -163,7 +165,7 @@ export default function CreateDiscussionGeneral() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -205,7 +207,7 @@ export default function CreateDiscussionGeneral() {
}}
/>
<LoadingOverlay visible={loading} />
<ScrollView showsVerticalScrollIndicator={false} style={[Styles.h100]}>
<ScrollView showsVerticalScrollIndicator={false} style={[Styles.h100, { backgroundColor: colors.background }]}>
<View style={[Styles.p15, Styles.mb100]}>
{
(entityUser.role == "supadmin" ||
@@ -215,6 +217,7 @@ export default function CreateDiscussionGeneral() {
placeholder="Pilih Lembaga Desa"
value={chooseGroup.label}
required
bg={colors.card}
onPress={() => {
setValChoose(chooseGroup.val);
setValSelect("group");
@@ -231,6 +234,7 @@ export default function CreateDiscussionGeneral() {
placeholder="Judul"
required
error={error.title}
bg={colors.card}
errorText="Judul tidak boleh kosong"
onChange={(val) => { validationForm("title", val) }}
/>
@@ -240,6 +244,7 @@ export default function CreateDiscussionGeneral() {
placeholder="Hal yang didiskusikan"
required
error={error.desc}
bg={colors.card}
errorText="Diskusi tidak boleh kosong"
onChange={(val) => { validationForm("desc", val) }}
multiline
@@ -248,15 +253,16 @@ export default function CreateDiscussionGeneral() {
{
fileForm.length > 0
&&
<View style={[Styles.borderAll, Styles.round10, Styles.p10, Styles.mb10]}>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { borderColor: colors.icon + '20' }]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
{
fileForm.map((item, index) => (
<BorderBottomItem
key={index}
borderType={fileForm.length > 1 ? "bottom" : "none"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
borderType={fileForm.length - 1 == index ? "none" : "bottom"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
bgColor="transparent"
titleWeight="normal"
onPress={() => { setIndexDelFile(index); setModalFile(true) }}
/>
@@ -291,17 +297,18 @@ export default function CreateDiscussionGeneral() {
<Text>Total {entitiesMember.length} Anggota</Text>
</View>
<View style={[Styles.borderAll, Styles.round10, Styles.p10]}>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, { borderColor: colors.icon + '20' }]}>
{
entitiesMember.map((item: { img: any; name: any; }, index: any) => {
return (
<BorderBottomItem
key={index}
borderType="bottom"
borderType={entitiesMember.length - 1 == index ? "none" : "bottom"}
icon={
<ImageUser src={`${ConstEnv.url_storage}/files/${item.img}`} size="sm" />
<ImageUser src={`${ConstEnv.url_storage}/files/${item.img}`} size="xs" />
}
title={item.name}
bgColor="transparent"
/>
)
})
@@ -327,7 +334,7 @@ export default function CreateDiscussionGeneral() {
<DrawerBottom animation="slide" isVisible={isModalFile} setVisible={setModalFile} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<Ionicons name="trash" color="black" size={25} />}
icon={<Ionicons name="trash-outline" color={colors.text} size={25} />}
title="Hapus"
onPress={() => { deleteFile(indexDelFile) }}
/>

View File

@@ -11,6 +11,7 @@ import Styles from "@/constants/Styles";
import { apiEditDiscussionGeneral, apiGetDiscussionGeneralOne } from "@/lib/api";
import { setUpdateDiscussionGeneralDetail } from "@/lib/discussionGeneralDetail";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons";
import * as DocumentPicker from "expo-document-picker";
import { router, Stack, useLocalSearchParams } from "expo-router";
@@ -21,6 +22,7 @@ import { useDispatch, useSelector } from "react-redux";
export default function EditDiscussionGeneral() {
const { token, decryptToken } = useAuthSession();
const { colors } = useTheme();
const { id } = useLocalSearchParams<{ id: string }>();
const [disableBtn, setDisableBtn] = useState(false)
const dispatch = useDispatch()
@@ -162,7 +164,7 @@ export default function EditDiscussionGeneral() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -198,13 +200,14 @@ export default function EditDiscussionGeneral() {
}}
/>
<LoadingOverlay visible={loading} />
<ScrollView showsVerticalScrollIndicator={false} style={[Styles.h100]}>
<ScrollView showsVerticalScrollIndicator={false} style={[Styles.h100, { backgroundColor: colors.background }]}>
<View style={[Styles.p15]}>
<InputForm
label="Judul"
type="default"
placeholder="Judul"
required
bg={colors.card}
error={error.title}
value={dataForm.title}
errorText="Judul tidak boleh kosong"
@@ -215,6 +218,7 @@ export default function EditDiscussionGeneral() {
type="default"
placeholder="Hal yang didiskusikan"
required
bg={colors.card}
error={error.desc}
value={dataForm.desc}
errorText="Diskusi tidak boleh kosong"
@@ -225,16 +229,17 @@ export default function EditDiscussionGeneral() {
{
(fileForm.length > 0 || dataFile.filter((val) => !val.delete).length > 0)
&&
<View style={[Styles.borderAll, Styles.round10, Styles.p10, Styles.mb10]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { borderColor: colors.icon + '20' }]}>
<Text style={[Styles.textDefault]}>File</Text>
{
dataFile.filter((val) => !val.delete).map((item, index) => (
<BorderBottomItem
key={index}
borderType={(fileForm.length + dataFile.length) > 1 ? "bottom" : "none"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name + '.' + item.extension}
titleWeight="normal"
bgColor="transparent"
onPress={() => { setIndexDelFile({ id: item.id, cat: "oldFile" }); setModalFile(true) }}
/>
))
@@ -244,9 +249,10 @@ export default function EditDiscussionGeneral() {
<BorderBottomItem
key={index}
borderType={(fileForm.length + dataFile.length) > 1 ? "bottom" : "none"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
titleWeight="normal"
bgColor="transparent"
onPress={() => { setIndexDelFile({ id: index, cat: "newFile" }); setModalFile(true) }}
/>
))
@@ -259,7 +265,7 @@ export default function EditDiscussionGeneral() {
<DrawerBottom animation="slide" isVisible={isModalFile} setVisible={setModalFile} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<Ionicons name="trash" color="black" size={25} />}
icon={<Ionicons name="trash-outline" color={colors.text} size={25} />}
title="Hapus"
onPress={() => { deleteFile(indexDelFile.id, indexDelFile.cat) }}
/>

View File

@@ -4,10 +4,12 @@ import InputSearch from "@/components/inputSearch";
import LabelStatus from "@/components/labelStatus";
import SkeletonContent from "@/components/skeletonContent";
import Text from "@/components/Text";
import WrapTab from "@/components/wrapTab";
import { ColorsStatus } from "@/constants/ColorsStatus";
import Styles from "@/constants/Styles";
import { apiGetDiscussionGeneral } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { AntDesign, Feather, Ionicons, MaterialIcons } from "@expo/vector-icons";
import { router, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
@@ -27,6 +29,7 @@ type Props = {
export default function Discussion() {
const entityUser = useSelector((state: any) => state.user)
const { token, decryptToken } = useAuthSession()
const { colors } = useTheme();
const { active, group } = useLocalSearchParams<{ active?: string, group?: string }>()
const [search, setSearch] = useState('')
const [nameGroup, setNameGroup] = useState('')
@@ -96,33 +99,34 @@ export default function Discussion() {
})
return (
<View style={[Styles.p15, { flex: 1 }]}>
<View style={[Styles.p15, { flex: 1, backgroundColor: colors.background }]}>
<View>
{
entityUser.role != "user" && entityUser.role != "coadmin" &&
<View style={[Styles.wrapBtnTab]}>
<WrapTab>
<ButtonTab
active={status == "false" ? "false" : "true"}
value="true"
onPress={() => { setStatus("true") }}
label="Aktif"
icon={<Feather name="check-circle" color={status == "false" ? 'black' : 'white'} size={20} />}
icon={<Feather name="check-circle" color={status == "false" ? colors.dimmed : 'white'} size={20} />}
n={2} />
<ButtonTab
active={status == "false" ? "false" : "true"}
value="false"
onPress={() => { setStatus("false") }}
label="Arsip"
icon={<AntDesign name="closecircleo" color={status == "true" ? 'black' : 'white'} size={20} />}
icon={<AntDesign name="closecircleo" color={status == "true" ? colors.dimmed : 'white'} size={20} />}
n={2} />
</View>
</WrapTab>
}
<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>
@@ -144,12 +148,13 @@ export default function Discussion() {
renderItem={({ item, index }: { item: Props, index: number }) => {
return (
<BorderBottomItem
bgColor="transparent"
key={index}
onPress={() => { router.push(`/discussion/${item.id}`) }}
borderType="bottom"
icon={
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
<MaterialIcons name="chat" size={25} color={'#384288'} />
<View style={[Styles.iconContent]}>
<MaterialIcons name="chat" size={25} color={'black'} />
</View>
}
title={item.title}
@@ -160,8 +165,8 @@ export default function Discussion() {
desc={item.desc.replace(/<[^>]*>?/gm, ' ').replace(/\r?\n|\r/g, ' ')}
leftBottomInfo={
<View style={[Styles.rowItemsCenter]}>
<Ionicons name="chatbox-ellipses-outline" size={18} color="grey" style={Styles.mr05} />
<Text style={[Styles.textInformation, Styles.cGray, Styles.mb05]}>Diskusikan</Text>
<Ionicons name="chatbox-ellipses-outline" size={18} color={colors.dimmed} style={Styles.mr05} />
<Text style={[Styles.textInformation, {color: colors.dimmed}, Styles.mb05]}>Diskusikan</Text>
</View>
}
rightBottomInfo={`${item.total_komentar} Komentar`}
@@ -177,6 +182,7 @@ export default function Discussion() {
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
tintColor={colors.primary}
/>
}
/>

View File

@@ -11,6 +11,7 @@ import { ConstEnv } from "@/constants/ConstEnv";
import Styles from "@/constants/Styles";
import { apiDeleteMemberDiscussionGeneral, apiGetDiscussionGeneralOne } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { Feather, MaterialCommunityIcons } from "@expo/vector-icons";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
@@ -26,6 +27,7 @@ type Props = {
export default function MemberDiscussionDetail() {
const { token, decryptToken } = useAuthSession()
const { colors } = useTheme();
const entityUser = useSelector((state: any) => state.user)
const { id } = useLocalSearchParams<{ id: string }>()
const [data, setData] = useState<Props[]>([])
@@ -71,7 +73,7 @@ export default function MemberDiscussionDetail() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
@@ -86,10 +88,10 @@ export default function MemberDiscussionDetail() {
)
}}
/>
<ScrollView>
<ScrollView style={{ backgroundColor: colors.background }}>
<View style={[Styles.p15]}>
<Text style={[Styles.textDefault, Styles.mv05]}>{data.length} Anggota</Text>
<View style={[Styles.wrapPaper, Styles.mb100]}>
<View style={[Styles.wrapPaper, { backgroundColor: colors.card, borderColor: colors.background }]}>
{
entityUser.role != "user" && entityUser.role != "coadmin" &&
<BorderBottomItem
@@ -135,7 +137,7 @@ export default function MemberDiscussionDetail() {
<DrawerBottom animation="slide" isVisible={isModal} setVisible={setModal} title={chooseUser.name}>
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<MaterialCommunityIcons name="account-eye" color="black" size={25} />}
icon={<MaterialCommunityIcons name="account-eye" color={colors.text} size={25} />}
title="Lihat Profil"
onPress={() => {
setModal(false)
@@ -145,7 +147,7 @@ export default function MemberDiscussionDetail() {
{
entityUser.role != "user" && entityUser.role != "coadmin" &&
<MenuItemRow
icon={<MaterialCommunityIcons name="account-remove" color="black" size={25} />}
icon={<MaterialCommunityIcons name="account-remove" color={colors.text} size={25} />}
title="Keluarkan"
onPress={() => {
setModal(false)

View File

@@ -9,6 +9,7 @@ import Styles from "@/constants/Styles";
import { apiAddMemberCalendar, apiGetCalendarOne, apiGetDivisionMember } from "@/lib/api";
import { setUpdateCalendar } from "@/lib/calendarUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { AntDesign } from "@expo/vector-icons";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
@@ -23,6 +24,7 @@ type Props = {
}
export default function AddMemberCalendarEvent() {
const { colors } = useTheme();
const dispatch = useDispatch()
const update = useSelector((state: any) => state.calendarUpdate)
const { token, decryptToken } = useAuthSession()
@@ -100,7 +102,7 @@ export default function AddMemberCalendarEvent() {
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
@@ -182,7 +184,7 @@ export default function AddMemberCalendarEvent() {
</View>
</View>
{
selectMember.some((i: any) => i.idUser == item.idUser) && <AntDesign name="check" size={20} color={'black'} />
selectMember.some((i: any) => i.idUser == item.idUser) && <AntDesign name="check" size={20} color={colors.text} />
}
</Pressable>
)

View File

@@ -9,6 +9,7 @@ import { valueTypeEventRepeat } from "@/constants/TypeEventRepeat"
import { apiGetCalendarOne, apiUpdateCalendar } from "@/lib/api"
import { stringToDateTime } from "@/lib/fun_stringToDate"
import { useAuthSession } from "@/providers/AuthProvider"
import { useTheme } from "@/providers/ThemeProvider";
import { useHeaderHeight } from "@react-navigation/elements"
import { Stack, router, useLocalSearchParams } from "expo-router"
import moment from "moment"
@@ -17,6 +18,7 @@ import { KeyboardAvoidingView, Platform, SafeAreaView, ScrollView, View } from "
import Toast from "react-native-toast-message"
export default function EditEventCalendar() {
const { colors } = useTheme();
const { token, decryptToken } = useAuthSession();
const [choose, setChoose] = useState({ val: "", label: "" })
const [isSelect, setSelect] = useState(false)
@@ -162,7 +164,7 @@ export default function EditEventCalendar() {
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
@@ -205,7 +207,7 @@ export default function EditEventCalendar() {
type="default"
placeholder="Nama Acara"
required
bg="white"
bg={colors.card}
value={data.title}
onChange={(val) => validationForm("title", val)}
error={error.title}
@@ -251,12 +253,12 @@ export default function EditEventCalendar() {
label="Link Meet"
type="default"
placeholder="Link Meet"
bg="white"
bg={colors.card}
value={data.linkMeet}
onChange={(val) => validationForm("linkMeet", val)}
/>
<SelectForm
bg="white"
bg={colors.card}
label="Ulangi Acara"
placeholder="Ulangi Acara"
value={choose.label}
@@ -268,7 +270,7 @@ export default function EditEventCalendar() {
type="numeric"
placeholder="Jumlah Pengulangan"
required
bg="white"
bg={colors.card}
value={String(data.repeatValue)}
onChange={(val) => validationForm("repeatValue", val)}
error={error.repeatValue}
@@ -279,7 +281,7 @@ export default function EditEventCalendar() {
label="Deskripsi"
type="default"
placeholder="Deskripsi"
bg="white"
bg={colors.card}
value={data.desc}
onChange={(val) => validationForm("desc", val)}
multiline

View File

@@ -13,6 +13,7 @@ import Styles from "@/constants/Styles"
import { apiDeleteCalendarMember, apiGetCalendarOne, apiGetDivisionOneFeature } from "@/lib/api"
import { setUpdateCalendar } from "@/lib/calendarUpdate"
import { useAuthSession } from "@/providers/AuthProvider"
import { useTheme } from "@/providers/ThemeProvider"
import { MaterialCommunityIcons } from "@expo/vector-icons"
import Clipboard from "@react-native-clipboard/clipboard"
import { router, Stack, useLocalSearchParams } from "expo-router"
@@ -45,6 +46,7 @@ type PropsMember = {
}
export default function DetailEventCalendar() {
const { colors } = useTheme()
const { id, detail } = useLocalSearchParams<{ id: string, detail: string }>();
const [data, setData] = useState<Props>()
const [member, setMember] = useState<PropsMember[]>([])
@@ -152,14 +154,14 @@ export default function DetailEventCalendar() {
};
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// 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)} />
header:()=>(
header: () => (
<AppHeader
title="Detail Acara"
showBack={true}
@@ -181,9 +183,9 @@ export default function DetailEventCalendar() {
}
>
<View style={[Styles.p15]}>
<View style={[Styles.wrapPaper, Styles.mb15]}>
<View style={[Styles.wrapPaper, Styles.mb15, { backgroundColor: colors.card, borderColor: colors.background }]}>
<View style={[Styles.rowItemsCenter, { alignItems: 'flex-start' }]}>
<MaterialCommunityIcons name="calendar-text" size={30} color="black" style={Styles.mr10} />
<MaterialCommunityIcons name="calendar-text" size={30} color={colors.text} style={Styles.mr10} />
{
loading ?
<Skeleton width={80} height={10} borderRadius={10} widthType="percent" />
@@ -192,7 +194,7 @@ export default function DetailEventCalendar() {
</View>
<View style={[Styles.rowItemsCenter, Styles.mt10]}>
<MaterialCommunityIcons name="calendar-month-outline" size={30} color="black" style={Styles.mr10} />
<MaterialCommunityIcons name="calendar-month-outline" size={30} color={colors.text} style={Styles.mr10} />
{
loading ?
<Skeleton width={80} height={10} borderRadius={10} widthType="percent" />
@@ -201,7 +203,7 @@ export default function DetailEventCalendar() {
}
</View>
<View style={[Styles.rowItemsCenter, Styles.mt10]}>
<MaterialCommunityIcons name="clock-outline" size={30} color="black" style={Styles.mr10} />
<MaterialCommunityIcons name="clock-outline" size={30} color={colors.text} style={Styles.mr10} />
{
loading ?
<Skeleton width={80} height={10} borderRadius={10} widthType="percent" />
@@ -210,7 +212,7 @@ export default function DetailEventCalendar() {
}
</View>
<View style={[Styles.rowItemsCenter, Styles.mt10]}>
<MaterialCommunityIcons name="repeat" size={30} color="black" style={Styles.mr10} />
<MaterialCommunityIcons name="repeat" size={30} color={colors.text} style={Styles.mr10} />
{
loading ?
<Skeleton width={80} height={10} borderRadius={10} widthType="percent" />
@@ -228,7 +230,7 @@ export default function DetailEventCalendar() {
}
</View>
<View style={[Styles.rowItemsCenter, Styles.mt10]}>
<MaterialCommunityIcons name="link-variant" size={30} color="black" style={Styles.mr10} />
<MaterialCommunityIcons name="link-variant" size={30} color={colors.text} style={Styles.mr10} />
{
loading ?
<Skeleton width={80} height={10} borderRadius={10} widthType="percent" />
@@ -241,7 +243,7 @@ export default function DetailEventCalendar() {
}
</View>
<View style={[Styles.rowItemsCenter, Styles.mt10, { alignItems: 'flex-start' }]}>
<MaterialCommunityIcons name="card-text-outline" size={30} color="black" style={Styles.mr10} />
<MaterialCommunityIcons name="card-text-outline" size={30} color={colors.text} style={Styles.mr10} />
{
loading ?
<Skeleton width={80} height={10} borderRadius={10} widthType="percent" />
@@ -257,7 +259,7 @@ export default function DetailEventCalendar() {
<Text style={[Styles.textDefault]}>Total {member.length} Anggota</Text>
</View>
<View style={[Styles.wrapPaper]}>
<View style={[Styles.wrapPaper, { backgroundColor: colors.card, borderColor: colors.background }]}>
{
member.map((item, index) => (
<BorderBottomItem
@@ -286,7 +288,7 @@ export default function DetailEventCalendar() {
<DrawerBottom animation="slide" isVisible={isModalMember} setVisible={setModalMember} title={memberChoose.name}>
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<MaterialCommunityIcons name="account-eye" color="black" size={25} />}
icon={<MaterialCommunityIcons name="account-eye" color={colors.text} size={25} />}
title="Lihat Profil"
onPress={() => {
setModalMember(false)
@@ -295,7 +297,7 @@ export default function DetailEventCalendar() {
/>
<MenuItemRow
icon={<MaterialCommunityIcons name="account-remove" color="black" size={25} />}
icon={<MaterialCommunityIcons name="account-remove" color={colors.text} size={25} />}
title="Keluarkan"
onPress={() => {
setModalMember(false)

View File

@@ -10,6 +10,7 @@ import { apiCreateCalendar, apiGetDivisionMember } from "@/lib/api";
import { setFormCreateCalendar } from "@/lib/calendarCreate";
import { setUpdateCalendar } from "@/lib/calendarUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { AntDesign } from "@expo/vector-icons";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
@@ -24,6 +25,7 @@ type Props = {
}
export default function CreateCalendarAddMember() {
const { colors } = useTheme();
const { token, decryptToken } = useAuthSession()
const { id } = useLocalSearchParams<{ id: string }>()
const [data, setData] = useState<Props[]>([])
@@ -90,7 +92,7 @@ export default function CreateCalendarAddMember() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
@@ -154,7 +156,7 @@ export default function CreateCalendarAddMember() {
return (
<Pressable
key={index}
style={[Styles.itemSelectModal]}
style={[Styles.itemSelectModal, {borderColor: colors.icon + '20'}]}
onPress={() => { onChoose(item.idUser, item.name, item.img) }}
>
<View style={[Styles.rowItemsCenter, Styles.w70]}>
@@ -164,7 +166,7 @@ export default function CreateCalendarAddMember() {
</View>
</View>
{
selectMember.some((i: any) => i.idUser == item.idUser) && <AntDesign name="check" size={20} color={'black'} />
selectMember.some((i: any) => i.idUser == item.idUser) && <AntDesign name="check" size={20} color={colors.text} />
}
</Pressable>
)

View File

@@ -9,6 +9,7 @@ import Styles from "@/constants/Styles";
import { setFormCreateCalendar } from "@/lib/calendarCreate";
import { stringToDateTime } from "@/lib/fun_stringToDate";
import { useHeaderHeight } from '@react-navigation/elements';
import { useTheme } from "@/providers/ThemeProvider";
import { Stack, router, useLocalSearchParams } from "expo-router";
import { useState } from "react";
import {
@@ -21,6 +22,7 @@ import {
import { useDispatch, useSelector } from "react-redux";
export default function CalendarDivisionCreate() {
const { colors } = useTheme();
const { id } = useLocalSearchParams<{ id: string }>()
const [choose, setChoose] = useState({ val: "", label: "" })
const [isSelect, setSelect] = useState(false)
@@ -126,7 +128,7 @@ export default function CalendarDivisionCreate() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -144,7 +146,7 @@ export default function CalendarDivisionCreate() {
// disable={Object.values(error).some((val) => val == true) || data.title == "" || data.dateStart == "" || data.timeStart == "" || data.timeEnd == "" || data.repeatEventType == ""}
// />
// ),
header:()=>(
header: () => (
<AppHeader
title="Tambah Acara"
showBack={true}
@@ -173,7 +175,7 @@ export default function CalendarDivisionCreate() {
type="default"
placeholder="Nama Acara"
required
bg="white"
bg={colors.card}
value={data.title}
onChange={(val) => validationForm("title", val)}
error={error.title}
@@ -219,12 +221,12 @@ export default function CalendarDivisionCreate() {
label="Link Meet"
type="default"
placeholder="Link Meet"
bg="white"
bg={colors.card}
value={data.linkMeet}
onChange={(val) => validationForm("linkMeet", val)}
/>
<SelectForm
bg="white"
bg={colors.card}
label="Ulangi Acara"
placeholder="Ulangi Acara"
value={choose.label}
@@ -236,7 +238,7 @@ export default function CalendarDivisionCreate() {
type="numeric"
placeholder="Jumlah Pengulangan"
required
bg="white"
bg={colors.card}
value={String(data.repeatValue)}
onChange={(val) => validationForm("repeatValue", val)}
error={error.repeatValue}
@@ -247,7 +249,7 @@ export default function CalendarDivisionCreate() {
label="Deskripsi"
type="default"
placeholder="Deskripsi"
bg="white"
bg={colors.card}
value={data.desc}
onChange={(val) => validationForm("desc", val)}
multiline

View File

@@ -1,10 +1,10 @@
import InputSearch from "@/components/inputSearch";
import Skeleton from "@/components/skeleton";
import Text from "@/components/Text";
import { ColorsStatus } from "@/constants/ColorsStatus";
import Styles from "@/constants/Styles";
import { apiGetCalendarHistory } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
import { FlatList, View, VirtualizedList } from "react-native";
@@ -15,6 +15,7 @@ type Props = {
data: []
}
export default function CalendarHistory() {
const { colors, activeTheme } = useTheme();
const { id } = useLocalSearchParams<{ id: string }>();
const { token, decryptToken } = useAuthSession();
const [data, setData] = useState<Props[]>([])
@@ -64,11 +65,11 @@ export default function CalendarHistory() {
})
return (
<View style={[Styles.p15, { flex: 1 }]}>
<View style={[Styles.p15, { flex: 1, backgroundColor: colors.background }]}>
<View>
<InputSearch onChange={(val) => setSearch(val)} />
</View>
<View style={[{ flex: 2, }]}>
<View style={[{ flex: 2 }, Styles.mt10]}>
{
loading ?
arrSkeleton.map((item, index) => (
@@ -81,7 +82,7 @@ export default function CalendarHistory() {
getItem={getItem}
renderItem={({ item, index }: { item: Props, index: number }) => {
return (
<View key={index} style={[{ flexDirection: 'row' }, Styles.mv05, ColorsStatus.lightGreen, Styles.p10, Styles.round10]}>
<View key={index} style={[{ flexDirection: 'row' }, Styles.mb05, Styles.borderAll, { backgroundColor: colors.card }, Styles.p10, Styles.round05, { borderColor: colors.icon + '20' }]}>
<View style={[Styles.mr10, Styles.ph05]}>
<Text style={[Styles.textSubtitle]}>{String(item.dateStart)}</Text>
<Text style={[Styles.textDefault, { textAlign: 'center' }]}>{item.year}</Text>

View File

@@ -7,6 +7,7 @@ import Text from "@/components/Text";
import Styles from "@/constants/Styles";
import { apiGetCalendarByDateDivision, apiGetIndicatorCalendar } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { Feather } from "@expo/vector-icons";
import { router, Stack, useLocalSearchParams } from "expo-router";
import 'intl';
@@ -34,6 +35,7 @@ type Props = {
};
export default function CalendarDivision() {
const { colors, activeTheme } = useTheme();
const [selected, setSelected] = useState<any>(new Date())
const [data, setData] = useState<Props[]>([])
const { token, decryptToken } = useAuthSession()
@@ -117,15 +119,15 @@ export default function CalendarDivision() {
);
},
IconNext: <Pressable onPress={() => !loadingBtn ? setMonth(month + 1) : null}>
<Feather name="chevron-right" size={20} color={loadingBtn ? 'gray' : 'black'} />
<Feather name="chevron-right" size={20} color={loadingBtn ? 'gray' : colors.text} />
</Pressable>,
IconPrev: <Pressable onPress={() => !loadingBtn ? setMonth(month - 1) : null}>
<Feather name="chevron-left" size={20} color={loadingBtn ? 'gray' : 'black'} />
<Feather name="chevron-left" size={20} color={loadingBtn ? 'gray' : colors.text} />
</Pressable>,
};
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -158,7 +160,7 @@ export default function CalendarDivision() {
style={[Styles.h100]}
>
<View style={[Styles.p15]}>
<View style={[Styles.wrapPaper, Styles.p10]}>
<View style={[Styles.wrapPaper, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
<Datepicker
components={components}
mode="single"
@@ -167,19 +169,19 @@ export default function CalendarDivision() {
onMonthChange={(month) => setMonth(month)}
styles={{
selected: Styles.selectedDate,
month_label: Styles.cBlack,
month_selector_label: Styles.cBlack,
year_label: Styles.cBlack,
year_selector_label: Styles.cBlack,
day_label: Styles.cBlack,
time_label: Styles.cBlack,
weekday_label: Styles.cBlack,
month_label: { color: colors.text },
month_selector_label: { color: colors.text },
year_label: { color: colors.text },
year_selector_label: { color: colors.text },
day_label: { color: colors.text },
time_label: { color: colors.text },
weekday_label: { color: colors.text },
}}
/>
</View>
<View style={[Styles.mb15, Styles.mt15]}>
<Text style={[Styles.textDefaultSemiBold, Styles.mb05]}>Acara</Text>
<View style={[Styles.wrapPaper]}>
<View style={[Styles.wrapPaper, { backgroundColor: colors.card, borderColor: colors.background }]}>
{
loading ?
<>

View File

@@ -11,6 +11,7 @@ import Styles from "@/constants/Styles";
import { apiEditDiscussion, apiGetDiscussionOne } from "@/lib/api";
import { setUpdateDiscussion } from "@/lib/discussionUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons";
import * as DocumentPicker from "expo-document-picker";
import { router, Stack, useLocalSearchParams } from "expo-router";
@@ -20,6 +21,7 @@ import Toast from "react-native-toast-message";
import { useDispatch, useSelector } from "react-redux";
export default function DiscussionDivisionEdit() {
const { colors } = useTheme();
const { id, detail } = useLocalSearchParams<{ id: string; detail: string }>();
const { token, decryptToken } = useAuthSession();
const [data, setData] = useState("");
@@ -127,7 +129,7 @@ export default function DiscussionDivisionEdit() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -177,20 +179,21 @@ export default function DiscussionDivisionEdit() {
value={data}
onChange={setData}
multiline
bg={colors.card}
/>
<ButtonSelect value="Upload File" onPress={pickDocumentAsync} />
{
(fileForm.length > 0 || dataFile.filter((val) => !val.delete).length > 0)
&&
<View style={[Styles.borderAll, Styles.round10, Styles.p10, Styles.mb10]}>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { borderColor: colors.background, backgroundColor: colors.card }]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
{
dataFile.filter((val) => !val.delete).map((item, index) => (
<BorderBottomItem
key={index}
borderType={(fileForm.length + dataFile.length) > 1 ? "bottom" : "none"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name + '.' + item.extension}
titleWeight="normal"
onPress={() => { setIndexDelFile({ id: item.id, cat: "oldFile" }); setModalFile(true) }}
@@ -202,7 +205,7 @@ export default function DiscussionDivisionEdit() {
<BorderBottomItem
key={index}
borderType={fileForm.length > 1 ? "bottom" : "none"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
titleWeight="normal"
onPress={() => { setIndexDelFile({ id: index, cat: "newFile" }); setModalFile(true) }}
@@ -218,7 +221,7 @@ export default function DiscussionDivisionEdit() {
<DrawerBottom animation="slide" isVisible={isModalFile} setVisible={setModalFile} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<Ionicons name="trash" color="black" size={25} />}
icon={<Ionicons name="trash-outline" color={colors.text} size={25} />}
title="Hapus"
onPress={() => { deleteFile(indexDelFile.id, indexDelFile.cat) }}
/>

View File

@@ -25,6 +25,7 @@ import { getDB } from "@/lib/firebaseDatabase";
import { useAuthSession } from "@/providers/AuthProvider";
import { Feather, Ionicons, MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons";
import { ref } from "@react-native-firebase/database";
import { useTheme } from "@/providers/ThemeProvider";
import { useHeaderHeight } from '@react-navigation/elements';
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
@@ -64,6 +65,7 @@ type PropsFile = {
}
export default function DiscussionDetail() {
const { colors } = useTheme();
const { id, detail } = useLocalSearchParams<{ id: string; detail: string }>();
const [data, setData] = useState<Props>();
const [dataComment, setDataComment] = useState<PropsComment[]>([]);
@@ -295,7 +297,7 @@ export default function DiscussionDetail() {
showBack={true}
onPressLeft={() => router.back()}
right={
(entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision || isCreator ?
((entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision || isCreator) ?
<HeaderRightDiscussionDetail
id={detail}
status={data?.status}
@@ -306,7 +308,7 @@ export default function DiscussionDetail() {
)
}}
/>
<View style={{ flex: 1 }}>
<View style={{ flex: 1, backgroundColor: colors.background }}>
<ScrollView
refreshControl={
<RefreshControl
@@ -410,7 +412,7 @@ export default function DiscussionDetail() {
style={[
Styles.contentItemCenter,
Styles.w100,
{ backgroundColor: "#f4f4f4" },
{ backgroundColor: colors.background },
viewEdit && Styles.borderTop
]}
>
@@ -419,15 +421,15 @@ export default function DiscussionDetail() {
<>
<View style={[Styles.w90, Styles.rowSpaceBetween, Styles.pv05]}>
<View style={[Styles.rowItemsCenter]}>
<Feather name="edit-3" color="black" size={22} style={[Styles.mh05]} />
<Feather name="edit-3" color={colors.text} size={22} style={[Styles.mh05]} />
<Text style={[Styles.textMediumSemiBold]}>Edit Komentar</Text>
</View>
<Pressable onPress={() => handleViewEditKomentar()}>
<MaterialIcons name="close" color="black" size={22} />
<MaterialIcons name="close" color={colors.text} size={22} />
</Pressable>
</View>
<InputForm
bg="white"
bg={colors.card}
type="default"
round
multiline
@@ -474,7 +476,7 @@ export default function DiscussionDetail() {
isMemberDivision)
?
<InputForm
bg="white"
bg={colors.card}
type="default"
round
multiline
@@ -531,12 +533,12 @@ export default function DiscussionDetail() {
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={setVisible} title="Komentar">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<MaterialCommunityIcons name="pencil-outline" color="black" size={25} />}
icon={<MaterialCommunityIcons name="pencil-outline" color={colors.text} size={25} />}
title="Edit"
onPress={() => { handleViewEditKomentar() }}
/>
<MenuItemRow
icon={<MaterialIcons name="delete" color="black" size={25} />}
icon={<Ionicons name="trash-outline" color={colors.text} size={25} />}
title="Hapus"
onPress={() => {
AlertKonfirmasi({

View File

@@ -11,6 +11,7 @@ import Styles from "@/constants/Styles"
import { apiCreateDiscussion } from "@/lib/api"
import { setUpdateDiscussion } from "@/lib/discussionUpdate"
import { useAuthSession } from "@/providers/AuthProvider"
import { useTheme } from "@/providers/ThemeProvider"
import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons"
import * as DocumentPicker from "expo-document-picker"
import { router, Stack, useLocalSearchParams } from "expo-router"
@@ -21,6 +22,7 @@ import { useDispatch, useSelector } from "react-redux"
export default function CreateDiscussionDivision() {
const { colors } = useTheme();
const { id } = useLocalSearchParams<{ id: string }>()
const [desc, setDesc] = useState('')
const { token, decryptToken } = useAuthSession()
@@ -88,7 +90,7 @@ export default function CreateDiscussionDivision() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
@@ -127,19 +129,20 @@ export default function CreateDiscussionDivision() {
required
onChange={setDesc}
multiline
bg={colors.card}
/>
<ButtonSelect value="Upload File" onPress={pickDocumentAsync} />
{
fileForm.length > 0
&&
<View style={[Styles.borderAll, Styles.round10, Styles.p10, Styles.mb10]}>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, Styles.mb10, { borderColor: colors.background, backgroundColor: colors.card }]}>
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
{
fileForm.map((item, index) => (
<BorderBottomItem
key={index}
borderType={fileForm.length > 1 ? "bottom" : "none"}
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
titleWeight="normal"
onPress={() => { setIndexDelFile(index); setModalFile(true) }}
@@ -154,7 +157,7 @@ export default function CreateDiscussionDivision() {
<DrawerBottom animation="slide" isVisible={isModalFile} setVisible={setModalFile} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<Ionicons name="trash" color="black" size={25} />}
icon={<Ionicons name="trash-outline" color={colors.text} size={25} />}
title="Hapus"
onPress={() => { deleteFile(indexDelFile) }}
/>

View File

@@ -5,10 +5,12 @@ import InputSearch from "@/components/inputSearch";
import LabelStatus from "@/components/labelStatus";
import SkeletonContent from "@/components/skeletonContent";
import Text from "@/components/Text";
import WrapTab from "@/components/wrapTab";
import { ConstEnv } from "@/constants/ConstEnv";
import Styles from "@/constants/Styles";
import { apiGetDiscussion, apiGetDivisionOneFeature } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { AntDesign, Feather, Ionicons } from "@expo/vector-icons";
import { router, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
@@ -30,6 +32,7 @@ type Props = {
export default function DiscussionDivision() {
const { colors } = useTheme();
const { id, active } = useLocalSearchParams<{ id: string, active?: string }>()
const [data, setData] = useState<Props[]>([])
const { token, decryptToken } = useAuthSession()
@@ -128,26 +131,26 @@ export default function DiscussionDivision() {
})
return (
<View style={[Styles.p15, { flex: 1 }]}>
<View style={[Styles.p15, { flex: 1, backgroundColor: colors.background }]}>
{
((entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision) &&
<View>
<View style={[Styles.wrapBtnTab]}>
<WrapTab>
<ButtonTab
active={status == "false" ? "false" : "true"}
value="true"
onPress={() => { setStatus("true") }}
label="Aktif"
icon={<Feather name="check-circle" color={status == "false" ? 'black' : 'white'} size={20} />}
icon={<Feather name="check-circle" color={status == "false" ? colors.dimmed : 'white'} size={20} />}
n={2} />
<ButtonTab
active={status == "false" ? "false" : "true"}
value="false"
onPress={() => { setStatus("false") }}
label="Arsip"
icon={<AntDesign name="closecircleo" color={status == "true" ? 'black' : 'white'} size={20} />}
icon={<AntDesign name="closecircleo" color={status == "true" ? colors.dimmed : 'white'} size={20} />}
n={2} />
</View>
</WrapTab>
<InputSearch onChange={setSearch} />
</View>
}

View File

@@ -24,6 +24,7 @@ import {
} from "@/lib/api";
import { setUpdateDokumen } from "@/lib/dokumenUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import {
AntDesign,
MaterialCommunityIcons,
@@ -66,6 +67,7 @@ type PropsPath = {
};
export default function DocumentDivision() {
const { colors } = useTheme();
const [loadingRename, setLoadingRename] = useState(false)
const [isShare, setShare] = useState(false)
const { token, decryptToken } = useAuthSession()
@@ -334,7 +336,7 @@ export default function DocumentDivision() {
}, [path]);
return (
<SafeAreaView style={{ flex: 1 }}>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () =>
@@ -380,7 +382,7 @@ export default function DocumentDivision() {
showBack={(selectedFiles.length > 0 || dariSelectAll) ? false : true}
left={
<ButtonHeader
item={<MaterialIcons name="close" size={20} color="white" />}
item={<MaterialIcons name="close" size={25} color="white" />}
onPress={() => {
handleBatal();
}}
@@ -393,7 +395,7 @@ export default function DocumentDivision() {
selectedFiles.length > 0 || dariSelectAll ? (
<ButtonHeader
item={
<MaterialIcons name="checklist-rtl" size={20} color="white" />
<MaterialIcons name="checklist-rtl" size={25} color="white" />
}
onPress={() => {
handleSelectAll();
@@ -427,9 +429,9 @@ export default function DocumentDivision() {
}}
>
{item.id != "home" && (
<AntDesign name="right" style={[Styles.mh05, Styles.mt02]} color="black" />
<AntDesign name="right" style={[Styles.mh05, Styles.mt02]} color={colors.text} />
)}
<Text> {item.name} </Text>
<Text style={{ color: colors.text }}> {item.name} </Text>
</Pressable>
))
}
@@ -493,7 +495,7 @@ export default function DocumentDivision() {
</View>
</ScrollView>
{(selectedFiles.length > 0 || dariSelectAll) && (
<View style={[ColorsStatus.primary, Styles.bottomMenuSelectDocument]}>
<View style={[Styles.bottomMenuSelectDocument, { backgroundColor: colors.header }]}>
<View style={[Styles.rowItemsCenter, { justifyContent: "center" }]}>
<MenuItemRow
icon={

View File

@@ -9,6 +9,7 @@ import Styles from "@/constants/Styles";
import { apiAddFileTask, apiCheckFileTask } from "@/lib/api";
import { setUpdateTask } from "@/lib/taskUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons";
import * as DocumentPicker from "expo-document-picker";
import { router, Stack, useLocalSearchParams } from "expo-router";
@@ -23,6 +24,7 @@ import Toast from "react-native-toast-message";
import { useDispatch, useSelector } from "react-redux";
export default function TaskDivisionAddFile() {
const { colors } = useTheme();
const { id, detail } = useLocalSearchParams<{ id: string; detail: string }>();
const [fileForm, setFileForm] = useState<any[]>([]);
const [listFile, setListFile] = useState<any[]>([]);
@@ -127,7 +129,7 @@ export default function TaskDivisionAddFile() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -169,13 +171,13 @@ export default function TaskDivisionAddFile() {
listFile.length > 0 && (
<View style={[Styles.mb15]}>
<Text style={[Styles.textDefaultSemiBold, Styles.mv05]}>File</Text>
<View style={[Styles.wrapPaper]}>
<View style={[Styles.wrapPaper, { backgroundColor: colors.card, borderColor: colors.background }]}>
{
listFile.map((item, index) => (
<BorderBottomItem
key={index}
borderType="all"
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item}
titleWeight="normal"
onPress={() => { setIndexDelFile(index); setModal(true) }}
@@ -197,7 +199,7 @@ export default function TaskDivisionAddFile() {
<DrawerBottom animation="slide" isVisible={isModal} setVisible={setModal} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<Ionicons name="trash" color="black" size={25} />}
icon={<Ionicons name="trash-outline" color={colors.text} size={25} />}
title="Hapus"
onPress={() => { deleteFile(indexDelFile) }}
/>

View File

@@ -9,6 +9,7 @@ import Styles from "@/constants/Styles";
import { apiAddMemberTask, apiGetDivisionMember, apiGetTaskOne } from "@/lib/api";
import { setUpdateTask } from "@/lib/taskUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { AntDesign } from "@expo/vector-icons";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
@@ -23,6 +24,7 @@ type Props = {
}
export default function AddMemberTask() {
const { colors } = useTheme();
const dispatch = useDispatch()
const update = useSelector((state: any) => state.projectUpdate)
const { token, decryptToken } = useAuthSession()
@@ -127,7 +129,7 @@ export default function AddMemberTask() {
)
}}
/>
<View style={[Styles.p15, { flex: 1 }]}>
<View style={[Styles.p15, { flex: 1, backgroundColor: colors.background }]}>
<InputSearch onChange={(val) => setSearch(val)} value={search} />
{
@@ -177,7 +179,7 @@ export default function AddMemberTask() {
</View>
</View>
{
selectMember.some((i: any) => i.idUser == item.idUser) && <AntDesign name="check" size={20} color={'black'} />
selectMember.some((i: any) => i.idUser == item.idUser) && <AntDesign name="check" size={20} color={colors.text} />
}
</Pressable>
)

View File

@@ -9,6 +9,7 @@ import { formatDateOnly } from "@/lib/fun_formatDateOnly";
import { getDatesInRange } from "@/lib/fun_getDatesInRange";
import { setUpdateTask } from "@/lib/taskUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { useHeaderHeight } from '@react-navigation/elements';
import { router, Stack, useLocalSearchParams } from "expo-router";
import 'intl';
@@ -25,6 +26,7 @@ import DateTimePicker, { DateType } from "react-native-ui-datepicker";
import { useDispatch, useSelector } from "react-redux";
export default function TaskDivisionAddTask() {
const { colors } = useTheme();
const { token, decryptToken } = useAuthSession();
const dispatch = useDispatch();
const update = useSelector((state: any) => state.taskUpdate);
@@ -138,7 +140,7 @@ export default function TaskDivisionAddTask() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -183,7 +185,7 @@ export default function TaskDivisionAddTask() {
>
<ScrollView>
<View style={[Styles.p15, Styles.mb100]}>
<View style={[Styles.wrapPaper, Styles.p10]}>
<View style={[Styles.wrapPaper, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
<DateTimePicker
mode="range"
startDate={range.startDate}
@@ -193,13 +195,13 @@ export default function TaskDivisionAddTask() {
selected: Styles.selectedDate,
selected_label: Styles.cWhite,
range_fill: Styles.selectRangeDate,
month_label: Styles.cBlack,
month_selector_label: Styles.cBlack,
year_label: Styles.cBlack,
year_selector_label: Styles.cBlack,
day_label: Styles.cBlack,
time_label: Styles.cBlack,
weekday_label: Styles.cBlack,
month_label: { color: colors.text },
month_selector_label: { color: colors.text },
year_label: { color: colors.text },
year_selector_label: { color: colors.text },
day_label: { color: colors.text },
time_label: { color: colors.text },
weekday_label: { color: colors.text },
}}
/>
</View>
@@ -209,7 +211,7 @@ export default function TaskDivisionAddTask() {
<Text style={[Styles.mb05]}>
Tanggal Mulai <Text style={Styles.cError}>*</Text>
</Text>
<View style={[Styles.wrapPaper, Styles.p10]}>
<View style={[Styles.wrapPaper, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
<Text style={{ textAlign: "center" }}>{from}</Text>
</View>
</View>
@@ -217,7 +219,7 @@ export default function TaskDivisionAddTask() {
<Text style={[Styles.mb05]}>
Tanggal Berakhir <Text style={Styles.cError}>*</Text>
</Text>
<View style={[Styles.wrapPaper, Styles.p10]}>
<View style={[Styles.wrapPaper, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
<Text style={{ textAlign: "center" }}>{to}</Text>
</View>
</View>
@@ -238,7 +240,7 @@ export default function TaskDivisionAddTask() {
type="default"
placeholder="Judul Tugas"
required
bg="white"
bg={colors.card}
value={title}
error={error.title}
errorText="Judul tidak boleh kosong"

View File

@@ -5,6 +5,7 @@ import Styles from "@/constants/Styles";
import { apiCancelTask } from "@/lib/api";
import { setUpdateTask } from "@/lib/taskUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
import { SafeAreaView, ScrollView, View } from "react-native";
@@ -12,6 +13,7 @@ import Toast from "react-native-toast-message";
import { useDispatch, useSelector } from "react-redux";
export default function TaskDivisionCancel() {
const { colors } = useTheme();
const { id, detail } = useLocalSearchParams<{ id: string; detail: string }>();
const { token, decryptToken } = useAuthSession();
const dispatch = useDispatch();
@@ -69,7 +71,7 @@ export default function TaskDivisionCancel() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -115,7 +117,7 @@ export default function TaskDivisionCancel() {
type="default"
placeholder="Alasan Pembatalan"
required
bg="white"
bg={colors.card}
error={error}
errorText="Alasan pembatalan harus diisi"
onChange={(val) => onValidation(val)}

View File

@@ -5,6 +5,7 @@ import Styles from "@/constants/Styles";
import { apiEditTask, apiGetTaskOne } from "@/lib/api";
import { setUpdateTask } from "@/lib/taskUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
import { SafeAreaView, ScrollView, View } from "react-native";
@@ -12,6 +13,7 @@ import Toast from "react-native-toast-message";
import { useDispatch, useSelector } from "react-redux";
export default function TaskDivisionEdit() {
const { colors } = useTheme();
const { id, detail } = useLocalSearchParams<{ id: string; detail: string }>();
const { token, decryptToken } = useAuthSession();
const [judul, setJudul] = useState("");
@@ -87,7 +89,7 @@ export default function TaskDivisionEdit() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -128,7 +130,7 @@ export default function TaskDivisionEdit() {
type="default"
placeholder="Judul Kegiatan"
required
bg="white"
bg={colors.card}
value={judul}
onChange={(val) => { onValidation(val) }}
error={error}

View File

@@ -10,6 +10,7 @@ import SectionTanggalTugasTask from "@/components/task/sectionTanggalTugasTask";
import Styles from "@/constants/Styles";
import { apiGetDivisionOneFeature, apiGetTaskOne } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
import { RefreshControl, SafeAreaView, ScrollView, View } from "react-native";
@@ -25,6 +26,7 @@ type Props = {
}
export default function DetailTaskDivision() {
const { colors } = useTheme();
const { id, detail } = useLocalSearchParams<{ id: string, detail: string }>();
const { token, decryptToken } = useAuthSession()
const [data, setData] = useState<Props>()
@@ -97,7 +99,7 @@ export default function DetailTaskDivision() {
};
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,

View File

@@ -5,6 +5,7 @@ import Styles from "@/constants/Styles";
import { apiGetTaskOne, apiReportTask } from "@/lib/api";
import { setUpdateTask } from "@/lib/taskUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
import { SafeAreaView, ScrollView, View } from "react-native";
@@ -12,6 +13,7 @@ import Toast from "react-native-toast-message";
import { useDispatch, useSelector } from "react-redux";
export default function TaskDivisionReport() {
const { colors } = useTheme();
const { id, detail } = useLocalSearchParams<{ id: string; detail: string }>();
const { token, decryptToken } = useAuthSession();
const [laporan, setLaporan] = useState("");
@@ -87,7 +89,7 @@ export default function TaskDivisionReport() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -128,7 +130,7 @@ export default function TaskDivisionReport() {
type="default"
placeholder="Laporan Kegiatan"
required
bg="white"
bg={colors.card}
value={laporan}
onChange={(val) => { onValidation(val) }}
error={error}

View File

@@ -16,6 +16,7 @@ import { setMemberChoose } from "@/lib/memberChoose";
import { setTaskCreate } from "@/lib/taskCreate";
import { setUpdateTask } from "@/lib/taskUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons";
import * as DocumentPicker from "expo-document-picker";
import { router, Stack, useLocalSearchParams } from "expo-router";
@@ -26,6 +27,7 @@ import { useDispatch, useSelector } from "react-redux";
export default function CreateTaskDivision() {
const { colors } = useTheme();
const { id } = useLocalSearchParams();
const { token, decryptToken } = useAuthSession();
const dispatch = useDispatch();
@@ -113,7 +115,7 @@ export default function CreateTaskDivision() {
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -161,6 +163,7 @@ export default function CreateTaskDivision() {
val == "" || val == "null" ? setError(true) : setError(false);
}}
error={error}
bg={colors.card}
errorText="Judul Tugas tidak boleh kosong"
/>
<ButtonSelect value="Tambah Tanggal & Tugas" onPress={() => { router.push(`/division/${id}/task/create/task`); }} />
@@ -171,13 +174,13 @@ export default function CreateTaskDivision() {
fileForm.length > 0 && (
<View style={[Styles.mb15]}>
<Text style={[Styles.textDefaultSemiBold, Styles.mv05]}>File</Text>
<View style={[Styles.wrapPaper]}>
<View style={[Styles.wrapPaper, { backgroundColor: colors.card, borderColor: colors.background }]}>
{
fileForm.map((item, index) => (
<BorderBottomItem
key={index}
borderType="all"
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
titleWeight="normal"
onPress={() => { setIndexDelFile(index); setModal(true) }}
@@ -195,7 +198,7 @@ export default function CreateTaskDivision() {
<Text>Total {entitiesMember.length} Anggota</Text>
</View>
<View style={[Styles.borderAll, Styles.round10, Styles.p10]}>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
{entitiesMember.map(
(item: { img: any; name: any }, index: any) => {
return (
@@ -223,7 +226,7 @@ export default function CreateTaskDivision() {
<DrawerBottom animation="slide" isVisible={isModal} setVisible={setModal} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<Ionicons name="trash" color="black" size={25} />}
icon={<Ionicons name="trash-outline" color={colors.text} size={25} />}
title="Hapus"
onPress={() => { deleteFile(indexDelFile) }}
/>

View File

@@ -9,6 +9,7 @@ import Styles from "@/constants/Styles";
import { apiGetDivisionMember } from "@/lib/api";
import { setMemberChoose } from "@/lib/memberChoose";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { AntDesign } from "@expo/vector-icons";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
@@ -23,6 +24,7 @@ type Props = {
}
export default function AddMemberCreateTask() {
const { colors } = useTheme();
const dispatch = useDispatch()
const { token, decryptToken } = useAuthSession()
const { id } = useLocalSearchParams<{ id: string, detail: string }>()
@@ -97,7 +99,7 @@ export default function AddMemberCreateTask() {
)
}}
/>
<View style={[Styles.p15, { flex: 1 }]}>
<View style={[Styles.p15, { flex: 1, backgroundColor: colors.background }]}>
<InputSearch onChange={(val) => setSearch(val)} value={search} />
{
@@ -143,7 +145,7 @@ export default function AddMemberCreateTask() {
</View>
</View>
{
selectMember.some((i: any) => i.idUser == item.idUser) && <AntDesign name="check" size={20} color={'black'} />
selectMember.some((i: any) => i.idUser == item.idUser) && <AntDesign name="check" size={20} color={colors.text} />
}
</Pressable>
)

View File

@@ -1,5 +1,6 @@
import AppHeader from "@/components/AppHeader";
import ButtonSaveHeader from "@/components/buttonSaveHeader";
import { useTheme } from "@/providers/ThemeProvider";
import { InputForm } from "@/components/inputForm";
import ModalAddDetailTugasTask from "@/components/task/modalAddDetailTugasTask";
import Text from "@/components/Text";
@@ -27,6 +28,7 @@ import DateTimePicker, {
import { useDispatch, useSelector } from "react-redux";
export default function CreateTaskAddTugas() {
const { colors } = useTheme();
const headerHeight = useHeaderHeight();
const dispatch = useDispatch()
const [disable, setDisable] = useState(true);
@@ -118,7 +120,7 @@ export default function CreateTaskAddTugas() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -158,7 +160,7 @@ export default function CreateTaskAddTugas() {
>
<ScrollView>
<View style={[Styles.p15, Styles.mb100]}>
<View style={[Styles.wrapPaper, Styles.p10]}>
<View style={[Styles.wrapPaper, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
<DateTimePicker
mode="range"
startDate={range.startDate}
@@ -168,13 +170,13 @@ export default function CreateTaskAddTugas() {
selected: Styles.selectedDate,
selected_label: Styles.cWhite,
range_fill: Styles.selectRangeDate,
month_label: Styles.cBlack,
month_selector_label: Styles.cBlack,
year_label: Styles.cBlack,
year_selector_label: Styles.cBlack,
day_label: Styles.cBlack,
time_label: Styles.cBlack,
weekday_label: Styles.cBlack,
month_label: { color: colors.text },
month_selector_label: { color: colors.text },
year_label: { color: colors.text },
year_selector_label: { color: colors.text },
day_label: { color: colors.text },
time_label: { color: colors.text },
weekday_label: { color: colors.text },
}}
/>
</View>
@@ -184,7 +186,7 @@ export default function CreateTaskAddTugas() {
<Text style={[Styles.mb05]}>
Tanggal Mulai <Text style={Styles.cError}>*</Text>
</Text>
<View style={[Styles.wrapPaper, Styles.p10]}>
<View style={[Styles.wrapPaper, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
<Text style={{ textAlign: "center" }}>{from}</Text>
</View>
</View>
@@ -192,7 +194,7 @@ export default function CreateTaskAddTugas() {
<Text style={[Styles.mb05]}>
Tanggal Berakhir <Text style={Styles.cError}>*</Text>
</Text>
<View style={[Styles.wrapPaper, Styles.p10]}>
<View style={[Styles.wrapPaper, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
<Text style={{ textAlign: "center" }}>{to}</Text>
</View>
</View>
@@ -213,7 +215,7 @@ export default function CreateTaskAddTugas() {
type="default"
placeholder="Judul Tugas"
required
bg="white"
bg={colors.card}
value={title}
error={error.title}
errorText="Judul tidak boleh kosong"

View File

@@ -11,6 +11,7 @@ import { ColorsStatus } from "@/constants/ColorsStatus";
import Styles from "@/constants/Styles";
import { apiGetTask } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import {
AntDesign,
Ionicons,
@@ -31,7 +32,8 @@ type Props = {
};
export default function ListTask() {
const { id, status } = useLocalSearchParams<{ id: string; status: string }>()
const { colors } = useTheme()
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 +45,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 +59,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) {
@@ -104,7 +112,7 @@ export default function ListTask() {
})
return (
<View style={[Styles.p15, { flex: 1 }]}>
<View style={[Styles.p15, { flex: 1, backgroundColor: colors.background }]}>
<View>
<ScrollView horizontal style={[Styles.mb10]} showsHorizontalScrollIndicator={false}>
<ButtonTab
@@ -115,7 +123,7 @@ export default function ListTask() {
icon={
<MaterialCommunityIcons
name="clock-alert-outline"
color={statusFix == "0" ? "white" : "black"}
color={statusFix == "0" ? "white" : colors.dimmed}
size={20}
/>
}
@@ -129,7 +137,7 @@ export default function ListTask() {
icon={
<MaterialCommunityIcons
name="progress-check"
color={statusFix == "1" ? "white" : "black"}
color={statusFix == "1" ? "white" : colors.dimmed}
size={20}
/>
}
@@ -143,7 +151,7 @@ export default function ListTask() {
icon={
<Ionicons
name="checkmark-done-circle-outline"
color={statusFix == "2" ? "white" : "black"}
color={statusFix == "2" ? "white" : colors.dimmed}
size={20}
/>
}
@@ -157,7 +165,7 @@ export default function ListTask() {
icon={
<AntDesign
name="closecircleo"
color={statusFix == "3" ? "white" : "black"}
color={statusFix == "3" ? "white" : colors.dimmed}
size={20}
/>
}
@@ -173,13 +181,19 @@ export default function ListTask() {
>
<MaterialCommunityIcons
name={isList ? "format-list-bulleted" : "view-grid"}
color={"black"}
color={colors.text}
size={30}
/>
</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 ?

View File

@@ -4,6 +4,7 @@ import { InputForm } from "@/components/inputForm";
import ModalAddDetailTugasTask from "@/components/task/modalAddDetailTugasTask";
import Text from "@/components/Text";
import Styles from "@/constants/Styles";
import { useTheme } from "@/providers/ThemeProvider";
import { apiEditTaskTugas, apiGetTaskTugas } from "@/lib/api";
import { formatDateOnly } from "@/lib/fun_formatDateOnly";
import { getDatesInRange } from "@/lib/fun_getDatesInRange";
@@ -28,6 +29,7 @@ import DateTimePicker, { DateType } from "react-native-ui-datepicker";
import { useDispatch, useSelector } from "react-redux";
export default function UpdateProjectTaskDivision() {
const { colors } = useTheme();
const headerHeight = useHeaderHeight();
const { detail } = useLocalSearchParams<{ detail: string }>();
const dispatch = useDispatch();
@@ -186,7 +188,7 @@ export default function UpdateProjectTaskDivision() {
}, [range])
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -231,7 +233,7 @@ export default function UpdateProjectTaskDivision() {
>
<ScrollView>
<View style={[Styles.p15, Styles.mb100]}>
<View style={[Styles.wrapPaper, Styles.p10]}>
<View style={[Styles.wrapPaper, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
{!loading && (
<DateTimePicker
mode="range"
@@ -244,13 +246,13 @@ export default function UpdateProjectTaskDivision() {
selected: Styles.selectedDate,
selected_label: Styles.cWhite,
range_fill: Styles.selectRangeDate,
month_label: Styles.cBlack,
month_selector_label: Styles.cBlack,
year_label: Styles.cBlack,
year_selector_label: Styles.cBlack,
day_label: Styles.cBlack,
time_label: Styles.cBlack,
weekday_label: Styles.cBlack,
month_label: { color: colors.text },
month_selector_label: { color: colors.text },
year_label: { color: colors.text },
year_selector_label: { color: colors.text },
day_label: { color: colors.text },
time_label: { color: colors.text },
weekday_label: { color: colors.text },
}}
/>
)}
@@ -261,7 +263,7 @@ export default function UpdateProjectTaskDivision() {
<Text style={[Styles.mb05]}>
Tanggal Mulai <Text style={Styles.cError}>*</Text>
</Text>
<View style={[Styles.wrapPaper, Styles.p10]}>
<View style={[Styles.wrapPaper, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
<Text style={{ textAlign: "center" }}>{from}</Text>
</View>
</View>
@@ -269,7 +271,7 @@ export default function UpdateProjectTaskDivision() {
<Text style={[Styles.mb05]}>
Tanggal Berakhir <Text style={Styles.cError}>*</Text>
</Text>
<View style={[Styles.wrapPaper, Styles.p10]}>
<View style={[Styles.wrapPaper, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
<Text style={{ textAlign: "center" }}>{to}</Text>
</View>
</View>
@@ -292,7 +294,7 @@ export default function UpdateProjectTaskDivision() {
type="default"
placeholder="Judul Tugas"
required
bg="white"
bg={colors.card}
value={title}
error={error.title}
errorText="Judul tidak boleh kosong"

View File

@@ -8,6 +8,7 @@ import { ConstEnv } from "@/constants/ConstEnv";
import Styles from "@/constants/Styles";
import { apiAddMemberDivision, apiGetDivisionOneDetail, apiGetUser } from "@/lib/api";
import { setUpdateDivision } from "@/lib/divisionUpdate";
import { useTheme } from "@/providers/ThemeProvider";
import { useAuthSession } from "@/providers/AuthProvider";
import { AntDesign } from "@expo/vector-icons";
import { router, Stack, useLocalSearchParams } from "expo-router";
@@ -23,6 +24,7 @@ type Props = {
}
export default function AddMemberDivision() {
const { colors } = useTheme();
const { token, decryptToken } = useAuthSession()
const { id } = useLocalSearchParams<{ id: string }>()
const [dataOld, setDataOld] = useState<Props[]>([])
@@ -130,7 +132,7 @@ export default function AddMemberDivision() {
)
}}
/>
<View style={[Styles.p15, { flex: 1 }]}>
<View style={[Styles.p15, { flex: 1, backgroundColor: colors.background }]}>
<InputSearch onChange={(val) => handleSearch(val)} value={search} />
{
@@ -180,7 +182,7 @@ export default function AddMemberDivision() {
</View>
</View>
{
selectMember.some((i: any) => i.idUser == item.id) && <AntDesign name="check" size={20} color={'black'} />
selectMember.some((i: any) => i.idUser == item.id) && <AntDesign name="check" size={20} color={colors.text} />
}
</Pressable>
)

View File

@@ -5,6 +5,7 @@ import Styles from "@/constants/Styles";
import { apiEditDivision, apiGetDivisionOneDetail } from "@/lib/api";
import { setUpdateDivision } from "@/lib/divisionUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
import { SafeAreaView, ScrollView, View } from "react-native";
@@ -12,6 +13,7 @@ import Toast from "react-native-toast-message";
import { useDispatch, useSelector } from "react-redux";
export default function EditDivision() {
const { colors } = useTheme();
const dispatch = useDispatch()
const update = useSelector((state: any) => state.divisionUpdate)
const { token, decryptToken } = useAuthSession();
@@ -63,7 +65,7 @@ export default function EditDivision() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -98,7 +100,7 @@ export default function EditDivision() {
)
}}
/>
<ScrollView>
<ScrollView style={{ backgroundColor: colors.background }}>
<View style={[Styles.p15, Styles.mb100]}>
<InputForm
label="Nama Divisi"

View File

@@ -8,6 +8,7 @@ import CaraouselHome from "@/components/home/carouselHome"
import Styles from "@/constants/Styles"
import { apiGetDivisionOneDetail } from "@/lib/api"
import { useAuthSession } from "@/providers/AuthProvider"
import { useTheme } from "@/providers/ThemeProvider"
import { router, Stack, useLocalSearchParams } from "expo-router"
import { useEffect, useState } from "react"
import { RefreshControl, SafeAreaView, ScrollView, View } from "react-native"
@@ -22,6 +23,7 @@ type Props = {
}
export default function DetailDivisionFitur() {
const { colors } = useTheme()
const { token, decryptToken } = useAuthSession()
const { id } = useLocalSearchParams<{ id: string }>()
const [data, setData] = useState<Props>()
@@ -54,7 +56,7 @@ export default function DetailDivisionFitur() {
};
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,

View File

@@ -13,6 +13,7 @@ import { ConstEnv } from "@/constants/ConstEnv"
import Styles from "@/constants/Styles"
import { apiDeleteMemberDivision, apiGetDivisionOneDetail, apiGetDivisionOneFeature, apiUpdateStatusAdminDivision } from "@/lib/api"
import { useAuthSession } from "@/providers/AuthProvider"
import { useTheme } from "@/providers/ThemeProvider"
import { Feather, MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons"
import { router, Stack, useLocalSearchParams } from "expo-router"
import { useEffect, useState } from "react"
@@ -39,6 +40,7 @@ type PropsMember = {
}
export default function InformationDivision() {
const { colors } = useTheme()
const [refreshing, setRefreshing] = useState(false)
const entityUser = useSelector((state: any) => state.user)
const { id } = useLocalSearchParams<{ id: string }>()
@@ -161,7 +163,7 @@ export default function InformationDivision() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
@@ -187,7 +189,7 @@ export default function InformationDivision() {
onRefresh={handleRefresh}
/>
}
style={[Styles.h100]}
style={[Styles.h100, { backgroundColor: colors.background }]}
>
<View style={[Styles.p15]}>
{
@@ -197,7 +199,7 @@ export default function InformationDivision() {
}
<View style={[Styles.mb15]}>
<Text style={[Styles.textDefaultSemiBold, Styles.mb05]}>Deskripsi Divisi</Text>
<View style={[Styles.wrapPaper]}>
<View style={[Styles.wrapPaper, Styles.noShadow, { backgroundColor: colors.card, borderWidth: 1, borderColor: colors.icon + '20' }]}>
{loading ?
arrSkeleton.map((item, index) => {
return (
@@ -211,7 +213,7 @@ export default function InformationDivision() {
</View>
<View style={[Styles.mb15]}>
<Text style={[Styles.textDefault, Styles.mv05]}>{dataMember.length} Anggota</Text>
<View style={[Styles.wrapPaper]}>
<View style={[Styles.wrapPaper, Styles.noShadow, { backgroundColor: colors.card, borderWidth: 1, borderColor: colors.icon + '20' }]}>
{
((entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision) &&
dataDetail?.isActive && (
@@ -219,8 +221,8 @@ export default function InformationDivision() {
onPress={() => { router.push(`/division/${id}/add-member`) }}
borderType="none"
icon={
<View style={[Styles.iconContent, ColorsStatus.gray]}>
<Feather name="user-plus" size={25} color={'#384288'} />
<View style={[Styles.iconContent]}>
<Feather name="user-plus" size={25} color={'black'} />
</View>
}
title="Tambah Anggota"
@@ -260,8 +262,8 @@ export default function InformationDivision() {
<View>
<Pressable style={[Styles.wrapItemBorderBottom]} onPress={() => { handleMemberAdmin() }}>
<View style={[Styles.rowItemsCenter]}>
<View style={[Styles.iconContent, ColorsStatus.info]}>
<MaterialIcons name="verified-user" size={25} color='#19345E' />
<View style={[Styles.iconContent]}>
<MaterialIcons name="verified-user" size={25} color={'black'} />
</View>
<View style={[Styles.rowSpaceBetween, { width: '88%' }]}>
<View style={[Styles.ml10]}>
@@ -274,7 +276,7 @@ export default function InformationDivision() {
<Pressable style={[Styles.wrapItemBorderBottom]} onPress={() => { handleMemberOut() }}>
<View style={[Styles.rowItemsCenter]}>
<View style={[Styles.iconContent, ColorsStatus.info]}>
<MaterialCommunityIcons name="close-circle" size={25} color='#19345E' />
<MaterialCommunityIcons name="close-circle" size={25} color={colors.primary} />
</View>
<View style={[Styles.rowSpaceBetween, { width: '88%' }]}>
<View style={[Styles.ml10]}>

View File

@@ -6,6 +6,7 @@ import { InputDate } from "@/components/inputDate"
import Styles from "@/constants/Styles"
import { apiGetDivisionReport } from "@/lib/api"
import { stringToDate } from "@/lib/fun_stringToDate"
import { useTheme } from "@/providers/ThemeProvider"
import { useAuthSession } from "@/providers/AuthProvider"
import dayjs from "dayjs"
import { router, Stack, useLocalSearchParams } from "expo-router"
@@ -14,6 +15,7 @@ import { SafeAreaView, ScrollView, View } from "react-native"
import Toast from "react-native-toast-message"
export default function ReportDivision() {
const { colors } = useTheme();
const { id } = useLocalSearchParams<{ id: string }>()
const { token, decryptToken } = useAuthSession();
const [showReport, setShowReport] = useState(false);
@@ -104,7 +106,7 @@ export default function ReportDivision() {
}, [showReport]);
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
@@ -119,7 +121,7 @@ export default function ReportDivision() {
)
}}
/>
<ScrollView>
<ScrollView style={{ backgroundColor: colors.background }}>
<View style={[Styles.p15, Styles.mb100]}>
<InputDate
onChange={(val) => validationForm("date", val)}

View File

@@ -8,6 +8,7 @@ import Styles from "@/constants/Styles";
import { apiCheckDivisionName } from "@/lib/api";
import { setFormCreateDivision } from "@/lib/divisionCreate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { router, Stack } from "expo-router";
import { useEffect, useState } from "react";
import { SafeAreaView, ScrollView, View } from "react-native";
@@ -15,6 +16,7 @@ import Toast from "react-native-toast-message";
import { useDispatch, useSelector } from "react-redux";
export default function CreateDivision() {
const { colors } = useTheme();
const { token, decryptToken } = useAuthSession()
const [isSelect, setSelect] = useState(false)
const [chooseGroup, setChooseGroup] = useState({ val: "", label: "" })
@@ -99,7 +101,7 @@ export default function CreateDivision() {
}, []);
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -131,7 +133,7 @@ export default function CreateDivision() {
/>
<ScrollView
showsVerticalScrollIndicator={false}
style={[Styles.h100]}
style={[Styles.h100, { backgroundColor: colors.background }]}
>
<View style={[Styles.p15]}>
{

View File

@@ -8,6 +8,7 @@ import { apiCreateDivision } from "@/lib/api";
import { setFormCreateDivision } from "@/lib/divisionCreate";
import { setUpdateDivision } from "@/lib/divisionUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { AntDesign } from "@expo/vector-icons";
import { StackActions, useNavigation } from "@react-navigation/native";
import { router, Stack, useLocalSearchParams } from "expo-router";
@@ -23,6 +24,7 @@ type Props = {
}
export default function CreateDivisionAddAdmin() {
const { colors } = useTheme();
const { token, decryptToken } = useAuthSession()
const navigation = useNavigation()
const { id } = useLocalSearchParams<{ id: string }>()
@@ -104,7 +106,7 @@ export default function CreateDivisionAddAdmin() {
)
}}
/>
<View style={[Styles.p15, { flex: 1 }]}>
<View style={[Styles.p15, { flex: 1, backgroundColor: colors.background }]}>
<ScrollView>
{
data.length > 0 ?
@@ -128,7 +130,7 @@ export default function CreateDivisionAddAdmin() {
</View>
</View>
{
selectMember.some((i: any) => i == item.idUser) && <AntDesign name="check" size={20} color={'black'} />
selectMember.some((i: any) => i == item.idUser) && <AntDesign name="check" size={20} color={colors.text} />
}
</Pressable>
)

View File

@@ -10,6 +10,7 @@ import { apiGetUser } from "@/lib/api";
import { setFormCreateDivision } from "@/lib/divisionCreate";
import { useAuthSession } from "@/providers/AuthProvider";
import { AntDesign } from "@expo/vector-icons";
import { useTheme } from "@/providers/ThemeProvider";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
import { Pressable, ScrollView, View } from "react-native";
@@ -22,6 +23,7 @@ type Props = {
}
export default function CreateDivisionAddMember() {
const { colors } = useTheme();
const { token, decryptToken } = useAuthSession()
const { id } = useLocalSearchParams<{ id: string }>()
const [dataOld, setDataOld] = useState<Props[]>([])
@@ -84,7 +86,7 @@ export default function CreateDivisionAddMember() {
)
}}
/>
<View style={[Styles.p15, { flex: 1 }]}>
<View style={[Styles.p15, { flex: 1, backgroundColor: colors.background }]}>
<InputSearch onChange={(val) => setSearch(val)} value={search} />
{
@@ -134,7 +136,7 @@ export default function CreateDivisionAddMember() {
</View>
</View>
{
selectMember.some((i: any) => i.idUser == item.id) && <AntDesign name="check" size={20} color={'black'} />
selectMember.some((i: any) => i.idUser == item.id) && <AntDesign name="check" size={20} color={colors.text} />
}
</Pressable>
)

View File

@@ -1,20 +1,21 @@
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";
import Text from "@/components/Text";
import { ColorsStatus } from "@/constants/ColorsStatus";
import WrapTab from "@/components/wrapTab";
import Styles from "@/constants/Styles";
import { apiGetDivision } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import {
AntDesign,
Feather,
Ionicons,
MaterialCommunityIcons,
MaterialIcons,
MaterialCommunityIcons
} from "@expo/vector-icons";
import { router, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
@@ -37,9 +38,11 @@ export default function ListDivision() {
const [isList, setList] = useState(false);
const entityUser = useSelector((state: any) => state.user)
const { token, decryptToken } = useAuthSession()
const { colors } = useTheme();
const [search, setSearch] = useState("")
const [nameGroup, setNameGroup] = useState("")
const [data, setData] = useState<Props[]>([])
// ... state same ...
const update = useSelector((state: any) => state.divisionUpdate)
const arrSkeleton = Array.from({ length: 3 }, (_, index) => index)
const [loading, setLoading] = useState(false)
@@ -113,11 +116,11 @@ export default function ListDivision() {
return (
<View style={[Styles.p15, { flex: 1 }]}>
<View style={[Styles.p15, { flex: 1, backgroundColor: colors.background }]}>
<View>
{
entityUser.role != "user" && entityUser.role != "coadmin" ?
<View style={[Styles.wrapBtnTab]}>
<WrapTab>
<ButtonTab
active={status == "false" ? "false" : "true"}
value="true"
@@ -126,7 +129,7 @@ export default function ListDivision() {
icon={
<Feather
name="check-circle"
color={status == "false" ? "black" : "white"}
color={status == "false" ? colors.dimmed : "white"}
size={20}
/>
}
@@ -140,15 +143,15 @@ export default function ListDivision() {
icon={
<AntDesign
name="closecircleo"
color={status == "true" ? "black" : "white"}
color={status == "true" ? colors.dimmed : "white"}
size={20}
/>
}
n={2}
/>
</View>
</WrapTab>
:
<View style={[Styles.wrapBtnTab]}>
<WrapTab>
<ButtonTab
active={category == "semua" ? "false" : "true"}
value="true"
@@ -157,7 +160,7 @@ export default function ListDivision() {
icon={
<Ionicons
name="file-tray-outline"
color={category == "semua" ? "black" : "white"}
color={category == "semua" ? colors.dimmed : "white"}
size={20}
/>
}
@@ -171,13 +174,13 @@ export default function ListDivision() {
icon={
<Ionicons
name="file-tray-stacked-outline"
color={category == "semua" ? "white" : "black"}
color={category == "semua" ? "white" : colors.dimmed}
size={20}
/>
}
n={2}
/>
</View>
</WrapTab>
}
<View style={[Styles.rowSpaceBetween, { alignItems: 'center' }]}>
@@ -189,14 +192,15 @@ export default function ListDivision() {
>
<MaterialCommunityIcons
name={isList ? "format-list-bulleted" : "view-grid"}
color={"black"}
color={colors.text}
size={30}
/>
</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>
@@ -230,9 +234,10 @@ export default function ListDivision() {
key={index}
onPress={() => { router.push(`/division/${item.id}`) }}
borderType="bottom"
bgColor="transparent"
icon={
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
<MaterialIcons name="group" size={25} color={"#384288"} />
<View style={[Styles.iconContent]}>
<Feather name="users" size={25} color={'black'} />
</View>
}
title={item.name}

View File

@@ -9,6 +9,7 @@ import Styles from "@/constants/Styles";
import { apiGetDivisionReport } from "@/lib/api";
import { stringToDate } from "@/lib/fun_stringToDate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import dayjs from "dayjs";
import { router, Stack } from "expo-router";
import { useEffect, useState } from "react";
@@ -16,6 +17,7 @@ import { SafeAreaView, ScrollView, View } from "react-native";
import Toast from "react-native-toast-message";
export default function Report() {
const { colors } = useTheme();
const { token, decryptToken } = useAuthSession();
const [chooseGroup, setChooseGroup] = useState({ val: "", label: "" });
const [showReport, setShowReport] = useState(false);
@@ -122,7 +124,7 @@ export default function Report() {
}, [showReport]);
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -144,11 +146,11 @@ export default function Report() {
/>
<ScrollView
showsVerticalScrollIndicator={false}
style={[Styles.h100]}
style={[Styles.h100, { backgroundColor: colors.background }]}
>
<View style={[Styles.p15, Styles.mb50]}>
<SelectForm
bg="white"
bg={colors.card}
label="Lembaga Desa"
placeholder="Pilih Lembaga Desa"
value={chooseGroup.label}

View File

@@ -10,6 +10,7 @@ import { apiEditProfile, apiGetProfile } from "@/lib/api";
import { setEntities } from "@/lib/entitiesSlice";
import { validateName } from "@/lib/fun_validateName";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import { useHeaderHeight } from "@react-navigation/elements";
import * as ImagePicker from "expo-image-picker";
@@ -43,9 +44,11 @@ type Props = {
export default function EditProfile() {
const headerHeight = useHeaderHeight()
const dispatch = useDispatch()
const { colors } = useTheme();
const entities = useSelector((state: any) => state.entities)
const { token, decryptToken } = useAuthSession()
const [errorImg, setErrorImg] = useState(false)
// ... keeping state same ...
const [selectedImage, setSelectedImage] = useState<string | undefined | { uri: string }>(undefined);
const [choosePosition, setChoosePosition] = useState({ val: entities.idPosition, label: entities.position });
const [chooseGender, setChooseGender] = useState({ val: entities.gender, label: entities.gender == "F" ? 'Perempuan' : 'Laki-laki' });
@@ -213,7 +216,7 @@ export default function EditProfile() {
};
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
headerLeft: () => (

View File

@@ -1,16 +1,18 @@
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";
import { useTheme } from "@/providers/ThemeProvider";
import { AntDesign, Entypo, Feather, Ionicons, MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons";
import { router, Stack } from "expo-router";
import { SafeAreaView, View } from "react-native";
import { useSelector } from "react-redux";
export default function Feature() {
const entityUser = useSelector((state: any) => state.user)
const { colors } = useTheme();
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
headerTitle: 'Fitur',
@@ -22,32 +24,26 @@ export default function Feature() {
/>
<View style={[Styles.p15]}>
<View style={[Styles.rowSpaceBetween, Styles.mb15]}>
<ButtonFiturMenu icon={<MaterialIcons name="group" size={35} color="black" />} text="Divisi" onPress={() => { router.push('/division?active=true') }} />
<ButtonFiturMenu icon={<AntDesign name="areachart" size={35} color="black" />} text="Kegiatan" onPress={() => { router.push('/project?status=0') }} />
<ButtonFiturMenu icon={<MaterialIcons name="campaign" size={35} color="black" />} text="Pengumuman" onPress={() => { router.push('/announcement') }} />
<ButtonFiturMenu icon={<Ionicons name="chatbubbles-sharp" size={35} color="black" />} text="Diskusi" onPress={() => { router.push('/discussion?active=true') }} />
<ButtonFiturMenu icon={<Feather name="users" size={30} color={colors.icon} />} text="Divisi" onPress={() => { router.push('/division?active=true') }} />
<ButtonFiturMenu icon={<Feather name="bar-chart" size={30} color={colors.icon} />} text="Kegiatan" onPress={() => { router.push('/project?status=0') }} />
<ButtonFiturMenu icon={<Ionicons name="megaphone-outline" size={30} color={colors.icon} />} text="Pengumuman" onPress={() => { router.push('/announcement') }} />
<ButtonFiturMenu icon={<Ionicons name="chatbubbles-outline" size={30} color={colors.icon} />} text="Diskusi" onPress={() => { router.push('/discussion?active=true') }} />
</View>
<View style={[Styles.rowSpaceBetween, Styles.mb15, (entityUser.role == 'cosupadmin' ? Styles.w70 : entityUser.role == 'supadmin' || entityUser.role == 'developer' ? Styles.w100 : Styles.w40)]}>
<ButtonFiturMenu icon={<MaterialIcons name="groups" size={35} color="black" />} text="Anggota" onPress={() => { router.push('/member') }} />
<ButtonFiturMenu icon={<MaterialCommunityIcons name="account-tie" size={35} color="black" />} text="Jabatan" onPress={() => { router.push('/position') }} />
<ButtonFiturMenu icon={<MaterialCommunityIcons name="account-group-outline" size={30} color={colors.icon} />} text="Anggota" onPress={() => { router.push('/member') }} />
<ButtonFiturMenu icon={<MaterialCommunityIcons name="account-tie-outline" size={30} color={colors.icon} />} text="Jabatan" onPress={() => { router.push('/position') }} />
{
entityUser.role == "cosupadmin" && <ButtonFiturMenu icon={<Entypo name="image-inverted" size={35} color="black" />} text="Banner" onPress={() => { router.push('/banner') }} />
entityUser.role == "cosupadmin" && <ButtonFiturMenu icon={<Ionicons name="images-outline" size={30} color={colors.icon} />} text="Banner" onPress={() => { router.push('/banner') }} />
}
{
(entityUser.role == "supadmin" || entityUser.role == "developer") &&
<>
<ButtonFiturMenu icon={<AntDesign name="tags" size={35} color="black" />} text="Lembaga Desa" onPress={() => { router.push('/group') }} />
{/* <ButtonFiturMenu icon={<Ionicons name="color-palette-sharp" size={35} color="black" />} text="Tema" onPress={() => { }} /> */}
<ButtonFiturMenu icon={<Entypo name="image-inverted" size={35} color="black" />} text="Banner" onPress={() => { router.push('/banner') }} />
<ButtonFiturMenu icon={<Ionicons name="bookmarks-outline" size={30} color={colors.icon} />} text="Lembaga Desa" onPress={() => { router.push('/group') }} />
{/* <ButtonFiturMenu icon={<Ionicons name="color-palette-sharp" size={30} color={colors.icon} />} text="Tema" onPress={() => { }} /> */}
<ButtonFiturMenu icon={<Ionicons name="images-outline" size={30} color={colors.icon} />} text="Banner" onPress={() => { router.push('/banner') }} />
</>
}
</View>
{/* {
(entityUser.role == "supadmin" || entityUser.role == "developer") &&
<View style={[Styles.rowSpaceBetween, Styles.mb15]}>
<ButtonFiturMenu icon={<Entypo name="image-inverted" size={35} color="black" />} text="Banner" onPress={() => { router.push('/banner') }} />
</View>
} */}
</View>
</SafeAreaView>
)

View File

@@ -8,12 +8,14 @@ import InputSearch from "@/components/inputSearch";
import MenuItemRow from "@/components/menuItemRow";
import SkeletonTwoItem from "@/components/skeletonTwoItem";
import Text from "@/components/Text";
import WrapTab from "@/components/wrapTab";
import { ColorsStatus } from "@/constants/ColorsStatus";
import Styles from "@/constants/Styles";
import { apiDeleteGroup, apiEditGroup, apiGetGroup } from "@/lib/api";
import { setUpdateGroup } from "@/lib/groupSlice";
import { useAuthSession } from "@/providers/AuthProvider";
import { AntDesign, Feather, MaterialCommunityIcons } from "@expo/vector-icons";
import { useTheme } from "@/providers/ThemeProvider";
import { AntDesign, Feather, Ionicons, MaterialCommunityIcons } from "@expo/vector-icons";
import { useEffect, useState } from "react";
import { RefreshControl, View, VirtualizedList } from "react-native";
import Toast from "react-native-toast-message";
@@ -27,6 +29,7 @@ type Props = {
export default function Index() {
const { token, decryptToken } = useAuthSession()
const { colors } = useTheme();
const [isModal, setModal] = useState(false)
const [isVisibleEdit, setVisibleEdit] = useState(false)
const [data, setData] = useState<Props[]>([])
@@ -127,24 +130,24 @@ export default function Index() {
return (
<View style={[Styles.p15, { flex: 1 }]}>
<View style={[Styles.p15, { flex: 1, backgroundColor: colors.background }]}>
<View style={[Styles.mb10]}>
<View style={[Styles.wrapBtnTab]}>
<WrapTab>
<ButtonTab
active={status == "false" ? "false" : "true"}
value="true"
onPress={() => { setStatus("true") }}
label="Aktif"
icon={<Feather name="check-circle" color={status == "true" ? 'white' : 'black'} size={20} />}
icon={<Feather name="check-circle" color={status == "true" ? 'white' : colors.dimmed} size={20} />}
n={2} />
<ButtonTab
active={status == "false" ? "false" : "true"}
value="false"
onPress={() => { setStatus("false") }}
label="Tidak Aktif"
icon={<AntDesign name="closecircleo" color={status == "false" ? 'white' : 'black'} size={20} />}
icon={<AntDesign name="closecircleo" color={status == "false" ? 'white' : colors.dimmed} size={20} />}
n={2} />
</View>
</WrapTab>
<InputSearch onChange={setSearch} />
</View>
<View style={[{ flex: 2 }, Styles.mt05]}>
@@ -173,8 +176,8 @@ export default function Index() {
}}
borderType="all"
icon={
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
<MaterialCommunityIcons name="office-building-outline" size={25} color={'#384288'} />
<View style={[Styles.iconContent]}>
<Ionicons name="bookmark-outline" size={25} color={'black'} />
</View>
}
title={item.name}
@@ -187,6 +190,7 @@ export default function Index() {
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
tintColor={colors.primary}
/>
}
/>
@@ -198,7 +202,7 @@ export default function Index() {
<DrawerBottom animation="slide" isVisible={isModal} setVisible={() => setModal(false)} title={titleChoose}>
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<MaterialCommunityIcons name="toggle-switch-off-outline" color="black" size={25} />}
icon={<MaterialCommunityIcons name="toggle-switch-off-outline" color={colors.text} size={25} />}
title={activeChoose ? "Non Aktifkan" : "Aktifkan"}
onPress={() => {
setModal(false)
@@ -210,7 +214,7 @@ export default function Index() {
}}
/>
<MenuItemRow
icon={<MaterialCommunityIcons name="pencil-outline" color="black" size={25} />}
icon={<MaterialCommunityIcons name="pencil-outline" color={colors.text} size={25} />}
title="Edit"
onPress={() => {
setModal(false)
@@ -232,6 +236,7 @@ export default function Index() {
label="Lembaga Desa"
value={titleChoose}
error={error.title}
bg={"transparent"}
errorText="Lembaga Desa tidak boleh kosong & minimal 3 karakter"
onChange={(val) => { validationForm(val, 'title') }} />
</View>

View File

@@ -1,10 +1,9 @@
import CaraouselHome from "@/components/home/carouselHome";
import CaraouselHome2 from "@/components/home/carouselHome2";
import ChartDokumenHome from "@/components/home/chartDokumenHome";
import ChartProgresHome from "@/components/home/chartProgresHome";
import DisccussionHome from "@/components/home/discussionHome";
import DivisionHome from "@/components/home/divisionHome";
import EventHome from "@/components/home/eventHome";
import FiturHome from "@/components/home/fiturHome";
import { HeaderRightHome } from "@/components/home/headerRightHome";
import ProjectHome from "@/components/home/projectHome";
import Text from "@/components/Text";
@@ -12,9 +11,11 @@ import Styles from "@/constants/Styles";
import { apiGetProfile } from "@/lib/api";
import { setEntities } from "@/lib/entitiesSlice";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { LinearGradient } from "expo-linear-gradient";
import { Stack } from "expo-router";
import { useEffect, useState } from "react";
import { Platform, RefreshControl, SafeAreaView, ScrollView, View } from "react-native";
import { Dimensions, Platform, RefreshControl, SafeAreaView, ScrollView, View } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { useDispatch, useSelector } from "react-redux";
@@ -23,6 +24,7 @@ export default function Home() {
const entities = useSelector((state: any) => state.entities)
const dispatch = useDispatch()
const { token, decryptToken, signOut } = useAuthSession()
const { colors } = useTheme();
const insets = useSafeAreaInsets()
const [refreshing, setRefreshing] = useState(false)
@@ -47,13 +49,13 @@ export default function Home() {
};
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
title: 'Home',
headerTitle: entities.village,
header: () => (
<View style={[Styles.rowItemsCenter, Styles.ph20, Platform.OS === 'ios' ? Styles.pb07 : Styles.pb13, { backgroundColor: '#19345E', paddingTop: Platform.OS === 'ios' ? insets.top : 10 }]}>
<View style={[Styles.rowItemsCenter, Styles.ph20, Platform.OS === 'ios' ? Styles.pb07 : Styles.pb13, { backgroundColor: colors.header, paddingTop: Platform.OS === 'ios' ? insets.top : 10 }]}>
<Text style={Styles.textHeaderHome}>{entities.village}</Text>
<HeaderRightHome />
</View>
@@ -65,19 +67,34 @@ export default function Home() {
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
tintColor={colors.primary}
/>
}
showsVerticalScrollIndicator={false}
style={{ backgroundColor: colors.background }}
>
<CaraouselHome refreshing={refreshing}/>
<View style={[Styles.ph15, Styles.mb100]}>
<FiturHome />
<ProjectHome refreshing={refreshing}/>
<DivisionHome refreshing={refreshing}/>
<ChartProgresHome refreshing={refreshing}/>
<ChartDokumenHome refreshing={refreshing}/>
<EventHome refreshing={refreshing}/>
<DisccussionHome refreshing={refreshing}/>
<LinearGradient
colors={[colors.header, colors.header, colors.header, colors.header, colors.homeGradient]}
style={{
position: 'absolute',
width: Dimensions.get('window').width * 1.5,
height: Dimensions.get('window').width * 1.5,
borderRadius: Dimensions.get('window').width * 0.5,
top: -Dimensions.get('window').width * 1, // Positioned to show the bottom part of the circle as an arc
left: -Dimensions.get('window').width * 0.25,
zIndex: -1,
}}
/>
{/* <CaraouselHome refreshing={refreshing} /> */}
<View style={[Styles.ph15]}>
<CaraouselHome2 refreshing={refreshing} />
{/* <FiturHome /> */}
<ProjectHome refreshing={refreshing} />
<DivisionHome refreshing={refreshing} />
<ChartProgresHome refreshing={refreshing} />
<ChartDokumenHome refreshing={refreshing} />
<EventHome refreshing={refreshing} />
<DisccussionHome refreshing={refreshing} />
</View>
</ScrollView>
</SafeAreaView>

View File

@@ -10,6 +10,8 @@ import { ConstEnv } from "@/constants/ConstEnv";
import { valueRoleUser } from "@/constants/RoleUser";
import Styles from "@/constants/Styles";
import { apiGetProfile } from "@/lib/api";
import { useTheme } from "@/providers/ThemeProvider";
import { LinearGradient } from "expo-linear-gradient";
import { router, Stack, useLocalSearchParams } from "expo-router";
import React, { useEffect, useState } from "react";
import { Pressable, RefreshControl, SafeAreaView, ScrollView, View } from "react-native";
@@ -33,6 +35,7 @@ type Props = {
export default function MemberDetail() {
const { id } = useLocalSearchParams<{ id: string }>();
const { colors } = useTheme();
const [data, setData] = useState<Props>()
const [errorImg, setErrorImg] = useState(false)
const entityUser = useSelector((state: any) => state.user)
@@ -74,13 +77,11 @@ export default function MemberDetail() {
};
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
headerTitle: 'Anggota',
headerTitleAlign: 'center',
// headerRight: () => (entityUser.role != "user") && isEdit ? <HeaderRightMemberDetail active={data?.isActive} id={id} /> : <></>,
header: () => (
<AppHeader title="Anggota"
showBack={true}
@@ -93,15 +94,19 @@ export default function MemberDetail() {
}}
/>
<ScrollView
style={[Styles.h100]}
style={[Styles.h100, { backgroundColor: colors.background }]}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
tintColor={colors.text}
/>
}
>
<View style={[Styles.wrapHeadViewMember]}>
<LinearGradient
colors={[colors.header, colors.homeGradient]}
style={[Styles.wrapHeadViewMember]}
>
{
loading ?
<>
@@ -119,10 +124,10 @@ export default function MemberDetail() {
</>
}
</View>
</LinearGradient>
<View style={[Styles.p15]}>
<View style={[Styles.rowSpaceBetween]}>
<Text style={[Styles.textDefaultSemiBold]}>Informasi</Text>
<Text style={[Styles.textDefaultSemiBold, { color: colors.text }]}>Informasi</Text>
<LabelStatus
size="small"
category={data?.isActive ? 'success' : 'error'}

View File

@@ -10,6 +10,7 @@ import { apiCreateUser } from "@/lib/api";
import { validateName } from "@/lib/fun_validateName";
import { setUpdateMember } from "@/lib/memberSlice";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import { useHeaderHeight } from '@react-navigation/elements';
import * as ImagePicker from "expo-image-picker";
@@ -32,6 +33,7 @@ export default function CreateMember() {
const dispatch = useDispatch()
const update = useSelector((state: any) => state.memberUpdate)
const { token, decryptToken } = useAuthSession()
const { colors } = useTheme();
const [valSelect, setValSelect] = useState<"group" | "position" | "role" | "gender">("group");
const [chooseGroup, setChooseGroup] = useState({ val: "", label: "" });
const [choosePosition, setChoosePosition] = useState({ val: "", label: "" });
@@ -206,25 +208,11 @@ export default function CreateMember() {
};
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
// <ButtonBackHeader
// onPress={() => {
// router.back();
// }}
// />
// ),
headerTitle: "Tambah Anggota",
headerTitleAlign: "center",
// headerRight: () => (
// <ButtonSaveHeader
// disable={disableBtn || loading}
// category="create"
// onPress={() => { handleCreate() }}
// />
// ),
header: () => (
<AppHeader title="Anggota"
showBack={true}
@@ -241,7 +229,7 @@ export default function CreateMember() {
}}
/>
<KeyboardAvoidingView
style={[Styles.h100]}
style={[Styles.h100, { backgroundColor: colors.background }]}
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
keyboardVerticalOffset={headerHeight}
>
@@ -271,6 +259,7 @@ export default function CreateMember() {
placeholder="Pilih Lembaga Desa"
value={chooseGroup.label}
required
bg={colors.card}
onPress={() => {
setValChoose(chooseGroup.val);
setValSelect("group");
@@ -285,6 +274,7 @@ export default function CreateMember() {
placeholder="Pilih Jabatan"
value={choosePosition.label}
required
bg={colors.card}
onPress={() => {
setValChoose(choosePosition.val);
setValSelect("position");
@@ -298,6 +288,7 @@ export default function CreateMember() {
placeholder="Pilih Role"
value={chooseRole.label}
required
bg={colors.card}
onPress={() => {
setValChoose(chooseRole.val);
setValSelect("role");
@@ -311,6 +302,7 @@ export default function CreateMember() {
type="numeric"
placeholder="NIK"
required
bg={colors.card}
error={error.nik}
errorText="NIK Harus 16 Karakter"
onChange={val => {
@@ -322,6 +314,7 @@ export default function CreateMember() {
type="default"
placeholder="Nama"
required
bg={colors.card}
error={error.name}
errorText="Nama harus 350 karakter (huruf, angka, spasi, dan simbol ringan (. , ' _ -))"
onChange={val => {
@@ -333,6 +326,7 @@ export default function CreateMember() {
type="default"
placeholder="Email"
required
bg={colors.card}
error={error.email}
errorText="Email tidak valid"
onChange={val => {
@@ -344,7 +338,8 @@ export default function CreateMember() {
type="numeric"
placeholder="8XX-XXX-XXX"
required
itemLeft={<Text style={[Platform.OS === 'ios' && Styles.mt02]}>+62</Text>}
bg={colors.card}
itemLeft={<Text style={[Platform.OS === 'ios' && Styles.mt02, { color: colors.text }]}>+62</Text>}
error={error.phone}
errorText="Nomor Telepon tidak valid"
onChange={val => {
@@ -356,6 +351,7 @@ export default function CreateMember() {
placeholder="Pilih Jenis Kelamin"
value={chooseGender.label}
required
bg={colors.card}
onPress={() => {
setValChoose(chooseGender.val);
setValSelect("gender");

View File

@@ -10,6 +10,7 @@ import { apiEditUser, apiGetProfile } from "@/lib/api";
import { validateName } from "@/lib/fun_validateName";
import { setUpdateMember } from "@/lib/memberSlice";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import { useHeaderHeight } from '@react-navigation/elements';
import * as ImagePicker from "expo-image-picker";
@@ -47,6 +48,7 @@ export default function EditMember() {
const update = useSelector((state: any) => state.memberUpdate)
const { token, decryptToken } = useAuthSession()
const { id } = useLocalSearchParams<{ id: string }>();
const { colors } = useTheme();
const [errorImg, setErrorImg] = useState(false)
const [selectedImage, setSelectedImage] = useState<string | undefined | { uri: string }>(undefined);
const [choosePosition, setChoosePosition] = useState({ val: "", label: "" });
@@ -236,27 +238,11 @@ export default function EditMember() {
};
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
// <ButtonBackHeader
// onPress={() => {
// router.back();
// }}
// />
// ),
headerTitle: "Edit Anggota",
headerTitleAlign: "center",
// headerRight: () => (
// <ButtonSaveHeader
// disable={disableBtn || loading}
// category="update"
// onPress={() => {
// handleEdit()
// }}
// />
// ),
header: () => (
<AppHeader
title="Edit Anggota"
@@ -277,7 +263,7 @@ export default function EditMember() {
/>
<KeyboardAvoidingView
style={[Styles.h100]}
style={[Styles.h100, { backgroundColor: colors.background }]}
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
keyboardVerticalOffset={headerHeight}
>
@@ -325,6 +311,7 @@ export default function EditMember() {
placeholder="Pilih Jabatan"
value={choosePosition.label}
required
bg={colors.card}
onPress={() => {
setValChoose(choosePosition.val);
setValSelect("position");
@@ -338,6 +325,7 @@ export default function EditMember() {
placeholder="Pilih Role"
value={chooseRole.label}
required
bg={colors.card}
onPress={() => {
setValChoose(chooseRole.val);
setValSelect("role");
@@ -352,6 +340,7 @@ export default function EditMember() {
placeholder="NIK"
required
value={data?.nik}
bg={colors.card}
error={error.nik}
errorText="NIK Harus 16 Karakter"
onChange={val => {
@@ -364,6 +353,7 @@ export default function EditMember() {
placeholder="Nama"
required
value={data?.name}
bg={colors.card}
error={error.name}
errorText="Nama harus 350 karakter (huruf, angka, spasi, dan simbol ringan (. , ' _ -))"
onChange={val => {
@@ -376,6 +366,7 @@ export default function EditMember() {
placeholder="Email"
required
value={data?.email}
bg={colors.card}
error={error.email}
errorText="Email tidak valid"
onChange={val => {
@@ -387,8 +378,9 @@ export default function EditMember() {
type="numeric"
placeholder="8XX-XXX-XXX"
required
itemLeft={<Text style={[Platform.OS === 'ios' && Styles.mt02]}>+62</Text>}
itemLeft={<Text style={[Platform.OS === 'ios' && Styles.mt02, { color: colors.text }]}>+62</Text>}
value={data?.phone}
bg={colors.card}
error={error.phone}
errorText="Nomor Telepon tidak valid"
onChange={val => {
@@ -400,6 +392,7 @@ export default function EditMember() {
placeholder="Pilih Jenis Kelamin"
value={chooseGender.label}
required
bg={colors.card}
onPress={() => {
setValChoose(chooseGender.val);
setValSelect("gender");

View File

@@ -2,12 +2,15 @@ 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 WrapTab from "@/components/wrapTab";
import { ConstEnv } from "@/constants/ConstEnv";
import Styles from "@/constants/Styles";
import { apiGetUser } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { AntDesign, Feather } from "@expo/vector-icons";
import { router, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
@@ -32,6 +35,7 @@ export default function Index() {
const { active, group } = useLocalSearchParams<{ active?: string, group?: string }>()
const { token, decryptToken } = useAuthSession()
const entityUser = useSelector((state: any) => state.user)
const { colors } = useTheme();
const [search, setSearch] = useState('')
const [nameGroup, setNameGroup] = useState('')
const [data, setData] = useState<Props[]>([])
@@ -103,29 +107,30 @@ export default function Index() {
});
return (
<View style={[Styles.p15, { flex: 1 }]}>
<View style={[Styles.p15, { flex: 1, backgroundColor: colors.background }]}>
<View>
<View style={[Styles.wrapBtnTab]}>
<WrapTab>
<ButtonTab
active={status == "false" ? "false" : "true"}
value="true"
onPress={() => { setStatus("true") }}
label="Aktif"
icon={<Feather name="check-circle" color={status == "false" ? 'black' : 'white'} size={20} />}
icon={<Feather name="check-circle" color={status == "false" ? colors.dimmed : 'white'} size={20} />}
n={2} />
<ButtonTab
active={status == "false" ? "false" : "true"}
value="false"
onPress={() => { setStatus("false") }}
label="Tidak Aktif"
icon={<AntDesign name="closecircleo" color={status == "false" ? 'white' : 'black'} size={20} />}
icon={<AntDesign name="closecircleo" color={status == "false" ? 'white' : colors.dimmed} size={20} />}
n={2} />
</View>
</WrapTab>
<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>
@@ -166,6 +171,7 @@ export default function Index() {
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
tintColor={colors.primary}
/>
}
/>

View File

@@ -7,6 +7,7 @@ import { apiGetNotification, apiReadOneNotification } from "@/lib/api";
import { setUpdateNotification } from "@/lib/notificationSlice";
import { pushToPage } from "@/lib/pushToPage";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { Feather } from "@expo/vector-icons";
import { useEffect, useState } from "react";
import { RefreshControl, SafeAreaView, View, VirtualizedList } from "react-native";
@@ -24,6 +25,7 @@ type Props = {
export default function Notification() {
const { token, decryptToken } = useAuthSession()
const { colors } = useTheme();
const [loading, setLoading] = useState(false)
const [data, setData] = useState<Props[]>([])
const [page, setPage] = useState(1)
@@ -97,7 +99,7 @@ export default function Notification() {
};
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<View style={[Styles.p15]}>
{
loading ?
@@ -124,7 +126,7 @@ export default function Notification() {
title={item.title}
rightTopInfo={item.createdAt}
desc={item.desc}
textColor={item.isRead ? 'gray' : 'black'}
textColor={item.isRead ? 'gray' : colors.text}
onPress={() => {
handleReadNotification(item.id, item.category, item.idContent)
@@ -140,6 +142,7 @@ export default function Notification() {
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
tintColor={colors.primary}
/>
}
/>

View File

@@ -5,14 +5,17 @@ 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";
import WrapTab from "@/components/wrapTab";
import { ColorsStatus } from "@/constants/ColorsStatus";
import Styles from "@/constants/Styles";
import { apiDeletePosition, apiEditPosition, apiGetPosition } from "@/lib/api";
import { setUpdatePosition } from "@/lib/positionSlice";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { AntDesign, Feather, MaterialCommunityIcons } from "@expo/vector-icons";
import { useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
@@ -32,6 +35,7 @@ export default function Index() {
const arrSkeleton = Array.from({ length: 5 }, (_, index) => index)
const [loading, setLoading] = useState(true)
const { token, decryptToken } = useAuthSession()
const { colors } = useTheme()
const [status, setStatus] = useState<'true' | 'false'>('true')
const entityUser = useSelector((state: any) => state.user)
const { active, group } = useLocalSearchParams<{ active?: string, group?: string }>()
@@ -145,29 +149,30 @@ export default function Index() {
});
return (
<View style={[Styles.p15, { flex: 1 }]}>
<View style={[Styles.p15, { flex: 1, backgroundColor: colors.background }]}>
<View>
<View style={[Styles.wrapBtnTab]}>
<WrapTab>
<ButtonTab
active={status == "false" ? "false" : "true"}
value="true"
onPress={() => { setStatus("true") }}
label="Aktif"
icon={<Feather name="check-circle" color={status == "true" ? 'white' : 'black'} size={20} />}
icon={<Feather name="check-circle" color={status == "true" ? 'white' : colors.dimmed} size={20} />}
n={2} />
<ButtonTab
active={status == "false" ? "false" : "true"}
value="false"
onPress={() => { setStatus("false") }}
label="Tidak Aktif"
icon={<AntDesign name="closecircleo" color={status == "false" ? 'white' : 'black'} size={20} />}
icon={<AntDesign name="closecircleo" color={status == "false" ? 'white' : colors.dimmed} size={20} />}
n={2} />
</View>
</WrapTab>
<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>
@@ -195,8 +200,8 @@ export default function Index() {
}}
borderType="all"
icon={
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
<MaterialCommunityIcons name="account-tie" size={25} color={'#384288'} />
<View style={[Styles.iconContent]}>
<MaterialCommunityIcons name="account-tie-outline" size={25} color={'black'} />
</View>
}
title={item.name}
@@ -210,6 +215,7 @@ export default function Index() {
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
tintColor={colors.primary}
/>
}
/>
@@ -220,7 +226,7 @@ export default function Index() {
<DrawerBottom animation="slide" isVisible={isModal} setVisible={() => setModal(false)} title={chooseData.name}>
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<MaterialCommunityIcons name="toggle-switch-off-outline" color="black" size={25} />}
icon={<MaterialCommunityIcons name="toggle-switch-off-outline" color={colors.text} size={25} />}
title={chooseData.active ? 'Non Aktifkan' : "Aktifkan"}
onPress={() => {
setModal(false)
@@ -232,7 +238,7 @@ export default function Index() {
}}
/>
<MenuItemRow
icon={<MaterialCommunityIcons name="pencil-outline" color="black" size={25} />}
icon={<MaterialCommunityIcons name="pencil-outline" color={colors.text} size={25} />}
title="Edit"
onPress={() => {
setModal(false)
@@ -253,6 +259,7 @@ export default function Index() {
placeholder="Nama Jabatan"
required
label="Jabatan"
bg={"transparent"}
value={chooseData.name}
onChange={(val) => { validationForm(val) }}
error={error.name}

View File

@@ -7,22 +7,41 @@ import { assetUserImage } from "@/constants/AssetsError";
import { ConstEnv } from "@/constants/ConstEnv";
import Styles from "@/constants/Styles";
import { useAuthSession } from "@/providers/AuthProvider";
import { AntDesign } from "@expo/vector-icons";
import { useTheme } from "@/providers/ThemeProvider";
import { AntDesign, Ionicons } from "@expo/vector-icons";
import { router, Stack } from "expo-router";
import { LinearGradient } from "expo-linear-gradient";
import { useState } from "react";
import { Image, Pressable, SafeAreaView, ScrollView, View } from "react-native";
import { Image, Modal, Pressable, SafeAreaView, ScrollView, TouchableOpacity, View } from "react-native";
import ImageViewing from 'react-native-image-viewing';
import { useSelector } from 'react-redux';
export default function Profile() {
const { signOut } = useAuthSession()
const { theme, setTheme, colors } = useTheme();
const entities = useSelector((state: any) => state.entities)
const [error, setError] = useState(false)
const [preview, setPreview] = useState(false)
const [showThemeModal, setShowThemeModal] = useState(false)
const ThemeOption = ({ label, value, icon }: { label: string, value: 'light' | 'dark' | 'system', icon: string }) => (
<TouchableOpacity
style={[Styles.itemSelectModal, { backgroundColor: theme === value ? colors.primary + '10' : 'transparent', borderColor: colors.icon + '20' }]}
onPress={() => {
setTheme(value);
setShowThemeModal(false);
}}
>
<View style={Styles.rowItemsCenter}>
<Ionicons name={icon as any} size={20} color={theme === value ? colors.primary : colors.text} style={{ marginRight: 10 }} />
<Text style={{ color: colors.text, fontWeight: theme === value ? 'bold' : 'normal' }}>{label}</Text>
</View>
{theme === value && <Ionicons name="checkmark" size={20} color={colors.primary} />}
</TouchableOpacity>
);
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
headerTitle: 'Profile',
@@ -46,21 +65,14 @@ export default function Profile() {
}
/>
)
// 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]}>
<ScrollView style={[Styles.h100, { backgroundColor: colors.background }]}>
<View style={{ flexDirection: 'column' }}>
<View style={[Styles.wrapHeadViewMember]}>
<LinearGradient
colors={[colors.header, colors.homeGradient]}
style={[Styles.wrapHeadViewMember]}
>
<Pressable onPress={() => setPreview(true)}>
<Image
source={error ? require("../../assets/images/user.jpg") : { uri: `${ConstEnv.url_storage}/files/${entities.img}` }}
@@ -70,14 +82,35 @@ export default function Profile() {
</Pressable>
<Text style={[Styles.textSubtitle, Styles.cWhite, Styles.mt10]}>{entities.name}</Text>
<Text style={[Styles.textMediumNormal, Styles.cWhite]}>{entities.role}</Text>
</View>
</LinearGradient>
<View style={[Styles.p15]}>
<View style={[Styles.rowSpaceBetween]}>
<Text style={[Styles.textDefaultSemiBold]}>Informasi</Text>
<View style={[Styles.rowSpaceBetween, Styles.mb15]}>
<Text style={[Styles.textDefaultSemiBold, { color: colors.text }]}>Tampilan</Text>
</View>
<TouchableOpacity
onPress={() => setShowThemeModal(true)}
style={[Styles.wrapItemBorderAll, { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', borderColor: colors.icon + '40', backgroundColor: colors.background }]}
>
<View style={Styles.rowItemsCenter}>
<Ionicons name="color-palette-outline" size={20} color={colors.text} style={{ marginRight: 10 }} />
<Text style={{ color: colors.text }}>Tema Aplikasi</Text>
</View>
<View style={Styles.rowItemsCenter}>
<Text style={{ color: colors.icon, marginRight: 5, fontSize: 13 }}>
{theme === 'light' ? 'Terang' : theme === 'dark' ? 'Gelap' : 'Sistem'}
</Text>
<Ionicons name="chevron-forward" size={16} color={colors.icon} />
</View>
</TouchableOpacity>
<View style={[Styles.rowSpaceBetween, Styles.mt15]}>
<Text style={[Styles.textDefaultSemiBold, { color: colors.text }]}>Informasi</Text>
{
entities.idUserRole != "developer" && <Text onPress={() => { router.push('/edit-profile') }} style={[Styles.textLink]}>Edit</Text>
}
</View>
{/* Note: ItemDetailMember might need updates to support dynamic colors if it uses default text colors */}
<ItemDetailMember category="nik" value={entities.nik} />
<ItemDetailMember category="group" value={entities.group} />
<ItemDetailMember category="position" value={entities.position} />
@@ -87,6 +120,30 @@ export default function Profile() {
</View>
</View>
</ScrollView>
<Modal
animationType="fade"
transparent={true}
visible={showThemeModal}
onRequestClose={() => setShowThemeModal(false)}
>
<TouchableOpacity style={Styles.modalBgTransparant} activeOpacity={1} onPress={() => setShowThemeModal(false)}>
<View style={[Styles.modalContent, { backgroundColor: colors.background }]}>
<View style={[Styles.titleContainer, { backgroundColor: colors.background, borderBottomColor: colors.icon + '20', borderBottomWidth: 1 }]}>
<Text style={[Styles.textSubtitle, { color: colors.text }]}>Pilih Tema</Text>
<TouchableOpacity onPress={() => setShowThemeModal(false)}>
<Ionicons name="close" size={24} color={colors.text} />
</TouchableOpacity>
</View>
<View style={{ padding: 10 }}>
<ThemeOption label="Terang" value="light" icon="sunny-outline" />
<ThemeOption label="Gelap" value="dark" icon="moon-outline" />
<ThemeOption label="Sistem" value="system" icon="phone-portrait-outline" />
</View>
</View>
</TouchableOpacity>
</Modal>
<ImageViewing
images={[{ uri: error ? assetUserImage.uri : `${ConstEnv.url_storage}/files/${entities.img}` }]}
imageIndex={0}

View File

@@ -8,6 +8,7 @@ import Styles from "@/constants/Styles"
import { apiAddFileProject, apiCheckFileProject } from "@/lib/api"
import { setUpdateProject } from "@/lib/projectUpdate"
import { useAuthSession } from "@/providers/AuthProvider"
import { useTheme } from "@/providers/ThemeProvider"
import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons"
import * as DocumentPicker from "expo-document-picker"
import { router, Stack, useLocalSearchParams } from "expo-router"
@@ -17,6 +18,7 @@ import Toast from "react-native-toast-message"
import { useDispatch, useSelector } from "react-redux"
export default function ProjectAddFile() {
const { colors } = useTheme();
const { id } = useLocalSearchParams<{ id: string }>()
const [fileForm, setFileForm] = useState<any[]>([])
const [listFile, setListFile] = useState<any[]>([])
@@ -127,7 +129,7 @@ export default function ProjectAddFile() {
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
@@ -153,20 +155,20 @@ export default function ProjectAddFile() {
)
}}
/>
<ScrollView>
<ScrollView style={{ backgroundColor: colors.background }}>
<View style={[Styles.p15, Styles.mb100]}>
<ButtonSelect value="Upload File" onPress={pickDocumentAsync} />
{
listFile.length > 0 && (
<View style={[Styles.mb15]}>
<Text style={[Styles.textDefaultSemiBold, Styles.mv05]}>File</Text>
<View style={[Styles.wrapPaper]}>
<View style={[Styles.wrapPaper, { backgroundColor: colors.card, borderColor: colors.background }]}>
{
listFile.map((item, index) => (
<BorderBottomItem
key={index}
borderType="all"
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item}
titleWeight="normal"
onPress={() => { setIndexDelFile(index); setModal(true) }}
@@ -188,7 +190,7 @@ export default function ProjectAddFile() {
<DrawerBottom animation="slide" isVisible={isModal} setVisible={setModal} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<Ionicons name="trash" color="black" size={25} />}
icon={<Ionicons name="trash-outline" color={colors.text} size={25} />}
title="Hapus"
onPress={() => { deleteFile(indexDelFile) }}
/>

View File

@@ -9,6 +9,7 @@ import Styles from "@/constants/Styles";
import { apiAddMemberProject, apiGetProjectOne, apiGetUser } from "@/lib/api";
import { setUpdateProject } from "@/lib/projectUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { AntDesign } from "@expo/vector-icons";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
@@ -23,6 +24,7 @@ type Props = {
}
export default function AddMemberProject() {
const { colors } = useTheme();
const dispatch = useDispatch()
const update = useSelector((state: any) => state.projectUpdate)
const { token, decryptToken } = useAuthSession()
@@ -127,7 +129,7 @@ export default function AddMemberProject() {
)
}}
/>
<View style={[Styles.p15, { flex: 1 }]}>
<View style={[Styles.p15, { flex: 1, backgroundColor: colors.background }]}>
<InputSearch onChange={(val) => handleSearch(val)} value={search} />
{
selectMember.length > 0
@@ -152,7 +154,7 @@ export default function AddMemberProject() {
}
<ScrollView
showsVerticalScrollIndicator={false}
style={[Styles.h100]}
style={[Styles.h100, { backgroundColor: colors.background }]}
>
{
data.length > 0 ?
@@ -178,7 +180,7 @@ export default function AddMemberProject() {
</View>
</View>
{
selectMember.some((i: any) => i.idUser == item.id) && <AntDesign name="check" size={20} color={'black'} />
selectMember.some((i: any) => i.idUser == item.id) && <AntDesign name="check" size={20} color={colors.text} />
}
</Pressable>
)

View File

@@ -9,6 +9,7 @@ import { formatDateOnly } from "@/lib/fun_formatDateOnly";
import { getDatesInRange } from "@/lib/fun_getDatesInRange";
import { setUpdateProject } from "@/lib/projectUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { useHeaderHeight } from '@react-navigation/elements';
import { router, Stack, useLocalSearchParams } from "expo-router";
import 'intl';
@@ -30,6 +31,7 @@ import DateTimePicker, {
import { useDispatch, useSelector } from "react-redux";
export default function ProjectAddTask() {
const { colors } = useTheme();
const headerHeight = useHeaderHeight();
const { token, decryptToken } = useAuthSession()
const dispatch = useDispatch()
@@ -133,7 +135,7 @@ export default function ProjectAddTask() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -158,11 +160,11 @@ export default function ProjectAddTask() {
showBack={true}
onPressLeft={() => router.back()}
right={
<ButtonSaveHeader
disable={disable || loading}
category="create"
onPress={() => { handleCreate() }}
/>
<ButtonSaveHeader
disable={disable || loading}
category="create"
onPress={() => { handleCreate() }}
/>
}
/>
)
@@ -172,9 +174,9 @@ export default function ProjectAddTask() {
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
keyboardVerticalOffset={headerHeight}
>
<ScrollView>
<ScrollView style={{ backgroundColor: colors.background }}>
<View style={[Styles.p15, Styles.mb100]}>
<View style={[Styles.wrapPaper, Styles.p10]}>
<View style={[Styles.wrapPaper, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
<DateTimePicker
mode="range"
startDate={range.startDate}
@@ -184,13 +186,13 @@ export default function ProjectAddTask() {
selected: Styles.selectedDate,
selected_label: Styles.cWhite,
range_fill: Styles.selectRangeDate,
month_label: Styles.cBlack,
month_selector_label: Styles.cBlack,
year_label: Styles.cBlack,
year_selector_label: Styles.cBlack,
day_label: Styles.cBlack,
time_label: Styles.cBlack,
weekday_label: Styles.cBlack,
month_label: { color: colors.text },
month_selector_label: { color: colors.text },
year_label: { color: colors.text },
year_selector_label: { color: colors.text },
day_label: { color: colors.text },
time_label: { color: colors.text },
weekday_label: { color: colors.text },
}}
/>
</View>
@@ -200,7 +202,7 @@ export default function ProjectAddTask() {
<Text style={[Styles.mb05]}>
Tanggal Mulai <Text style={Styles.cError}>*</Text>
</Text>
<View style={[Styles.wrapPaper, Styles.p10]}>
<View style={[Styles.wrapPaper, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
<Text style={{ textAlign: "center" }}>{from}</Text>
</View>
</View>
@@ -208,7 +210,7 @@ export default function ProjectAddTask() {
<Text style={[Styles.mb05]}>
Tanggal Berakhir <Text style={Styles.cError}>*</Text>
</Text>
<View style={[Styles.wrapPaper, Styles.p10]}>
<View style={[Styles.wrapPaper, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
<Text style={{ textAlign: "center" }}>{to}</Text>
</View>
</View>
@@ -229,7 +231,7 @@ export default function ProjectAddTask() {
type="default"
placeholder="Judul Tugas"
required
bg="white"
bg={colors.card}
value={title}
error={error.title}
errorText="Judul tidak boleh kosong"

View File

@@ -5,6 +5,7 @@ import Styles from "@/constants/Styles";
import { apiCancelProject } from "@/lib/api";
import { setUpdateProject } from "@/lib/projectUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { router, Stack, useLocalSearchParams } from "expo-router";
import React, { useEffect, useState } from "react";
import { SafeAreaView, ScrollView, View } from "react-native";
@@ -12,6 +13,7 @@ import Toast from "react-native-toast-message";
import { useDispatch, useSelector } from "react-redux";
export default function ProjectCancel() {
const { colors } = useTheme();
const { token, decryptToken } = useAuthSession();
const { id } = useLocalSearchParams<{ id: string }>();
const dispatch = useDispatch();
@@ -65,7 +67,7 @@ export default function ProjectCancel() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -106,7 +108,7 @@ export default function ProjectCancel() {
/>
<ScrollView
showsVerticalScrollIndicator={false}
style={[Styles.h100]}
style={[Styles.h100, { backgroundColor: colors.background }]}
>
<View style={[Styles.p15]}>
<InputForm
@@ -114,7 +116,7 @@ export default function ProjectCancel() {
type="default"
placeholder="Alasan Pembatalan"
required
bg="white"
bg={colors.card}
error={error}
errorText="Alasan pembatalan harus diisi"
onChange={(val) => onValidation(val)}

View File

@@ -5,6 +5,7 @@ import Styles from "@/constants/Styles";
import { apiEditProject, apiGetProjectOne } from "@/lib/api";
import { setUpdateProject } from "@/lib/projectUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
import { SafeAreaView, ScrollView, View } from "react-native";
@@ -12,6 +13,7 @@ import Toast from "react-native-toast-message";
import { useDispatch, useSelector } from "react-redux";
export default function EditProject() {
const { colors } = useTheme();
const { token, decryptToken } = useAuthSession();
const { id } = useLocalSearchParams<{ id: string }>();
const dispatch = useDispatch()
@@ -86,7 +88,7 @@ export default function EditProject() {
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -121,14 +123,14 @@ export default function EditProject() {
)
}}
/>
<ScrollView>
<ScrollView style={{ backgroundColor: colors.background }}>
<View style={[Styles.p15, Styles.mb100]}>
<InputForm
label="Judul Kegiatan"
type="default"
placeholder="Judul Kegiatan"
required
bg="white"
bg={colors.card}
value={judul}
onChange={(val) => { onValidation(val) }}
error={error}

View File

@@ -10,6 +10,7 @@ import SectionProgress from "@/components/sectionProgress";
import Styles from "@/constants/Styles";
import { apiGetProjectOne } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { router, Stack, useLocalSearchParams } from "expo-router";
import React, { useEffect, useState } from "react";
import { RefreshControl, SafeAreaView, ScrollView, View } from "react-native";
@@ -32,6 +33,7 @@ type Props = {
export default function DetailProject() {
const { token, decryptToken } = useAuthSession()
const { colors } = useTheme();
const { id } = useLocalSearchParams<{ id: string }>();
const [data, setData] = useState<Props>()
const [progress, setProgress] = useState(0)
@@ -91,7 +93,7 @@ export default function DetailProject() {
};
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
@@ -111,10 +113,12 @@ export default function DetailProject() {
}}
/>
<ScrollView
style={{ backgroundColor: colors.background }}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
tintColor={colors.primary}
/>
}
>

View File

@@ -5,6 +5,7 @@ import Styles from "@/constants/Styles";
import { apiGetProjectOne, apiReportProject } from "@/lib/api";
import { setUpdateProject } from "@/lib/projectUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
import { SafeAreaView, ScrollView, View } from "react-native";
@@ -12,6 +13,7 @@ import Toast from "react-native-toast-message";
import { useDispatch, useSelector } from "react-redux";
export default function ReportProject() {
const { colors } = useTheme();
const { token, decryptToken } = useAuthSession();
const { id } = useLocalSearchParams<{ id: string }>();
const dispatch = useDispatch()
@@ -86,7 +88,7 @@ export default function ReportProject() {
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -123,7 +125,7 @@ export default function ReportProject() {
/>
<ScrollView
showsVerticalScrollIndicator={false}
style={[Styles.h100]}
style={[Styles.h100, { backgroundColor: colors.background }]}
>
<View style={[Styles.p15]}>
<InputForm
@@ -131,7 +133,7 @@ export default function ReportProject() {
type="default"
placeholder="Laporan Kegiatan"
required
bg="white"
bg={colors.card}
value={laporan}
onChange={(val) => { onValidation(val) }}
error={error}

View File

@@ -18,6 +18,7 @@ import { setMemberChoose } from "@/lib/memberChoose";
import { setUpdateProject } from "@/lib/projectUpdate";
import { setTaskCreate } from "@/lib/taskCreate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons";
import * as DocumentPicker from "expo-document-picker";
import { router, Stack } from "expo-router";
@@ -31,6 +32,7 @@ import Toast from "react-native-toast-message";
import { useDispatch, useSelector } from "react-redux";
export default function CreateProject() {
const { colors } = useTheme();
const [loading, setLoading] = useState(false)
const { token, decryptToken } = useAuthSession();
const [chooseGroup, setChooseGroup] = useState({ val: "", label: "" });
@@ -190,7 +192,7 @@ export default function CreateProject() {
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -230,7 +232,7 @@ export default function CreateProject() {
/>
<ScrollView
showsVerticalScrollIndicator={false}
style={[Styles.h100]}
style={[Styles.h100, { backgroundColor: colors.background }]}
>
<View style={[Styles.p15]}>
{
@@ -242,6 +244,7 @@ export default function CreateProject() {
placeholder="Pilih Lembaga Desa"
value={chooseGroup.label}
required
bg={colors.card}
onPress={() => {
setValChoose(chooseGroup.val);
setValSelect("group");
@@ -257,6 +260,7 @@ export default function CreateProject() {
type="default"
placeholder="Nama Kegiatan"
required
bg={colors.card}
value={dataForm.title}
error={error.title}
errorText="Nama kegiatan tidak boleh kosong"
@@ -294,13 +298,13 @@ export default function CreateProject() {
fileForm.length > 0 && (
<View style={[Styles.mb15]}>
<Text style={[Styles.textDefaultSemiBold, Styles.mv05]}>File</Text>
<View style={[Styles.wrapPaper]}>
<View style={[Styles.wrapPaper, { backgroundColor: colors.card, borderColor: colors.background }]}>
{
fileForm.map((item, index) => (
<BorderBottomItem
key={index}
borderType="all"
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
icon={<MaterialCommunityIcons name="file-outline" size={25} color={colors.text} />}
title={item.name}
titleWeight="normal"
onPress={() => { setIndexDelFile(index); setModal(true) }}
@@ -318,7 +322,7 @@ export default function CreateProject() {
<Text>Total {entitiesMember.length} Anggota</Text>
</View>
<View style={[Styles.borderAll, Styles.round10, Styles.p10]}>
<View style={[Styles.borderAll, Styles.round05, Styles.p10, { borderColor: colors.icon, backgroundColor: colors.card }]}>
{entitiesMember.map(
(item: { img: any; name: any }, index: any) => {
return (
@@ -344,7 +348,7 @@ export default function CreateProject() {
<DrawerBottom animation="slide" isVisible={isModal} setVisible={setModal} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<Ionicons name="trash" color="black" size={25} />}
icon={<Ionicons name="trash-outline" color={colors.text} size={25} />}
title="Hapus"
onPress={() => { deleteFile(indexDelFile) }}
/>

View File

@@ -9,6 +9,7 @@ import Styles from "@/constants/Styles";
import { apiGetUser } from "@/lib/api";
import { setMemberChoose } from "@/lib/memberChoose";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { AntDesign } from "@expo/vector-icons";
import { router, Stack } from "expo-router";
import React, { useEffect, useState } from "react";
@@ -23,6 +24,7 @@ type Props = {
}
export default function AddMemberCreateProject() {
const { colors } = useTheme();
const dispatch = useDispatch()
const { token, decryptToken } = useAuthSession()
const [data, setData] = useState<Props[]>([])
@@ -103,7 +105,7 @@ export default function AddMemberCreateProject() {
)
}}
/>
<View style={[Styles.p15, { flex: 1 }]}>
<View style={[Styles.p15, { flex: 1, backgroundColor: colors.background }]}>
<InputSearch onChange={(val) => setSearch(val)} value={search} />
{
@@ -129,6 +131,7 @@ export default function AddMemberCreateProject() {
}
<ScrollView
showsVerticalScrollIndicator={false}
style={{ backgroundColor: colors.background }}
>
{
@@ -149,7 +152,7 @@ export default function AddMemberCreateProject() {
</View>
</View>
{
selectMember.some((i: any) => i.idUser == item.id) && <AntDesign name="check" size={20} color={'black'} />
selectMember.some((i: any) => i.idUser == item.id) && <AntDesign name="check" size={20} color={colors.text} />
}
</Pressable>
)

View File

@@ -7,6 +7,7 @@ import Styles from "@/constants/Styles";
import { formatDateOnly } from "@/lib/fun_formatDateOnly";
import { getDatesInRange } from "@/lib/fun_getDatesInRange";
import { setTaskCreate } from "@/lib/taskCreate";
import { useTheme } from "@/providers/ThemeProvider";
import { useHeaderHeight } from '@react-navigation/elements';
import { router, Stack } from "expo-router";
import 'intl';
@@ -27,6 +28,7 @@ import DateTimePicker, {
import { useDispatch, useSelector } from "react-redux";
export default function CreateProjectAddTask() {
const { colors } = useTheme();
const headerHeight = useHeaderHeight();
const dispatch = useDispatch()
const [disable, setDisable] = useState(true);
@@ -119,7 +121,7 @@ export default function CreateProjectAddTask() {
}
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => (
@@ -158,9 +160,9 @@ export default function CreateProjectAddTask() {
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
keyboardVerticalOffset={headerHeight}
>
<ScrollView>
<ScrollView style={{ backgroundColor: colors.background }}>
<View style={[Styles.p15, Styles.mb100]}>
<View style={[Styles.wrapPaper, Styles.p10]}>
<View style={[Styles.wrapPaper, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
<DateTimePicker
mode="range"
startDate={range.startDate}
@@ -170,7 +172,7 @@ export default function CreateProjectAddTask() {
selected: Styles.selectedDate,
selected_label: Styles.cWhite,
range_fill: Styles.selectRangeDate,
month_label: Styles.cBlack,
month_label: { color: colors.text },
month_selector_label: Styles.cBlack,
year_label: Styles.cBlack,
year_selector_label: Styles.cBlack,
@@ -186,7 +188,7 @@ export default function CreateProjectAddTask() {
<Text style={[Styles.mb05]}>
Tanggal Mulai <Text style={Styles.cError}>*</Text>
</Text>
<View style={[Styles.wrapPaper, Styles.p10]}>
<View style={[Styles.wrapPaper, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
<Text style={{ textAlign: "center" }}>{from}</Text>
</View>
</View>
@@ -194,7 +196,7 @@ export default function CreateProjectAddTask() {
<Text style={[Styles.mb05]}>
Tanggal Berakhir <Text style={Styles.cError}>*</Text>
</Text>
<View style={[Styles.wrapPaper, Styles.p10]}>
<View style={[Styles.wrapPaper, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
<Text style={{ textAlign: "center" }}>{to}</Text>
</View>
</View>
@@ -215,7 +217,7 @@ export default function CreateProjectAddTask() {
type="default"
placeholder="Judul Tugas"
required
bg="white"
bg={colors.card}
value={title}
error={error.title}
errorText="Judul tidak boleh kosong"

View File

@@ -11,6 +11,7 @@ import { ColorsStatus } from "@/constants/ColorsStatus";
import Styles from "@/constants/Styles";
import { apiGetProject } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import {
AntDesign,
Ionicons,
@@ -32,16 +33,20 @@ 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 { colors } = useTheme();
const entityUser = useSelector((state: any) => state.user)
const [search, setSearch] = useState("")
const [nameGroup, setNameGroup] = useState("")
// ... state same ...
const [isYear, setYear] = useState("")
const [data, setData] = useState<Props[]>([])
const [isList, setList] = useState(false)
const update = useSelector((state: any) => state.projectUpdate)
@@ -63,11 +68,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 +98,7 @@ export default function ListProject() {
useEffect(() => {
handleLoad(true, 1);
}, [statusFix, search, group, cat]);
}, [statusFix, search, group, cat, year]);
const loadMoreData = () => {
if (waiting) return
@@ -118,7 +125,7 @@ export default function ListProject() {
})
return (
<View style={[Styles.p15, { flex: 1 }]}>
<View style={[Styles.p15, { flex: 1, backgroundColor: colors.background }]}>
<View>
<ScrollView horizontal style={[Styles.mb10]} showsHorizontalScrollIndicator={false}>
<ButtonTab
@@ -129,7 +136,7 @@ export default function ListProject() {
icon={
<MaterialCommunityIcons
name="clock-alert-outline"
color={statusFix == "0" ? "white" : "black"}
color={statusFix == "0" ? "white" : colors.dimmed}
size={20}
/>
}
@@ -143,7 +150,7 @@ export default function ListProject() {
icon={
<MaterialCommunityIcons
name="progress-check"
color={statusFix == "1" ? "white" : "black"}
color={statusFix == "1" ? "white" : colors.dimmed}
size={20}
/>
}
@@ -157,7 +164,7 @@ export default function ListProject() {
icon={
<Ionicons
name="checkmark-done-circle-outline"
color={statusFix == "2" ? "white" : "black"}
color={statusFix == "2" ? "white" : colors.dimmed}
size={20}
/>
}
@@ -171,7 +178,7 @@ export default function ListProject() {
icon={
<AntDesign
name="closecircleo"
color={statusFix == "3" ? "white" : "black"}
color={statusFix == "3" ? "white" : colors.dimmed}
size={20}
/>
}
@@ -187,24 +194,32 @@ export default function ListProject() {
>
<MaterialCommunityIcons
name={isList ? "format-list-bulleted" : "view-grid"}
color={"black"}
color={colors.text}
size={30}
/>
</Pressable>
</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>

View File

@@ -9,6 +9,7 @@ import { formatDateOnly } from "@/lib/fun_formatDateOnly";
import { getDatesInRange } from "@/lib/fun_getDatesInRange";
import { setUpdateProject } from "@/lib/projectUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { useHeaderHeight } from '@react-navigation/elements';
import { router, Stack, useLocalSearchParams } from "expo-router";
import 'intl';
@@ -21,6 +22,7 @@ import DateTimePicker, { DateType } from "react-native-ui-datepicker";
import { useDispatch, useSelector } from "react-redux";
export default function UpdateProjectTask() {
const { colors } = useTheme();
const headerHeight = useHeaderHeight();
const dispatch = useDispatch()
const update = useSelector((state: any) => state.projectUpdate)
@@ -169,7 +171,7 @@ export default function UpdateProjectTask() {
}, [range])
return (
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
// headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
@@ -200,9 +202,9 @@ export default function UpdateProjectTask() {
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
keyboardVerticalOffset={headerHeight}
>
<ScrollView>
<ScrollView style={{ backgroundColor: colors.background }}>
<View style={[Styles.p15, Styles.mb100]}>
<View style={[Styles.wrapPaper, Styles.p10]}>
<View style={[Styles.wrapPaper, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
{
!loading
&&
@@ -217,13 +219,13 @@ export default function UpdateProjectTask() {
selected: Styles.selectedDate,
selected_label: Styles.cWhite,
range_fill: Styles.selectRangeDate,
month_label: Styles.cBlack,
month_selector_label: Styles.cBlack,
year_label: Styles.cBlack,
year_selector_label: Styles.cBlack,
day_label: Styles.cBlack,
time_label: Styles.cBlack,
weekday_label: Styles.cBlack,
month_label: { color: colors.text },
month_selector_label: { color: colors.text },
year_label: { color: colors.text },
year_selector_label: { color: colors.text },
day_label: { color: colors.text },
time_label: { color: colors.text },
weekday_label: { color: colors.text },
}}
/>
}
@@ -233,13 +235,13 @@ export default function UpdateProjectTask() {
<View style={[Styles.rowSpaceBetween]}>
<View style={[{ width: '48%' }]}>
<Text style={[Styles.mb05]}>Tanggal Mulai <Text style={Styles.cError}>*</Text></Text>
<View style={[Styles.wrapPaper, Styles.p10]}>
<View style={[Styles.wrapPaper, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
<Text style={{ textAlign: 'center' }}>{from}</Text>
</View>
</View>
<View style={[{ width: '48%' }]}>
<Text style={[Styles.mb05]}>Tanggal Berakhir <Text style={Styles.cError}>*</Text></Text>
<View style={[Styles.wrapPaper, Styles.p10]}>
<View style={[Styles.wrapPaper, Styles.p10, { backgroundColor: colors.card, borderColor: colors.background }]}>
<Text style={{ textAlign: 'center' }}>{to}</Text>
</View>
</View>
@@ -260,7 +262,7 @@ export default function UpdateProjectTask() {
type="default"
placeholder="Judul Tugas"
required
bg="white"
bg={colors.card}
value={title}
error={error.title}
errorText="Judul tidak boleh kosong"

View File

@@ -8,12 +8,14 @@ import { ConstEnv } from "@/constants/ConstEnv";
import Styles from "@/constants/Styles";
import { apiGetSearch } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { AntDesign, MaterialIcons } from "@expo/vector-icons";
import { router, Stack } from "expo-router";
import React, { useState } from "react";
import { RefreshControl, SafeAreaView, ScrollView, View } from "react-native";
import Toast from "react-native-toast-message";
// ... types ...
type PropsUser = {
id: string
name: string
@@ -43,6 +45,7 @@ export default function Search() {
const [dataProject, setDataProject] = useState<PropProject[]>([])
const [refreshing, setRefreshing] = useState(false)
const [search, setSearch] = useState('')
const { colors } = useTheme();
async function handleSearch(cari: string) {
try {
@@ -79,7 +82,7 @@ export default function Search() {
return (
<>
<SafeAreaView>
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<Stack.Screen
options={{
headerTitle: 'Pencarian',
@@ -100,6 +103,7 @@ export default function Search() {
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
tintColor={colors.primary}
/>
}
>
@@ -177,7 +181,7 @@ export default function Search() {
</ScrollView>
:
<View style={[Styles.contentItemCenter, Styles.mt10]}>
<Text style={[Styles.textInformation, Styles.cGray]}>Tidak ada data</Text>
<Text style={[Styles.textInformation, { color: colors.icon }]}>Tidak ada data</Text>
</View>
}

View File

@@ -1,4 +1,5 @@
import AuthProvider from '@/providers/AuthProvider';
import ThemeProvider from '@/providers/ThemeProvider';
import { useFonts } from 'expo-font';
import { Stack } from 'expo-router';
import * as SplashScreen from 'expo-splash-screen';
@@ -29,14 +30,16 @@ export default function RootLayout() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<NotifierWrapper>
<AuthProvider>
<Stack>
<Stack.Screen name="index" options={{ headerShown: false }} />
<Stack.Screen name="verification" options={{ headerShown: false }} />
<Stack.Screen name="(application)" options={{ headerShown: false }} />
</Stack>
<StatusBar style="auto" />
</AuthProvider>
<ThemeProvider>
<AuthProvider>
<Stack>
<Stack.Screen name="index" options={{ headerShown: false }} />
<Stack.Screen name="verification" options={{ headerShown: false }} />
<Stack.Screen name="(application)" options={{ headerShown: false }} />
</Stack>
<StatusBar style="auto" />
</AuthProvider>
</ThemeProvider>
</NotifierWrapper>
</GestureHandlerRootView>
);

View File

@@ -3,6 +3,7 @@ import Text from '@/components/Text';
import { ConstEnv } from "@/constants/ConstEnv";
import Styles from "@/constants/Styles";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import CryptoES from "crypto-es";
import React, { useState } from "react";
import { Image, View } from "react-native";
@@ -15,6 +16,7 @@ export default function Index() {
value,
setValue,
});
const { colors } = useTheme();
const { signIn } = useAuthSession();
const login = (): void => {
@@ -24,7 +26,7 @@ export default function Index() {
signIn(encrypted);
}
return (
<View style={Styles.wrapLogin} >
<View style={[Styles.wrapLogin, { backgroundColor: colors.background }]} >
<View style={{ alignItems: "center", marginVertical: 50 }}>
<Image
source={require("../assets/images/logo.png")}
@@ -50,7 +52,7 @@ export default function Index() {
renderCell={({ index, symbol, isFocused }) => (
<Text
key={index}
style={[Styles.verificationCell, isFocused && Styles.verificationFocusCell]}
style={[Styles.verificationCell, isFocused && Styles.verificationFocusCell, { borderColor: isFocused ? colors.tint : colors.icon, color: colors.text }]}
onLayout={getCellOnLayoutHandler(index)}>
{symbol || (isFocused ? <Cursor /> : null)}
</Text>
@@ -61,7 +63,7 @@ export default function Index() {
// onPress={() => { router.push("/home") }}
onPress={login}
/>
<Text style={[Styles.textInformation, Styles.mt05, Styles.cDefault, { textAlign: 'center' }]}>
<Text style={[Styles.textInformation, Styles.mt05, Styles.cDefault, { textAlign: 'center', color: colors.tint }]}>
Tidak Menerima kode verifikasi? Kirim Ulang
</Text>
</View>

View File

@@ -1,4 +1,5 @@
import Styles from '@/constants/Styles';
import { useTheme } from "@/providers/ThemeProvider";
import { useRouter } from 'expo-router';
import { Platform, Text, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
@@ -15,20 +16,22 @@ type Props = {
export default function AppHeader({ title, right, showBack = true, onPressLeft, left }: Props) {
const insets = useSafeAreaInsets();
const router = useRouter();
const { colors } = useTheme();
return (
<View style={[Styles.headerContainer, Platform.OS === 'ios' ? Styles.pb05 : Styles.pb13, { paddingTop: Platform.OS === 'ios' ? insets.top : 10 }]}>
<View style={[Styles.headerContainer, Platform.OS === 'ios' ? Styles.pb05 : Styles.pb13, { backgroundColor: colors.header, paddingTop: Platform.OS === 'ios' ? insets.top : 10 }]}>
<View style={Styles.headerApp}>
{showBack ? (
<ButtonBackHeader onPress={onPressLeft} />
) :
left ? left :
(
<View style={Styles.headerSide} />
)}
<Text style={Styles.headerTitle}>{title}</Text>
<View style={[Styles.rowItemsCenter]}>
{showBack ? (
<ButtonBackHeader onPress={onPressLeft} />
) :
left ? left :
(
<View style={Styles.headerSide} />
)}
<Text style={[Styles.headerTitle, Styles.ml05]}>{title}</Text>
</View>
<View style={Styles.headerSide}>{right}</View>
</View>
</View>

View File

@@ -1,23 +1,19 @@
import { useTheme } from '@/providers/ThemeProvider';
import React from 'react';
import { Text as RNText, TextProps as RNTextProps, StyleSheet } from 'react-native';
import { StyleSheet, Text as RNText, TextProps as RNTextProps } from 'react-native';
type TextProps = RNTextProps & {
children: React.ReactNode;
};
const Text: React.FC<TextProps> = ({ style, ...props }) => {
const { colors } = useTheme();
return (
<RNText
style={[styles.defaultText, style]}
<RNText
style={[{ color: colors.text }, style]}
{...props}
/>
);
};
const styles = StyleSheet.create({
defaultText: {
color: 'black',
},
});
export default Text;

View File

@@ -2,6 +2,7 @@ import Styles from "@/constants/Styles"
import { setUpdateAnnouncement } from "@/lib/announcementUpdate"
import { apiDeleteAnnouncement } from "@/lib/api"
import { useAuthSession } from "@/providers/AuthProvider"
import { useTheme } from "@/providers/ThemeProvider"
import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons"
import { router } from "expo-router"
import { useState } from "react"
@@ -18,6 +19,7 @@ type Props = {
}
export default function HeaderRightAnnouncementDetail({ id }: Props) {
const { token, decryptToken } = useAuthSession()
const { colors } = useTheme();
const [isVisible, setVisible] = useState(false)
const update = useSelector((state: any) => state.announcementUpdate)
const dispatch = useDispatch()
@@ -46,7 +48,7 @@ export default function HeaderRightAnnouncementDetail({ id }: Props) {
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={setVisible} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<MaterialCommunityIcons name="pencil-outline" color="black" size={25} />}
icon={<MaterialCommunityIcons name="pencil-outline" color={colors.text} size={25} />}
title="Edit"
onPress={() => {
setVisible(false)
@@ -54,7 +56,7 @@ export default function HeaderRightAnnouncementDetail({ id }: Props) {
}}
/>
<MenuItemRow
icon={<Ionicons name="trash" color="black" size={25} />}
icon={<Ionicons name="trash-outline" color={colors.text} size={25} />}
title="Hapus"
onPress={() => {
setVisible(false)

View File

@@ -1,4 +1,5 @@
import Styles from "@/constants/Styles"
import { useTheme } from "@/providers/ThemeProvider"
import { AntDesign } from "@expo/vector-icons"
import { router } from "expo-router"
import { useState } from "react"
@@ -9,6 +10,7 @@ import DrawerBottom from "../drawerBottom"
import MenuItemRow from "../menuItemRow"
export default function HeaderRightAnnouncementList() {
const { colors } = useTheme();
const [isVisible, setVisible] = useState(false)
const entityUser = useSelector((state: any) => state.user)
@@ -21,7 +23,7 @@ export default function HeaderRightAnnouncementList() {
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={setVisible} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<AntDesign name="pluscircle" color="black" size={25} />}
icon={<AntDesign name="pluscircleo" color={colors.text} size={25} />}
title="Tambah Pengumuman"
onPress={() => {
setVisible(false)

View File

@@ -1,6 +1,7 @@
import Styles from "@/constants/Styles"
import { apiCheckPhoneLogin, apiSendOtp } from "@/lib/api"
import { useAuthSession } from "@/providers/AuthProvider"
import { useTheme } from "@/providers/ThemeProvider"
import AsyncStorage from "@react-native-async-storage/async-storage"
import { StatusBar } from "expo-status-bar"
import { useState } from "react"
@@ -21,6 +22,7 @@ export default function ViewLogin({ onValidate }: Props) {
const [disableLogin, setDisableLogin] = useState(true)
const [phone, setPhone] = useState('')
const { signIn, encryptToken } = useAuthSession();
const { colors, theme } = useTheme();
const handleCheckPhone = async () => {
try {
@@ -49,8 +51,8 @@ export default function ViewLogin({ onValidate }: Props) {
};
return (
<SafeAreaView>
<StatusBar style={Platform.OS === 'ios' ? 'dark' : 'light'} translucent={false} backgroundColor="black" />
<SafeAreaView style={{ flex: 1, backgroundColor: colors.background }}>
<StatusBar style={theme === 'dark' ? 'light' : 'dark'} translucent={false} backgroundColor={colors.background} />
<ToastCustom />
<View style={[Styles.p20, Styles.h100]}>
<View style={{ alignItems: "center", marginTop: 70, marginBottom: 50 }}>

View File

@@ -1,6 +1,7 @@
import Styles from "@/constants/Styles";
import { apiSendOtp } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { StatusBar } from "expo-status-bar";
import { useState } from "react";
@@ -20,6 +21,7 @@ export default function ViewVerification({ phone, otp }: Props) {
const [value, setValue] = useState('');
const [otpFix, setOtpFix] = useState(otp)
const { signIn, encryptToken } = useAuthSession();
const { colors, theme } = useTheme();
const login = async () => {
const valueUser = await AsyncStorage.getItem('user');
@@ -57,9 +59,9 @@ export default function ViewVerification({ phone, otp }: Props) {
return (
<>
<StatusBar style={Platform.OS === 'ios' ? 'dark' : 'light'} translucent={false} backgroundColor="black" />
<StatusBar style={theme === 'dark' ? 'light' : 'dark'} translucent={false} backgroundColor={colors.background} />
<ToastCustom />
<View style={Styles.wrapLogin} >
<View style={[Styles.wrapLogin, { backgroundColor: colors.background }]} >
<View style={{ alignItems: "center", marginTop: 70, marginBottom: 50 }}>
<Image
source={require("../../assets/images/logo.png")}
@@ -77,22 +79,22 @@ export default function ViewVerification({ phone, otp }: Props) {
<OtpInput
numberOfDigits={4}
onTextChange={(text) => setValue(text)}
focusColor={'#19345E'}
focusColor={colors.tint}
type="numeric"
theme={{
containerStyle: {
width: '80%',
alignSelf: 'center'
},
pinCodeContainerStyle: Styles.verificationCell,
pinCodeTextStyle: { color: 'black' }
pinCodeContainerStyle: { ...Styles.verificationCell, borderColor: colors.icon },
pinCodeTextStyle: { color: colors.text }
}}
/>
<ButtonForm
text="SUBMIT"
onPress={() => { onCheckOtp() }}
/>
<Text style={[Styles.textInformation, Styles.mt05, Styles.cDefault, { textAlign: 'center' }]}>
<Text style={[Styles.textInformation, Styles.mt05, Styles.cDefault, { textAlign: 'center', color: colors.tint }]}>
Tidak Menerima kode verifikasi? <Text onPress={() => { resendOtp() }}>Kirim Ulang</Text>
</Text>
</View>

View File

@@ -1,21 +1,23 @@
import { useState } from "react";
import ButtonMenuHeader from "../buttonMenuHeader";
import DrawerBottom from "../drawerBottom";
import { View } from "react-native";
import Styles from "@/constants/Styles";
import MenuItemRow from "../menuItemRow";
import { useTheme } from "@/providers/ThemeProvider";
import { AntDesign } from "@expo/vector-icons";
import { router } from "expo-router";
import { useState } from "react";
import { View } from "react-native";
import ButtonMenuHeader from "../buttonMenuHeader";
import DrawerBottom from "../drawerBottom";
import MenuItemRow from "../menuItemRow";
export default function HeaderRightBannerList() {
const [isVisible, setVisible] = useState(false)
const { colors } = useTheme()
return (
<>
<ButtonMenuHeader onPress={() => { setVisible(true) }} />
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={() => setVisible(false)} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<AntDesign name="pluscircle" color="black" size={25} />}
icon={<AntDesign name="pluscircleo" color={colors.text} size={25} />}
title="Tambah Banner"
onPress={() => {
setVisible(false)

View File

@@ -1,5 +1,6 @@
import { ColorsStatus } from "@/constants/ColorsStatus";
import Styles from "@/constants/Styles";
import { useTheme } from "@/providers/ThemeProvider";
import React, { useState } from "react";
import { Dimensions, Pressable, View } from "react-native";
import Text from "./Text";
@@ -16,7 +17,7 @@ type Props = {
leftBottomInfo?: React.ReactNode | string
rightBottomInfo?: React.ReactNode | string
titleWeight?: 'normal' | 'bold'
bgColor?: 'white' | 'transparent'
bgColor?: string
width?: number
descEllipsize?: boolean
textColor?: string,
@@ -26,8 +27,9 @@ type Props = {
export default function BorderBottomItem({ title, subtitle, icon, desc, onPress, onLongPress, rightTopInfo, borderType, leftBottomInfo, rightBottomInfo, titleWeight, bgColor, width, descEllipsize, textColor, colorPress, titleShowAll }: Props) {
const lebarDim = Dimensions.get("window").width;
const { colors } = useTheme();
const lebar = width ? lebarDim * width / 100 : 'auto';
const textColorFix = textColor ? textColor : 'black';
const textColorFix = textColor ? textColor : colors.text;
const [isTap, setIsTap] = useState(false);
@@ -37,13 +39,13 @@ export default function BorderBottomItem({ title, subtitle, icon, desc, onPress,
onPressOut={() => setIsTap(false)}
style={({ pressed }) => [
borderType == 'bottom'
? Styles.wrapItemBorderBottom
? [Styles.wrapItemBorderBottom, { borderBottomColor: colors.icon + '20' }]
: borderType == 'all'
? Styles.wrapItemBorderAll
? [Styles.wrapItemBorderAll, { borderColor: colors.icon + '20' }]
: Styles.wrapItemBorderNone,
bgColor && bgColor == 'white' && ColorsStatus.white,
bgColor == "transparent" ? { backgroundColor: 'transparent' } : { backgroundColor: colors.card },
// efek warna saat ditekan (sementara)
isTap && colorPress && ColorsStatus.pressedGray,
isTap && colorPress && { backgroundColor: colors.icon + '20' },
]}
>
<View style={[Styles.rowItemsCenter]}>
@@ -54,14 +56,14 @@ export default function BorderBottomItem({ title, subtitle, icon, desc, onPress,
{
subtitle &&
typeof subtitle == "string"
? <Text style={[Styles.textMediumNormal, { lineHeight: 15, color: textColorFix }]}>{subtitle}</Text>
? <Text style={[Styles.textMediumNormal, { lineHeight: 15, color: colors.dimmed }]}>{subtitle}</Text>
: <View style={{ alignItems: 'flex-start' }}>
{subtitle}
</View>
}
</View>
{
rightTopInfo && <Text style={[Styles.textInformation, Styles.mt05, { color: textColorFix }]}>{rightTopInfo}</Text>
rightTopInfo && <Text style={[Styles.textInformation, Styles.mt05, { color: colors.dimmed }]}>{rightTopInfo}</Text>
}
</View>
@@ -73,13 +75,13 @@ export default function BorderBottomItem({ title, subtitle, icon, desc, onPress,
<View style={[rightBottomInfo && !leftBottomInfo ? Styles.rowSpaceBetweenReverse : Styles.rowSpaceBetween, Styles.mt05]}>
{
typeof leftBottomInfo == 'string' ?
<Text style={[Styles.textInformation, Styles.cGray]}>{leftBottomInfo}</Text>
<Text style={[Styles.textInformation, { color: colors.dimmed }]}>{leftBottomInfo}</Text>
:
leftBottomInfo
}
{
typeof rightBottomInfo == 'string' ?
<Text style={[Styles.textInformation, Styles.cGray]}>{rightBottomInfo}</Text>
<Text style={[Styles.textInformation, {color: colors.dimmed }]}>{rightBottomInfo}</Text>
:
rightBottomInfo
}

View File

@@ -1,14 +1,18 @@
import { ColorsStatus } from "@/constants/ColorsStatus";
import { ConstEnv } from "@/constants/ConstEnv";
import { isImageFile } from "@/constants/FileExtensions";
import Styles from "@/constants/Styles";
import { Ionicons } from "@expo/vector-icons";
import { useTheme } from "@/providers/ThemeProvider";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import * as FileSystem from 'expo-file-system';
import { startActivityAsync } from 'expo-intent-launcher';
import * as Sharing from 'expo-sharing';
import React, { useState } from "react";
import { Alert, Dimensions, Platform, Pressable, View } from "react-native";
import { Dimensions, Platform, Pressable, View } from "react-native";
import { ScrollView } from "react-native-gesture-handler";
import ImageViewing from "react-native-image-viewing";
import * as mime from 'react-native-mime-types';
import Toast from "react-native-toast-message";
import Text from "./Text";
@@ -33,26 +37,48 @@ type Props = {
dataFile: { id: string; idStorage: string; name: string; extension: string }[]
}
type PropsFile = {
id: string;
idStorage: string;
name: string;
extension: string
}
export default function BorderBottomItem2({ title, subtitle, icon, desc, onPress, onLongPress, rightTopInfo, borderType, leftBottomInfo, rightBottomInfo, titleWeight, bgColor, width, descEllipsize, textColor, colorPress, titleShowAll, dataFile }: Props) {
const { colors } = useTheme();
const lebarDim = Dimensions.get("window").width;
const lebar = width ? lebarDim * width / 100 : 'auto';
const textColorFix = textColor ? textColor : 'black';
const textColorFix = textColor ? textColor : colors.text;
const [isTap, setIsTap] = useState(false);
const [loadingOpen, setLoadingOpen] = useState(false)
const [chooseFile, setChooseFile] = useState<PropsFile>()
const [preview, setPreview] = useState(false)
function handleChooseFile(item: PropsFile) {
setChooseFile(item)
setPreview(true)
}
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: PropsFile) => {
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',
{
@@ -61,89 +87,148 @@ export default function BorderBottomItem2({ title, subtitle, icon, desc, onPress
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);
Toast.show({
type: 'error',
text1: 'Tidak ada aplikasi yang dapat membuka file ini'
});
}
});
} catch (error) {
console.error('Error downloading or opening file:', error);
Toast.show({
type: 'error',
text1: 'Gagal membuka file',
text2: 'Silakan coba lagi nanti'
});
} finally {
setLoadingOpen(false);
}
};
return (
<Pressable onLongPress={onLongPress} onPress={onPress}
onPressIn={() => setIsTap(true)}
onPressOut={() => setIsTap(false)}
style={({ pressed }) => [
borderType == 'bottom'
? Styles.wrapItemBorderBottom
: borderType == 'all'
? Styles.wrapItemBorderAll
: Styles.wrapItemBorderNone,
bgColor && bgColor == 'white' && ColorsStatus.white,
// efek warna saat ditekan (sementara)
isTap && colorPress && ColorsStatus.pressedGray,
]}
>
<View style={[Styles.rowItemsCenter]}>
{icon}
<View style={[Styles.rowSpaceBetween, width ? { width: lebar } : { width: '88%' }]}>
<View style={[Styles.ml10, rightTopInfo ? { width: '70%' } : { width: '90%' }]}>
<Text style={[titleWeight == 'normal' ? Styles.textDefault : Styles.textDefaultSemiBold, { color: textColorFix }]} numberOfLines={titleShowAll ? 0 : 1} ellipsizeMode='tail'>{title}</Text>
<>
<Pressable onLongPress={onLongPress} onPress={onPress}
onPressIn={() => setIsTap(true)}
onPressOut={() => setIsTap(false)}
style={({ pressed }) => [
borderType == 'bottom'
? [Styles.wrapItemBorderBottom, { borderBottomColor: colors.icon + '20' }]
: borderType == 'all'
? [Styles.wrapItemBorderAll, { borderColor: colors.icon + '20' }]
: Styles.wrapItemBorderNone,
bgColor && bgColor == 'white' && { backgroundColor: colors.card },
// efek warna saat ditekan (sementara)
isTap && colorPress && ColorsStatus.pressedGray,
]}
>
<View style={[Styles.rowItemsCenter]}>
{icon}
<View style={[Styles.rowSpaceBetween, width ? { width: lebar } : { width: '88%' }]}>
<View style={[Styles.ml10, rightTopInfo ? { width: '70%' } : { width: '90%' }]}>
<Text style={[titleWeight == 'normal' ? Styles.textDefault : Styles.textDefaultSemiBold, { color: textColorFix }]} numberOfLines={titleShowAll ? 0 : 1} ellipsizeMode='tail'>{title}</Text>
{
subtitle &&
typeof subtitle == "string"
? <Text style={[Styles.textMediumNormal, { lineHeight: 15, color: textColorFix }]}>{subtitle}</Text>
: <View style={{ alignItems: 'flex-start' }}>
{subtitle}
</View>
}
</View>
{
subtitle &&
typeof subtitle == "string"
? <Text style={[Styles.textMediumNormal, { lineHeight: 15, color: textColorFix }]}>{subtitle}</Text>
: <View style={{ alignItems: 'flex-start' }}>
{subtitle}
</View>
rightTopInfo && <Text style={[Styles.textInformation, Styles.mt05, { color: textColorFix }]}>{rightTopInfo}</Text>
}
</View>
{
rightTopInfo && <Text style={[Styles.textInformation, Styles.mt05, { color: textColorFix }]}>{rightTopInfo}</Text>
}
</View>
</View>
{desc && <Text style={[Styles.textDefault, Styles.mt05, { textAlign: 'left', color: textColorFix }]} numberOfLines={descEllipsize == false ? 0 : 2} ellipsizeMode='tail'>{desc}</Text>}
{
dataFile.length > 0 && (
<ScrollView horizontal style={[Styles.mv05]} showsHorizontalScrollIndicator={false}>
{dataFile.map((item, index) => (
<Pressable
key={index}
style={[Styles.rowItemsCenter, Styles.borderAll, Styles.round10, Styles.ph05, Styles.pv03, Styles.mr05]}
onPress={() => { openFile({ idStorage: item.idStorage, name: item.name, extension: item.extension }) }}
>
<Ionicons name="document-text" size={18} color="grey" style={Styles.mr05} />
<Text style={[Styles.textInformation, Styles.cGray, Styles.mb05]}>{item.name}.{item.extension}</Text>
</Pressable>
))}
</ScrollView>
)
}
{
(leftBottomInfo || rightBottomInfo) &&
(
<View style={[rightBottomInfo && !leftBottomInfo ? Styles.rowSpaceBetweenReverse : Styles.rowSpaceBetween, Styles.mt05]}>
{
typeof leftBottomInfo == 'string' ?
<Text style={[Styles.textInformation, Styles.cGray]}>{leftBottomInfo}</Text>
:
leftBottomInfo
}
{
typeof rightBottomInfo == 'string' ?
<Text style={[Styles.textInformation, Styles.cGray]}>{rightBottomInfo}</Text>
:
rightBottomInfo
}
</View>
{desc && <Text style={[Styles.textDefault, Styles.mt05, { textAlign: 'left', color: textColorFix }]} numberOfLines={descEllipsize == false ? 0 : 2} ellipsizeMode='tail'>{desc}</Text>}
{
dataFile.length > 0 && (
<ScrollView horizontal style={[Styles.mv05]} showsHorizontalScrollIndicator={false}>
{dataFile.map((item, index) => (
<Pressable
key={index}
style={[Styles.rowItemsCenter, Styles.borderAll, Styles.round05, Styles.ph05, Styles.pv03, Styles.mr05, { borderColor: colors.icon }]}
onPress={() => {
isImageFile(item.extension) ?
handleChooseFile(item)
: openFile(item)
}}
>
<MaterialCommunityIcons
name={isImageFile(item.extension) ? "file-image-outline" : "file-document-outline"}
size={18}
color={colors.icon} />
<Text style={[Styles.textInformation]}>{item.name}.{item.extension}</Text>
</Pressable>
))}
</ScrollView>
)
}
{
(leftBottomInfo || rightBottomInfo) &&
(
<View style={[rightBottomInfo && !leftBottomInfo ? Styles.rowSpaceBetweenReverse : Styles.rowSpaceBetween, Styles.mt05]}>
{
typeof leftBottomInfo == 'string' ?
<Text style={[Styles.textInformation, Styles.cGray]}>{leftBottomInfo}</Text>
:
leftBottomInfo
}
{
typeof rightBottomInfo == 'string' ?
<Text style={[Styles.textInformation, Styles.cGray]}>{rightBottomInfo}</Text>
:
rightBottomInfo
}
</View>
)
}
</Pressable>
<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: 26 }}></Text>
</Pressable>
</View>
)
}
</Pressable>
)}
FooterComponent={({ imageIndex }) => (
<View style={{
paddingBottom: 20,
paddingHorizontal: 16,
alignItems: 'center',
}}>
<Text style={{ color: 'white', fontSize: 16 }}>{chooseFile?.name}.{chooseFile?.extension}</Text>
</View>
)}
/>
</>
)
}

View File

@@ -9,7 +9,7 @@ export default function ButtonBackHeader({ onPress }: Props) {
return (
<>
<ButtonHeader
item={<Feather name="chevron-left" size={20} color="white" />}
item={<Feather name="chevron-left" size={25} color="white" />}
onPress={() => { onPress && onPress() }}
/>
</>

View File

@@ -1,4 +1,5 @@
import Styles from "@/constants/Styles";
import { useTheme } from "@/providers/ThemeProvider";
import React from "react";
import { TouchableWithoutFeedback, View } from "react-native";
import Text from "./Text";
@@ -10,13 +11,14 @@ type Props = {
};
export function ButtonFiturMenu({ onPress, icon, text }: Props) {
const { colors } = useTheme();
return (
<TouchableWithoutFeedback onPress={onPress}>
<View style={{ alignItems: 'center' }}>
<View style={[Styles.btnFiturMenu]}>
<View style={[Styles.btnFiturMenu, { backgroundColor: colors.card, borderColor: colors.icon + '20', shadowColor: colors.text }]}>
{icon}
</View>
<Text style={[Styles.mt05]}>{text}</Text>
<Text style={[Styles.mt05, { color: colors.text }]}>{text}</Text>
</View>
</TouchableWithoutFeedback>
)

View File

@@ -9,7 +9,7 @@ export default function ButtonMenuHeader({ onPress }: Props) {
return (
<>
<ButtonHeader
item={<Feather name="menu" size={20} color="white" />}
item={<Feather name="menu" size={25} color="white" />}
onPress={() => onPress()}
/>
</>

View File

@@ -12,7 +12,7 @@ export default function ButtonSaveHeader({ category, onPress, disable }: Props)
return (
<>
<ButtonHeader
item={<Feather name="check" size={20} color={disable ? "grey" : "white"} />}
item={<Feather name="check" size={25} color={disable ? "grey" : "white"} />}
onPress={() => {
if (!disable) {
AlertKonfirmasi({

View File

@@ -1,4 +1,5 @@
import Styles from "@/constants/Styles";
import { useTheme } from "@/providers/ThemeProvider";
import { Feather } from "@expo/vector-icons";
import { Pressable, View } from "react-native";
import Text from "./Text";
@@ -12,12 +13,20 @@ type Props = {
}
export default function ButtonSelect({ value, onPress, round, error, errorText }: Props) {
const { colors } = useTheme();
return (
<View style={[Styles.mv05]}>
<Pressable onPress={onPress}>
<View style={[Styles.inputRoundForm, Styles.inputRoundFormRight, round && Styles.round30, Styles.pv10, error && { borderColor: "red" }]}>
<Feather name="arrow-right-circle" size={20} color="black" />
<Text style={[Styles.cBlack]}>{value}</Text>
<View style={[
Styles.inputRoundForm,
Styles.inputRoundFormRight,
round && Styles.round30,
Styles.pv10,
{ borderColor: colors.icon + '20', backgroundColor: colors.input },
error && { borderColor: "red" }
]}>
<Feather name="arrow-right-circle" size={20} color={colors.text} />
<Text style={[{ color: colors.text }]}>{value}</Text>
</View>
</Pressable>
{error && (<Text style={[Styles.textInformation, Styles.mt05, Styles.cError]}>{errorText}</Text>)}

View File

@@ -1,6 +1,6 @@
import { ColorsStatus } from "@/constants/ColorsStatus"
import Styles from "@/constants/Styles"
import { TouchableOpacity } from "react-native"
import Styles from "@/constants/Styles";
import { useTheme } from "@/providers/ThemeProvider";
import { TouchableOpacity } from "react-native";
import Text from "./Text";
type Props = {
@@ -14,10 +14,11 @@ type Props = {
export default function ButtonTab({ active, value, onPress, label, n, icon }: Props) {
const { colors } = useTheme();
return (
<TouchableOpacity style={[Styles.btnTab, (active == value) && ColorsStatus.orange, { width: n == 2 ? '50%' : 'auto' }]} onPress={() => { onPress() }}>
<TouchableOpacity style={[Styles.btnTab, (active == value) && { backgroundColor: colors.tabActive }, { width: n == 2 ? '50%' : 'auto' }]} onPress={() => { onPress() }}>
{icon}
<Text numberOfLines={1} style={[Styles.textMediumSemiBold, Styles.ml10, { color: active == value ? 'white' : 'black' }]}>{label}</Text>
<Text numberOfLines={1} style={[Styles.textMediumSemiBold, Styles.ml10, { color: active == value ? 'white' : colors.dimmed }]}>{label}</Text>
</TouchableOpacity>
)
}

View File

@@ -2,6 +2,7 @@ import Styles from "@/constants/Styles"
import { apiDeleteCalendar } from "@/lib/api"
import { setUpdateCalendar } from "@/lib/calendarUpdate"
import { useAuthSession } from "@/providers/AuthProvider"
import { useTheme } from "@/providers/ThemeProvider"
import { Ionicons, MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons"
import { router } from "expo-router"
import { useState } from "react"
@@ -19,6 +20,7 @@ type Props = {
}
export default function HeaderRightCalendarDetail({ id, idReminder }: Props) {
const { colors } = useTheme()
const [isVisible, setVisible] = useState(false)
const { token, decryptToken } = useAuthSession()
const update = useSelector((state: any) => state.calendarUpdate)
@@ -49,7 +51,7 @@ export default function HeaderRightCalendarDetail({ id, idReminder }: Props) {
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={setVisible} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<MaterialIcons name="groups" color="black" size={25} />}
icon={<MaterialCommunityIcons name="account-group-outline" color={colors.text} size={25} />}
title="Tambah Anggota"
onPress={() => {
setVisible(false)
@@ -57,7 +59,7 @@ export default function HeaderRightCalendarDetail({ id, idReminder }: Props) {
}}
/>
<MenuItemRow
icon={<MaterialCommunityIcons name="pencil-outline" color="black" size={25} />}
icon={<MaterialCommunityIcons name="pencil-outline" color={colors.text} size={25} />}
title="Edit"
onPress={() => {
setVisible(false)
@@ -65,7 +67,7 @@ export default function HeaderRightCalendarDetail({ id, idReminder }: Props) {
}}
/>
<MenuItemRow
icon={<Ionicons name="trash" color="black" size={25} />}
icon={<Ionicons name="trash-outline" color={colors.text} size={25} />}
title="Hapus"
onPress={() => {
setVisible(false)

View File

@@ -1,6 +1,7 @@
import Styles from "@/constants/Styles"
import { apiGetDivisionOneFeature } from "@/lib/api"
import { useAuthSession } from "@/providers/AuthProvider"
import { useTheme } from "@/providers/ThemeProvider"
import { AntDesign, MaterialCommunityIcons } from "@expo/vector-icons"
import { router, useLocalSearchParams } from "expo-router"
import { useEffect, useState } from "react"
@@ -11,6 +12,7 @@ import DrawerBottom from "../drawerBottom"
import MenuItemRow from "../menuItemRow"
export default function HeaderRightCalendarList() {
const { colors } = useTheme()
const [isVisible, setVisible] = useState(false)
const { token, decryptToken } = useAuthSession()
const { id } = useLocalSearchParams<{ id: string }>();
@@ -47,7 +49,7 @@ export default function HeaderRightCalendarList() {
<></>
) : (
<MenuItemRow
icon={<AntDesign name="pluscircle" color="black" size={25} />}
icon={<AntDesign name="pluscircleo" color={colors.text} size={25} />}
title="Tambah Acara"
onPress={() => {
setVisible(false)
@@ -57,7 +59,7 @@ export default function HeaderRightCalendarList() {
)
}
<MenuItemRow
icon={<MaterialCommunityIcons name="history" color="black" size={25} />}
icon={<MaterialCommunityIcons name="history" color={colors.text} size={25} />}
title="Riwayat"
onPress={() => {
setVisible(false)

View File

@@ -1,4 +1,5 @@
import Styles from "@/constants/Styles";
import { useTheme } from "@/providers/ThemeProvider";
import { Pressable, View } from "react-native";
import Text from "../Text";
@@ -11,10 +12,11 @@ type Props = {
export default function ItemDateCalendar({ text, isSelected, isSign, onPress }: Props) {
const { colors } = useTheme()
return (
<>
<Pressable style={{ alignItems: 'center' }} onPress={onPress}>
<Text style={[isSelected ? Styles.cWhite : Styles.cBlack]}>{text}</Text>
<Text style={[isSelected ? Styles.cWhite : { color: colors.text }]}>{text}</Text>
<View style={[Styles.signDate, { backgroundColor: isSign ? 'red' : 'transparent' }]}></View>
</Pressable>
</>

View File

@@ -1,5 +1,6 @@
import { ColorsStatus } from "@/constants/ColorsStatus";
import Styles from "@/constants/Styles";
import { useTheme } from "@/providers/ThemeProvider";
import { View } from "react-native";
import Text from "../Text";
@@ -14,12 +15,13 @@ type Props = {
}[]
export default function ItemHistoryEvent({ data }: { data: Props }) {
const { colors, activeTheme } = useTheme()
return (
<>
{
data.length > 0 ? (
data.map((item, index) => (
<View key={index} style={[{ flexDirection: 'row' }, Styles.mv05, ColorsStatus.lightGreen, Styles.p10, Styles.round10]}>
<View key={index} style={[{ flexDirection: 'row' }, Styles.mv05, activeTheme === 'dark' ? { backgroundColor: colors.card } : ColorsStatus.lightGreen, Styles.p10, Styles.round05, { borderBottomWidth: 1, borderColor: colors.background }]}>
<View style={[Styles.mr10, Styles.ph05]}>
<Text style={[Styles.textSubtitle]}>{String(item.dateStart)}</Text>
<Text style={[Styles.textDefault, { textAlign: 'center' }]}>{item.year}</Text>

View File

@@ -2,6 +2,7 @@ import Styles from "@/constants/Styles"
import { apiArchiveDiscussion, apiOpenCloseDiscussion } from "@/lib/api"
import { setUpdateDiscussion } from "@/lib/discussionUpdate"
import { useAuthSession } from "@/providers/AuthProvider"
import { useTheme } from "@/providers/ThemeProvider"
import { MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons"
import { router } from "expo-router"
import { useState } from "react"
@@ -20,6 +21,7 @@ type Props = {
}
export default function HeaderRightDiscussionDetail({ id, status, isActive }: Props) {
const { colors } = useTheme()
const [isVisible, setVisible] = useState(false)
const { token, decryptToken } = useAuthSession()
const update = useSelector((state: any) => state.discussionUpdate)
@@ -72,7 +74,7 @@ export default function HeaderRightDiscussionDetail({ id, status, isActive }: Pr
isActive &&
<>
<MenuItemRow
icon={<MaterialCommunityIcons name="pencil-outline" color="black" size={25} />}
icon={<MaterialCommunityIcons name="pencil-outline" color={colors.text} size={25} />}
title="Edit"
onPress={() => {
setVisible(false)
@@ -80,7 +82,7 @@ export default function HeaderRightDiscussionDetail({ id, status, isActive }: Pr
}}
/>
<MenuItemRow
icon={<MaterialIcons name={status == 1 ? 'close' : 'check'} color="black" size={25} />}
icon={<MaterialIcons name={status == 1 ? 'close' : 'check'} color={colors.text} size={25} />}
title={status == 1 ? 'Tutup Diskusi' : 'Buka Diskusi'}
onPress={() => {
setVisible(false)
@@ -96,7 +98,7 @@ export default function HeaderRightDiscussionDetail({ id, status, isActive }: Pr
</>
}
<MenuItemRow
icon={<MaterialCommunityIcons name="archive-outline" color="black" size={25} />}
icon={<MaterialCommunityIcons name="archive-outline" color={colors.text} size={25} />}
title={isActive ? 'Arsipkan' : 'Aktifkan Diskusi'}
onPress={() => {
setVisible(false)

View File

@@ -1,6 +1,7 @@
import Styles from "@/constants/Styles"
import { apiGetDivisionOneFeature } from "@/lib/api"
import { useAuthSession } from "@/providers/AuthProvider"
import { useTheme } from "@/providers/ThemeProvider"
import { AntDesign } from "@expo/vector-icons"
import { router, useLocalSearchParams } from "expo-router"
import { useEffect, useState } from "react"
@@ -11,6 +12,7 @@ import DrawerBottom from "../drawerBottom"
import MenuItemRow from "../menuItemRow"
export default function HeaderRightDiscussionList() {
const { colors } = useTheme()
const [isVisible, setVisible] = useState(false)
const [isAdminDivision, setIsAdminDivision] = useState(false);
const { token, decryptToken } = useAuthSession()
@@ -45,7 +47,7 @@ export default function HeaderRightDiscussionList() {
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={setVisible} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<AntDesign name="pluscircle" color="black" size={25} />}
icon={<AntDesign name="pluscircleo" color={colors.text} size={25} />}
title="Tambah Diskusi"
onPress={() => {
setVisible(false)

View File

@@ -1,4 +1,5 @@
import Styles from "@/constants/Styles";
import { useTheme } from "@/providers/ThemeProvider";
import { Feather, Ionicons } from "@expo/vector-icons";
import { Pressable, View } from "react-native";
import Text from "./Text";
@@ -11,22 +12,23 @@ type Props = {
}
export default function DiscussionItem({ title, user, date, onPress }: Props) {
const { colors } = useTheme();
return (
<Pressable style={[Styles.wrapItemDiscussion]} onPress={onPress}>
<Pressable style={[Styles.wrapItemDiscussion, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]} onPress={onPress}>
<View style={[Styles.rowItemsCenter, Styles.mb10]}>
<Ionicons name="chatbox-ellipses-outline" size={22} color="black" style={Styles.mr10} />
<Ionicons name="chatbox-ellipses-outline" size={22} color={colors.text} style={Styles.mr10} />
<View style={[{ flex: 1 }]}>
<Text style={{ fontWeight: 'bold' }} numberOfLines={1} ellipsizeMode="tail">{title}</Text>
</View>
</View>
<View style={[Styles.rowSpaceBetween]}>
<View style={[Styles.rowItemsCenter, { flex: 1 }]}>
<Feather name="user" size={18} color="grey" style={Styles.mr05} />
<Text style={[Styles.textInformation]} numberOfLines={1} ellipsizeMode="tail">{user}</Text>
<Feather name="user" size={18} color={colors.dimmed} style={Styles.mr05} />
<Text style={[Styles.textInformation, { color: colors.dimmed }]} numberOfLines={1} ellipsizeMode="tail">{user}</Text>
</View>
<View style={[Styles.rowItemsCenter, { flex: 1, justifyContent: 'flex-end' }]}>
<Feather name="clock" size={18} color="grey" style={Styles.mr05} />
<Text style={[Styles.textInformation]}>{date}</Text>
<Feather name="clock" size={18} color={colors.dimmed} style={Styles.mr05} />
<Text style={[Styles.textInformation, { color: colors.dimmed }]}>{date}</Text>
</View>
</View>
</Pressable>

View File

@@ -2,6 +2,7 @@ import Styles from "@/constants/Styles"
import { apiDeleteDiscussionGeneral, apiUpdateStatusDiscussionGeneral } from "@/lib/api"
import { setUpdateDiscussionGeneralDetail } from "@/lib/discussionGeneralDetail"
import { useAuthSession } from "@/providers/AuthProvider"
import { useTheme } from "@/providers/ThemeProvider"
import { MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons"
import { router } from "expo-router"
import { useState } from "react"
@@ -21,6 +22,7 @@ type Props = {
export default function HeaderRightDiscussionGeneralDetail({ id, active, status }: Props) {
const { token, decryptToken } = useAuthSession()
const { colors } = useTheme();
const [isVisible, setVisible] = useState(false)
const entityUser = useSelector((state: any) => state.user)
const dispatch = useDispatch()
@@ -59,7 +61,7 @@ export default function HeaderRightDiscussionGeneralDetail({ id, active, status
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={setVisible} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<MaterialIcons name="groups" color="black" size={25} />}
icon={<MaterialCommunityIcons name="account-group-outline" color={colors.text} size={25} />}
title="Anggota"
onPress={() => {
setVisible(false)
@@ -74,7 +76,7 @@ export default function HeaderRightDiscussionGeneralDetail({ id, active, status
(
<>
<MenuItemRow
icon={<MaterialCommunityIcons name="pencil-outline" color="black" size={25} />}
icon={<MaterialCommunityIcons name="pencil-outline" color={colors.text} size={25} />}
title="Edit"
onPress={() => {
setVisible(false)
@@ -82,7 +84,7 @@ export default function HeaderRightDiscussionGeneralDetail({ id, active, status
}}
/>
<MenuItemRow
icon={<MaterialIcons name="close" color="black" size={25} />}
icon={<MaterialIcons name="close" color={colors.text} size={25} />}
title={status == 1 ? 'Tutup Diskusi' : 'Buka Diskusi'}
onPress={() => {
setVisible(false)
@@ -99,7 +101,7 @@ export default function HeaderRightDiscussionGeneralDetail({ id, active, status
)
:
<MenuItemRow
icon={<MaterialCommunityIcons name="archive-outline" color="black" size={25} />}
icon={<MaterialCommunityIcons name="archive-outline" color={colors.text} size={25} />}
title="Aktifkan Diskusi"
onPress={() => {
setVisible(false)
@@ -119,7 +121,7 @@ export default function HeaderRightDiscussionGeneralDetail({ id, active, status
entityUser.role != "user" && entityUser.role != "coadmin" && active &&
<View style={[Styles.rowItemsCenter, Styles.mt15]}>
<MenuItemRow
icon={<MaterialCommunityIcons name="archive-outline" color="black" size={25} />}
icon={<MaterialCommunityIcons name="archive-outline" color={colors.text} size={25} />}
title="Arsipkan"
onPress={() => {
setVisible(false)

View File

@@ -1,4 +1,5 @@
import Styles from "@/constants/Styles"
import { useTheme } from "@/providers/ThemeProvider"
import { AntDesign } from "@expo/vector-icons"
import { router } from "expo-router"
import { useState } from "react"
@@ -10,6 +11,7 @@ import MenuItemRow from "../menuItemRow"
import ModalFilter from "../modalFilter"
export default function HeaderDiscussionGeneral() {
const { colors } = useTheme();
const [isVisible, setVisible] = useState(false)
const [isFilter, setFilter] = useState(false)
const entityUser = useSelector((state: any) => state.user)
@@ -23,7 +25,7 @@ export default function HeaderDiscussionGeneral() {
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={setVisible} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<AntDesign name="pluscircle" color="black" size={25} />}
icon={<AntDesign name="pluscircleo" color={colors.text} size={25} />}
title="Tambah Diskusi"
onPress={() => {
setVisible(false)
@@ -33,7 +35,7 @@ export default function HeaderDiscussionGeneral() {
{
(entityUser.role == 'supadmin' || entityUser.role == 'developer') &&
<MenuItemRow
icon={<AntDesign name="filter" color="black" size={25} />}
icon={<AntDesign name="filter" color={colors.text} size={25} />}
title="Filter"
onPress={() => {
setVisible(false)

View File

@@ -1,6 +1,7 @@
import Styles from "@/constants/Styles";
import { apiGetDivisionOneFeature } from "@/lib/api";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { router, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
import { View } from "react-native";
@@ -17,6 +18,7 @@ type Props = {
};
export default function DiscussionDivisionDetail({ refreshing }: { refreshing: boolean }) {
const { colors } = useTheme();
const { token, decryptToken } = useAuthSession();
const { id } = useLocalSearchParams<{ id: string }>();
const [data, setData] = useState<Props[]>([]);
@@ -48,12 +50,11 @@ export default function DiscussionDivisionDetail({ refreshing }: { refreshing: b
handleLoad(true)
}, [])
return (
<View style={[Styles.mb15]}>
<Text style={[Styles.textDefaultSemiBold, Styles.mv10]}>Diskusi</Text>
<View style={[Styles.wrapPaper]}>
<View style={[Styles.wrapPaper, { backgroundColor: colors.card, borderColor: colors.icon + '20' }, Styles.p0]}>
{
loading ?
<>

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