## Perubahan Tampilan Admin
### File Baru (4) - `screens/Admin/Voting/ScreenVotingStatus.tsx` - `screens/Admin/Voting/ScreenVotingHistory.tsx` - `screens/Admin/Voting/ScreenEventTypeOfEvent.tsx` - `screens/Admin/Voting/BoxVotingStatus.tsx` ### File Diubah (3) - `app/(application)/admin/voting/[status]/status.tsx` → 5 baris - `app/(application)/admin/voting/history.tsx` → 5 baris - `app/(application)/admin/event/type-of-event.tsx` → 5 baris ### API Updates (2) - `service/api-admin/api-admin-voting.ts` → tambah param `page` - `service/api-admin/api-master-admin.ts` → tambah param `page` ## Fitur Baru - Pagination (infinite scroll) - Pull-to-Refresh - Skeleton Loading - Empty State - Search Functionality ### No Issue"
This commit is contained in:
169
QWEN.md
169
QWEN.md
@@ -35,6 +35,7 @@ hipmi-mobile/
|
|||||||
│ └── ...
|
│ └── ...
|
||||||
├── assets/ # Images, icons, and static assets
|
├── assets/ # Images, icons, and static assets
|
||||||
├── constants/ # Constants and configuration values
|
├── constants/ # Constants and configuration values
|
||||||
|
├── helpers/ # Helper functions (pagination, etc.)
|
||||||
├── hooks/ # Custom React hooks
|
├── hooks/ # Custom React hooks
|
||||||
├── lib/ # Utility libraries
|
├── lib/ # Utility libraries
|
||||||
├── navigation/ # Navigation configuration
|
├── navigation/ # Navigation configuration
|
||||||
@@ -49,6 +50,8 @@ hipmi-mobile/
|
|||||||
- Node.js (with bun as the package manager)
|
- Node.js (with bun as the package manager)
|
||||||
- Expo CLI
|
- Expo CLI
|
||||||
- iOS Simulator or Android Emulator (for native builds)
|
- iOS Simulator or Android Emulator (for native builds)
|
||||||
|
- Android Studio (for Android builds)
|
||||||
|
- Xcode (for iOS builds, macOS only)
|
||||||
|
|
||||||
### Setup and Development
|
### Setup and Development
|
||||||
|
|
||||||
@@ -76,28 +79,79 @@ hipmi-mobile/
|
|||||||
bun run lint
|
bun run lint
|
||||||
```
|
```
|
||||||
|
|
||||||
### Environment Variables
|
### Build Commands
|
||||||
The application uses environment variables defined in the app.config.js file:
|
|
||||||
|
#### EAS Build (Production)
|
||||||
|
```bash
|
||||||
|
# Production build
|
||||||
|
eas build --profile production
|
||||||
|
|
||||||
|
# Preview build
|
||||||
|
eas build --profile preview
|
||||||
|
|
||||||
|
# Development build
|
||||||
|
eas build --profile development
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Local Native Builds
|
||||||
|
```bash
|
||||||
|
# Generate native folders (iOS & Android)
|
||||||
|
npx expo prebuild
|
||||||
|
|
||||||
|
# iOS specific
|
||||||
|
bunx expo prebuild --platform ios
|
||||||
|
open ios/HIPMIBADUNG.xcworkspace
|
||||||
|
|
||||||
|
# Android specific
|
||||||
|
bunx expo prebuild --platform android
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Version Management
|
||||||
|
```bash
|
||||||
|
# Patch version update
|
||||||
|
npm version patch
|
||||||
|
```
|
||||||
|
|
||||||
|
### Android Debugging
|
||||||
|
```bash
|
||||||
|
# List connected devices
|
||||||
|
adb devices
|
||||||
|
|
||||||
|
# Install APK to device/emulator
|
||||||
|
adb install android/app/build/outputs/apk/debug/app-debug.apk
|
||||||
|
|
||||||
|
# Install to specific device
|
||||||
|
adb -s <device_id> install android/app/build/outputs/apk/debug/app-debug.apk
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
The application uses environment variables defined in the `app.config.js` file:
|
||||||
- `API_BASE_URL`: Base URL for API endpoints
|
- `API_BASE_URL`: Base URL for API endpoints
|
||||||
- `BASE_URL`: Base application URL
|
- `BASE_URL`: Base application URL
|
||||||
- `DEEP_LINK_URL`: URL for deep linking functionality
|
- `DEEP_LINK_URL`: URL for deep linking functionality
|
||||||
|
|
||||||
### EAS Build Configuration
|
Create a `.env` file in the project root with these variables.
|
||||||
|
|
||||||
|
## EAS Build Configuration
|
||||||
|
|
||||||
The project uses Expo Application Services (EAS) for building and deploying:
|
The project uses Expo Application Services (EAS) for building and deploying:
|
||||||
- Development builds with development client
|
- **Development**: Development builds with development client
|
||||||
- Preview builds for internal distribution
|
- **Preview**: Internal distribution builds (APK for Android)
|
||||||
- Production builds for app stores
|
- **Production**: App store builds (App Bundle for Android, IPA for iOS)
|
||||||
|
|
||||||
|
Configuration is in `eas.json`.
|
||||||
|
|
||||||
## Features and Functionality
|
## Features and Functionality
|
||||||
|
|
||||||
The application appears to include several key modules:
|
The application includes several key modules:
|
||||||
- **Authentication**: Login, registration, and verification flows
|
- **Authentication**: Login with phone number, OTP verification, registration, terms acceptance
|
||||||
- **Admin Panel**: Administrative functions
|
- **Admin Panel**: Administrative functions for managing content and users
|
||||||
- **Collaboration**: Tools for member collaboration
|
- **Collaboration**: Tools for member collaboration
|
||||||
- **Events**: Event management and calendar
|
- **Events**: Event management and calendar
|
||||||
- **Forum**: Discussion forums
|
- **Forum**: Discussion forums
|
||||||
- **Maps**: Location-based services with Mapbox integration
|
- **Maps**: Location-based services with Mapbox integration
|
||||||
- **Donations**: Donation functionality
|
- **Donations**: Donation functionality with fund disbursement tracking
|
||||||
- **Job Board**: Employment opportunities
|
- **Job Board**: Employment opportunities
|
||||||
- **Investment**: Investment-related features
|
- **Investment**: Investment-related features
|
||||||
- **Voting**: Voting systems
|
- **Voting**: Voting systems
|
||||||
@@ -109,18 +163,50 @@ The application appears to include several key modules:
|
|||||||
### Coding Standards
|
### Coding Standards
|
||||||
- TypeScript is used throughout the project for type safety
|
- TypeScript is used throughout the project for type safety
|
||||||
- Component-based architecture with reusable components
|
- Component-based architecture with reusable components
|
||||||
- Context API for state management
|
- Context API for state management (AuthContext)
|
||||||
- File-based routing with Expo Router
|
- File-based routing with Expo Router
|
||||||
- Consistent naming conventions using camelCase for variables and PascalCase for components
|
- Consistent naming conventions using camelCase for variables and PascalCase for components
|
||||||
|
- Path aliases: `@/*` maps to project root
|
||||||
|
|
||||||
|
### Architecture Patterns
|
||||||
|
|
||||||
|
#### Screen Components
|
||||||
|
- Screen components are stored in `/screens` directory organized by feature
|
||||||
|
- Route files in `/app` import and use screen components
|
||||||
|
- Example pattern:
|
||||||
|
```tsx
|
||||||
|
// app/some-route.tsx
|
||||||
|
import SomeScreen from "@/screens/Feature/ScreenSome";
|
||||||
|
|
||||||
|
export default function SomeRoute() {
|
||||||
|
return <SomeScreen />;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Wrapper Components
|
||||||
|
- `NewWrapper` component is used for consistent screen layouts
|
||||||
|
- Located at `components/_ShareComponent/NewWrapper.tsx`
|
||||||
|
|
||||||
|
#### Pagination Pattern
|
||||||
|
- Use `hooks/use-pagination.tsx` and `helpers/paginationHelpers.tsx`
|
||||||
|
- Helper functions: `createSkeletonList`, `createEmptyState`, `createLoadingFooter`, `createPaginationComponents`
|
||||||
|
- API functions should accept `page` parameter (default: "1")
|
||||||
|
|
||||||
|
### API Service Structure
|
||||||
|
- Base API configuration: `service/api-config.ts`
|
||||||
|
- Client APIs: `service/api-client/`
|
||||||
|
- Admin APIs: `service/api-admin/`
|
||||||
|
- All API calls use axios with interceptors for auth token injection
|
||||||
|
|
||||||
### Testing
|
### Testing
|
||||||
- Linting is configured with ESLint
|
- Linting is configured with ESLint
|
||||||
- Standard Expo linting configuration is used
|
- Standard Expo linting configuration
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
- Firebase is integrated for authentication and messaging
|
- Firebase is integrated for authentication and messaging
|
||||||
- Camera and location permissions are properly configured
|
- Camera and location permissions are properly configured
|
||||||
- Deep linking is secured with app domain associations
|
- Deep linking is secured with app domain associations
|
||||||
|
- Auth tokens stored in AsyncStorage
|
||||||
|
|
||||||
## Key Dependencies
|
## Key Dependencies
|
||||||
|
|
||||||
@@ -133,6 +219,9 @@ The application appears to include several key modules:
|
|||||||
- `react-native-toast-message`: Toast notifications
|
- `react-native-toast-message`: Toast notifications
|
||||||
- `react-native-otp-entry`: OTP input components
|
- `react-native-otp-entry`: OTP input components
|
||||||
- `react-native-qrcode-svg`: QR code generation
|
- `react-native-qrcode-svg`: QR code generation
|
||||||
|
- `axios`: HTTP client for API calls
|
||||||
|
- `lodash`: Utility library
|
||||||
|
- `moti`: Animation library
|
||||||
|
|
||||||
### Development Dependencies
|
### Development Dependencies
|
||||||
- `@types/*`: TypeScript type definitions
|
- `@types/*`: TypeScript type definitions
|
||||||
@@ -142,28 +231,52 @@ The application appears to include several key modules:
|
|||||||
## Platform Support
|
## Platform Support
|
||||||
|
|
||||||
The application is configured to support:
|
The application is configured to support:
|
||||||
- **iOS**: With tablet support and proper permissions
|
- **iOS**:
|
||||||
- **Android**: With adaptive icons and intent filters for deep linking
|
- Bundle identifier: `com.anonymous.hipmi-mobile`
|
||||||
|
- Supports tablets
|
||||||
|
- Build number: 21
|
||||||
|
- Google Services integration
|
||||||
|
- Associated domains for deep linking
|
||||||
|
- **Android**:
|
||||||
|
- Package name: `com.bip.hipmimobileapp`
|
||||||
|
- Version code: 4
|
||||||
|
- Adaptive icons
|
||||||
|
- Edge-to-edge display enabled
|
||||||
|
- Intent filters for HTTPS deep linking
|
||||||
- **Web**: Static output configuration for web deployment
|
- **Web**: Static output configuration for web deployment
|
||||||
|
|
||||||
## Special Configurations
|
## Special Configurations
|
||||||
|
|
||||||
### iOS Configuration
|
### Deep Linking
|
||||||
- Bundle identifier: `com.anonymous.hipmi-mobile`
|
- Scheme: `hipmimobile://`
|
||||||
- Supports tablets
|
- Associated domains: `applinks:cld-dkr-staging-hipmi.wibudev.com`
|
||||||
- Google Services integration
|
- Configured for both iOS and Android
|
||||||
- Location permission handling
|
|
||||||
- Associated domains for deep linking
|
|
||||||
|
|
||||||
### Android Configuration
|
|
||||||
- Package name: `com.bip.hipmimobileapp`
|
|
||||||
- Adaptive icons
|
|
||||||
- Edge-to-edge display enabled
|
|
||||||
- Intent filters for HTTPS deep linking
|
|
||||||
- Google Services integration
|
|
||||||
|
|
||||||
### Maps Integration
|
### Maps Integration
|
||||||
The application uses Mapbox for mapping functionality with the `@rnmapbox/maps` plugin.
|
The application uses Mapbox for mapping functionality with the `@rnmapbox/maps` plugin.
|
||||||
|
|
||||||
### Push Notifications
|
### Push Notifications
|
||||||
Firebase Cloud Messaging is integrated for push notifications with proper configuration for both iOS and Android platforms.
|
Firebase Cloud Messaging is integrated for push notifications with proper configuration for both iOS and Android platforms.
|
||||||
|
|
||||||
|
### Camera
|
||||||
|
Camera permissions configured for both iOS and Android with microphone access for recording.
|
||||||
|
|
||||||
|
## Common Development Tasks
|
||||||
|
|
||||||
|
### Adding a New Screen
|
||||||
|
1. Create screen component in appropriate `/screens` subdirectory
|
||||||
|
2. Add route in `/app` directory if needed
|
||||||
|
3. Configure navigation in `AppRoot.tsx` if custom header is needed
|
||||||
|
|
||||||
|
### Adding API Endpoint
|
||||||
|
1. Add function in appropriate service file (`service/api-client/` or `service/api-admin/`)
|
||||||
|
2. Use `apiConfig` axios instance for requests
|
||||||
|
3. Include proper error handling
|
||||||
|
|
||||||
|
### Refactoring Pattern (from docs/prompt-for-qwen-code.md)
|
||||||
|
When moving code from route files to screen components:
|
||||||
|
1. Create new file in `screens/<Feature>/` directory
|
||||||
|
2. Rename function with prefix (e.g., `Admin_`, `Donation_`)
|
||||||
|
3. Use `NewWrapper` component for consistent layout
|
||||||
|
4. Apply pagination helpers if displaying lists
|
||||||
|
5. Import and call from original route file
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export default {
|
|||||||
"Aplikasi membutuhkan akses lokasi untuk menampilkan peta.",
|
"Aplikasi membutuhkan akses lokasi untuk menampilkan peta.",
|
||||||
},
|
},
|
||||||
associatedDomains: ["applinks:cld-dkr-staging-hipmi.wibudev.com"],
|
associatedDomains: ["applinks:cld-dkr-staging-hipmi.wibudev.com"],
|
||||||
buildNumber: "20",
|
buildNumber: "21",
|
||||||
},
|
},
|
||||||
|
|
||||||
android: {
|
android: {
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
import {
|
import {
|
||||||
ButtonCustom,
|
ButtonCustom,
|
||||||
DrawerCustom,
|
DrawerCustom,
|
||||||
DummyLandscapeImage,
|
DummyLandscapeImage,
|
||||||
LoaderCustom,
|
LoaderCustom,
|
||||||
Spacing,
|
Spacing,
|
||||||
StackCustom,
|
StackCustom,
|
||||||
TextCustom,
|
TextCustom,
|
||||||
} from "@/components";
|
} from "@/components";
|
||||||
import LeftButtonCustom from "@/components/Button/BackButton";
|
import LeftButtonCustom from "@/components/Button/BackButton";
|
||||||
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
||||||
@@ -49,7 +49,7 @@ export default function Portofolio() {
|
|||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
onLoadData(id as string);
|
onLoadData(id as string);
|
||||||
onLoadUserByToken();
|
onLoadUserByToken();
|
||||||
}, [id])
|
}, [id]),
|
||||||
);
|
);
|
||||||
|
|
||||||
async function onLoadData(id: string) {
|
async function onLoadData(id: string) {
|
||||||
@@ -144,27 +144,27 @@ export default function Portofolio() {
|
|||||||
<GridTwoView
|
<GridTwoView
|
||||||
spanLeft={2}
|
spanLeft={2}
|
||||||
spanRight={10}
|
spanRight={10}
|
||||||
leftIcon={
|
leftItem={
|
||||||
<FontAwesome
|
<FontAwesome
|
||||||
name="building-o"
|
name="building-o"
|
||||||
size={ICON_SIZE_SMALL}
|
size={ICON_SIZE_SMALL}
|
||||||
color="white"
|
color="white"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
rightIcon={<TextCustom>{data?.BusinessMaps?.namePin}</TextCustom>}
|
rightItem={<TextCustom>{data?.BusinessMaps?.namePin}</TextCustom>}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<GridTwoView
|
<GridTwoView
|
||||||
spanLeft={2}
|
spanLeft={2}
|
||||||
spanRight={10}
|
spanRight={10}
|
||||||
leftIcon={
|
leftItem={
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="list-outline"
|
name="list-outline"
|
||||||
size={ICON_SIZE_SMALL}
|
size={ICON_SIZE_SMALL}
|
||||||
color="white"
|
color="white"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
rightIcon={
|
rightItem={
|
||||||
<TextCustom>{data?.MasterBidangBisnis?.name}</TextCustom>
|
<TextCustom>{data?.MasterBidangBisnis?.name}</TextCustom>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@@ -172,26 +172,26 @@ export default function Portofolio() {
|
|||||||
<GridTwoView
|
<GridTwoView
|
||||||
spanLeft={2}
|
spanLeft={2}
|
||||||
spanRight={10}
|
spanRight={10}
|
||||||
leftIcon={
|
leftItem={
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="call-outline"
|
name="call-outline"
|
||||||
size={ICON_SIZE_SMALL}
|
size={ICON_SIZE_SMALL}
|
||||||
color="white"
|
color="white"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
rightIcon={<TextCustom>{data?.tlpn}</TextCustom>}
|
rightItem={<TextCustom>{data?.tlpn}</TextCustom>}
|
||||||
/>
|
/>
|
||||||
<GridTwoView
|
<GridTwoView
|
||||||
spanLeft={2}
|
spanLeft={2}
|
||||||
spanRight={10}
|
spanRight={10}
|
||||||
leftIcon={
|
leftItem={
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="location-outline"
|
name="location-outline"
|
||||||
size={ICON_SIZE_SMALL}
|
size={ICON_SIZE_SMALL}
|
||||||
color="white"
|
color="white"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
rightIcon={<TextCustom>{data?.alamatKantor}</TextCustom>}
|
rightItem={<TextCustom>{data?.alamatKantor}</TextCustom>}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Spacing />
|
<Spacing />
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
import {
|
import {
|
||||||
BaseBox,
|
BaseBox,
|
||||||
BoxButtonOnFooter,
|
BoxButtonOnFooter,
|
||||||
ButtonCustom,
|
ButtonCustom,
|
||||||
Grid,
|
Grid,
|
||||||
StackCustom,
|
StackCustom,
|
||||||
TextCustom,
|
TextCustom,
|
||||||
ViewWrapper,
|
ViewWrapper,
|
||||||
} from "@/components";
|
} from "@/components";
|
||||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||||
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
||||||
@@ -22,7 +22,7 @@ export default function AdminCollaborationPublish() {
|
|||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
handlerLoadData();
|
handlerLoadData();
|
||||||
}, [status])
|
}, [status]),
|
||||||
);
|
);
|
||||||
|
|
||||||
const handlerLoadData = async () => {
|
const handlerLoadData = async () => {
|
||||||
@@ -78,16 +78,16 @@ export default function AdminCollaborationPublish() {
|
|||||||
</StackCustom>
|
</StackCustom>
|
||||||
</BaseBox>
|
</BaseBox>
|
||||||
|
|
||||||
{data?.report && (
|
{data?.report && (
|
||||||
<BaseBox>
|
<BaseBox>
|
||||||
<GridTwoView
|
<GridTwoView
|
||||||
spanLeft={4}
|
spanLeft={4}
|
||||||
spanRight={8}
|
spanRight={8}
|
||||||
leftIcon={<TextCustom bold>Catatan report</TextCustom>}
|
leftItem={<TextCustom bold>Catatan report</TextCustom>}
|
||||||
rightIcon={<TextCustom>{data?.report}</TextCustom>}
|
rightItem={<TextCustom>{data?.report}</TextCustom>}
|
||||||
/>
|
/>
|
||||||
</BaseBox>
|
</BaseBox>
|
||||||
)}
|
)}
|
||||||
</ViewWrapper>
|
</ViewWrapper>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,129 +1,5 @@
|
|||||||
import {
|
import { Admin_ScreenEventTypeOfEvent } from "@/screens/Admin/Voting/ScreenEventTypeOfEvent";
|
||||||
ActionIcon,
|
|
||||||
BadgeCustom,
|
|
||||||
CenterCustom,
|
|
||||||
LoaderCustom,
|
|
||||||
Spacing,
|
|
||||||
StackCustom,
|
|
||||||
TextCustom,
|
|
||||||
ViewWrapper
|
|
||||||
} from "@/components";
|
|
||||||
import { IconEdit } from "@/components/_Icon";
|
|
||||||
import AdminActionIconPlus from "@/components/_ShareComponent/Admin/ActionIconPlus";
|
|
||||||
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
|
|
||||||
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
|
|
||||||
import { GridViewCustomSpan } from "@/components/_ShareComponent/GridViewCustomSpan";
|
|
||||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
|
||||||
import { apiAdminMasterTypeOfEvent } from "@/service/api-admin/api-master-admin";
|
|
||||||
import { colorActivationForBadge } from "@/utils/colorActivationForBadge";
|
|
||||||
import { router, useFocusEffect } from "expo-router";
|
|
||||||
import _ from "lodash";
|
|
||||||
import { useCallback, useState } from "react";
|
|
||||||
import { View } from "react-native";
|
|
||||||
import { Divider } from "react-native-paper";
|
|
||||||
|
|
||||||
export default function AdminEventTypeOfEvent() {
|
export default function AdminEventTypeOfEvent() {
|
||||||
const [listData, setListData] = useState<any[] | null>(null);
|
return <Admin_ScreenEventTypeOfEvent />;
|
||||||
const [loadData, setLoadData] = useState<boolean>(false);
|
|
||||||
|
|
||||||
useFocusEffect(
|
|
||||||
useCallback(() => {
|
|
||||||
onLoadData();
|
|
||||||
}, [])
|
|
||||||
);
|
|
||||||
|
|
||||||
const onLoadData = async () => {
|
|
||||||
try {
|
|
||||||
setLoadData(true);
|
|
||||||
const response = await apiAdminMasterTypeOfEvent();
|
|
||||||
|
|
||||||
if (response.success) {
|
|
||||||
setListData(response.data);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log("[ERROR]",error);
|
|
||||||
setListData([]);
|
|
||||||
} finally {
|
|
||||||
setLoadData(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<ViewWrapper headerComponent={<AdminTitlePage title="Event" />}>
|
|
||||||
<AdminComp_BoxTitle
|
|
||||||
title="Tipe Acara"
|
|
||||||
rightComponent={
|
|
||||||
<AdminActionIconPlus
|
|
||||||
onPress={() => {
|
|
||||||
router.push(`/admin/event/type-create`);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<>
|
|
||||||
<GridViewCustomSpan
|
|
||||||
span1={2}
|
|
||||||
span2={5}
|
|
||||||
span3={5}
|
|
||||||
component1={
|
|
||||||
<TextCustom bold align="center">
|
|
||||||
Aksi
|
|
||||||
</TextCustom>
|
|
||||||
}
|
|
||||||
component2={<TextCustom bold align="center">Status</TextCustom>}
|
|
||||||
component3={<TextCustom bold>Tipe Acara</TextCustom>}
|
|
||||||
/>
|
|
||||||
<Divider />
|
|
||||||
<Spacing />
|
|
||||||
|
|
||||||
<StackCustom>
|
|
||||||
{loadData ? (
|
|
||||||
<LoaderCustom />
|
|
||||||
) : _.isEmpty(listData) ? (
|
|
||||||
<TextCustom align="center" color="gray">
|
|
||||||
Belum ada data
|
|
||||||
</TextCustom>
|
|
||||||
) : (
|
|
||||||
listData?.map((item, index) => (
|
|
||||||
<View key={index}>
|
|
||||||
<GridViewCustomSpan
|
|
||||||
span1={2}
|
|
||||||
span2={5}
|
|
||||||
span3={5}
|
|
||||||
component1={
|
|
||||||
<CenterCustom>
|
|
||||||
<ActionIcon
|
|
||||||
icon={
|
|
||||||
<IconEdit size={ICON_SIZE_BUTTON} color="black" />
|
|
||||||
}
|
|
||||||
onPress={() => {
|
|
||||||
router.push(`/admin/event/type-update?id=${item.id}`);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</CenterCustom>
|
|
||||||
}
|
|
||||||
style2={{ alignItems: "center" }}
|
|
||||||
component2={
|
|
||||||
<CenterCustom>
|
|
||||||
<BadgeCustom
|
|
||||||
color={colorActivationForBadge({
|
|
||||||
status: item?.active,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{item?.active ? "Aktif" : "Tidak Aktif"}
|
|
||||||
</BadgeCustom>
|
|
||||||
</CenterCustom>
|
|
||||||
}
|
|
||||||
component3={<TextCustom >{item.name}</TextCustom>}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</StackCustom>
|
|
||||||
</>
|
|
||||||
</ViewWrapper>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
import {
|
import {
|
||||||
AlertDefaultSystem,
|
AlertDefaultSystem,
|
||||||
BadgeCustom,
|
BadgeCustom,
|
||||||
BaseBox,
|
BaseBox,
|
||||||
ButtonCustom,
|
ButtonCustom,
|
||||||
Spacing,
|
Spacing,
|
||||||
StackCustom,
|
StackCustom,
|
||||||
TextCustom,
|
TextCustom,
|
||||||
ViewWrapper,
|
ViewWrapper,
|
||||||
} from "@/components";
|
} from "@/components";
|
||||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||||
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
|
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
|
||||||
@@ -15,8 +15,8 @@ import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
|||||||
import { MainColor } from "@/constants/color-palet";
|
import { MainColor } from "@/constants/color-palet";
|
||||||
import { useAuth } from "@/hooks/use-auth";
|
import { useAuth } from "@/hooks/use-auth";
|
||||||
import {
|
import {
|
||||||
apiAdminInvestmentGetOneInvoiceById,
|
apiAdminInvestmentGetOneInvoiceById,
|
||||||
apiAdminInvestmentUpdateInvoice,
|
apiAdminInvestmentUpdateInvoice,
|
||||||
} from "@/service/api-admin/api-admin-investment";
|
} from "@/service/api-admin/api-admin-investment";
|
||||||
import { colorBadgeTransaction } from "@/utils/colorBadge";
|
import { colorBadgeTransaction } from "@/utils/colorBadge";
|
||||||
import { dateTimeView } from "@/utils/dateTimeView";
|
import { dateTimeView } from "@/utils/dateTimeView";
|
||||||
@@ -158,7 +158,7 @@ export default function AdminInvestmentTransactionDetail() {
|
|||||||
spanRight={6}
|
spanRight={6}
|
||||||
styleLeft={{ paddingRight: 10 }}
|
styleLeft={{ paddingRight: 10 }}
|
||||||
styleRight={{ paddingLeft: 10 }}
|
styleRight={{ paddingLeft: 10 }}
|
||||||
leftIcon={
|
leftItem={
|
||||||
<ButtonCustom
|
<ButtonCustom
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
@@ -181,7 +181,7 @@ export default function AdminInvestmentTransactionDetail() {
|
|||||||
Tolak
|
Tolak
|
||||||
</ButtonCustom>
|
</ButtonCustom>
|
||||||
}
|
}
|
||||||
rightIcon={
|
rightItem={
|
||||||
<ButtonCustom
|
<ButtonCustom
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
|
|||||||
@@ -1,4 +1,13 @@
|
|||||||
import { ButtonCustom, DrawerCustom, DummyLandscapeImage, Grid, Spacing, StackCustom, TextCustom, ViewWrapper } from "@/components";
|
import {
|
||||||
|
ButtonCustom,
|
||||||
|
DrawerCustom,
|
||||||
|
DummyLandscapeImage,
|
||||||
|
Grid,
|
||||||
|
Spacing,
|
||||||
|
StackCustom,
|
||||||
|
TextCustom,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
||||||
import API_IMAGE from "@/constants/api-storage";
|
import API_IMAGE from "@/constants/api-storage";
|
||||||
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
||||||
@@ -45,7 +54,7 @@ export default function AdminMaps() {
|
|||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
handlerLoadList();
|
handlerLoadList();
|
||||||
}, [])
|
}, []),
|
||||||
);
|
);
|
||||||
|
|
||||||
const handlerLoadList = async () => {
|
const handlerLoadList = async () => {
|
||||||
@@ -144,52 +153,52 @@ export default function AdminMaps() {
|
|||||||
<GridTwoView
|
<GridTwoView
|
||||||
spanLeft={2}
|
spanLeft={2}
|
||||||
spanRight={10}
|
spanRight={10}
|
||||||
leftIcon={
|
leftItem={
|
||||||
<FontAwesome
|
<FontAwesome
|
||||||
name="building-o"
|
name="building-o"
|
||||||
size={ICON_SIZE_SMALL}
|
size={ICON_SIZE_SMALL}
|
||||||
color="white"
|
color="white"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
rightIcon={<TextCustom>{selected.namePin}</TextCustom>}
|
rightItem={<TextCustom>{selected.namePin}</TextCustom>}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<GridTwoView
|
<GridTwoView
|
||||||
spanLeft={2}
|
spanLeft={2}
|
||||||
spanRight={10}
|
spanRight={10}
|
||||||
leftIcon={
|
leftItem={
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="list-outline"
|
name="list-outline"
|
||||||
size={ICON_SIZE_SMALL}
|
size={ICON_SIZE_SMALL}
|
||||||
color="white"
|
color="white"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
rightIcon={<TextCustom>{selected.bidangBisnis}</TextCustom>}
|
rightItem={<TextCustom>{selected.bidangBisnis}</TextCustom>}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<GridTwoView
|
<GridTwoView
|
||||||
spanLeft={2}
|
spanLeft={2}
|
||||||
spanRight={10}
|
spanRight={10}
|
||||||
leftIcon={
|
leftItem={
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="call-outline"
|
name="call-outline"
|
||||||
size={ICON_SIZE_SMALL}
|
size={ICON_SIZE_SMALL}
|
||||||
color="white"
|
color="white"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
rightIcon={<TextCustom>+{selected.nomorTelepon}</TextCustom>}
|
rightItem={<TextCustom>+{selected.nomorTelepon}</TextCustom>}
|
||||||
/>
|
/>
|
||||||
<GridTwoView
|
<GridTwoView
|
||||||
spanLeft={2}
|
spanLeft={2}
|
||||||
spanRight={10}
|
spanRight={10}
|
||||||
leftIcon={
|
leftItem={
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="location-outline"
|
name="location-outline"
|
||||||
size={ICON_SIZE_SMALL}
|
size={ICON_SIZE_SMALL}
|
||||||
color="white"
|
color="white"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
rightIcon={<TextCustom>{selected.alamatBisnis}</TextCustom>}
|
rightItem={<TextCustom>{selected.alamatBisnis}</TextCustom>}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
import {
|
import {
|
||||||
BoxButtonOnFooter,
|
BoxButtonOnFooter,
|
||||||
ButtonCustom,
|
ButtonCustom,
|
||||||
LoaderCustom,
|
LoaderCustom,
|
||||||
StackCustom,
|
StackCustom,
|
||||||
TextCustom,
|
TextCustom,
|
||||||
ViewWrapper,
|
ViewWrapper,
|
||||||
} from "@/components";
|
} from "@/components";
|
||||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||||
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
||||||
import {
|
import {
|
||||||
apiAdminUserAccessGetById,
|
apiAdminUserAccessGetById,
|
||||||
apiAdminUserAccessUpdateStatus,
|
apiAdminUserAccessUpdateStatus,
|
||||||
} from "@/service/api-admin/api-admin-user-access";
|
} from "@/service/api-admin/api-admin-user-access";
|
||||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||||
import { useCallback, useState } from "react";
|
import { useCallback, useState } from "react";
|
||||||
@@ -26,7 +26,7 @@ export default function SuperAdminDetail() {
|
|||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
onLoadData();
|
onLoadData();
|
||||||
}, [id])
|
}, [id]),
|
||||||
);
|
);
|
||||||
|
|
||||||
const onLoadData = async () => {
|
const onLoadData = async () => {
|
||||||
@@ -48,7 +48,7 @@ export default function SuperAdminDetail() {
|
|||||||
const response = await apiAdminUserAccessUpdateStatus({
|
const response = await apiAdminUserAccessUpdateStatus({
|
||||||
id: id as string,
|
id: id as string,
|
||||||
role: data?.masterUserRoleId === "2" ? "user" : "admin",
|
role: data?.masterUserRoleId === "2" ? "user" : "admin",
|
||||||
category: "role"
|
category: "role",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.success) {
|
if (!response.success) {
|
||||||
@@ -102,8 +102,8 @@ export default function SuperAdminDetail() {
|
|||||||
key={index}
|
key={index}
|
||||||
spanLeft={4}
|
spanLeft={4}
|
||||||
spanRight={8}
|
spanRight={8}
|
||||||
leftIcon={<TextCustom bold>{item?.label}</TextCustom>}
|
leftItem={<TextCustom bold>{item?.label}</TextCustom>}
|
||||||
rightIcon={<TextCustom>{item?.value}</TextCustom>}
|
rightItem={<TextCustom>{item?.value}</TextCustom>}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</StackCustom>
|
</StackCustom>
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
import {
|
import {
|
||||||
BoxButtonOnFooter,
|
BoxButtonOnFooter,
|
||||||
ButtonCustom,
|
ButtonCustom,
|
||||||
LoaderCustom,
|
LoaderCustom,
|
||||||
StackCustom,
|
StackCustom,
|
||||||
TextCustom,
|
TextCustom,
|
||||||
ViewWrapper,
|
ViewWrapper,
|
||||||
} from "@/components";
|
} from "@/components";
|
||||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||||
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
||||||
import { useAuth } from "@/hooks/use-auth";
|
import { useAuth } from "@/hooks/use-auth";
|
||||||
import {
|
import {
|
||||||
apiAdminUserAccessGetById,
|
apiAdminUserAccessGetById,
|
||||||
apiAdminUserAccessUpdateStatus,
|
apiAdminUserAccessUpdateStatus,
|
||||||
} from "@/service/api-admin/api-admin-user-access";
|
} from "@/service/api-admin/api-admin-user-access";
|
||||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||||
import { useCallback, useState } from "react";
|
import { useCallback, useState } from "react";
|
||||||
@@ -28,7 +28,7 @@ export default function AdminUserAccessDetail() {
|
|||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
onLoadData();
|
onLoadData();
|
||||||
}, [id])
|
}, [id]),
|
||||||
);
|
);
|
||||||
|
|
||||||
const onLoadData = async () => {
|
const onLoadData = async () => {
|
||||||
@@ -102,8 +102,8 @@ export default function AdminUserAccessDetail() {
|
|||||||
key={index}
|
key={index}
|
||||||
spanLeft={4}
|
spanLeft={4}
|
||||||
spanRight={8}
|
spanRight={8}
|
||||||
leftIcon={<TextCustom bold>{item?.label}</TextCustom>}
|
leftItem={<TextCustom bold>{item?.label}</TextCustom>}
|
||||||
rightIcon={<TextCustom>{item?.value}</TextCustom>}
|
rightItem={<TextCustom>{item?.value}</TextCustom>}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</StackCustom>
|
</StackCustom>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
BaseBox,
|
BaseBox,
|
||||||
CircleContainer,
|
CircleContainer,
|
||||||
Grid,
|
Grid,
|
||||||
|
NewWrapper,
|
||||||
Spacing,
|
Spacing,
|
||||||
StackCustom,
|
StackCustom,
|
||||||
TextCustom,
|
TextCustom,
|
||||||
@@ -13,7 +14,7 @@ import {
|
|||||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||||
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
|
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
|
||||||
import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview";
|
import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview";
|
||||||
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
|
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
||||||
import ReportBox from "@/components/Box/ReportBox";
|
import ReportBox from "@/components/Box/ReportBox";
|
||||||
import { MainColor } from "@/constants/color-palet";
|
import { MainColor } from "@/constants/color-palet";
|
||||||
import { useAuth } from "@/hooks/use-auth";
|
import { useAuth } from "@/hooks/use-auth";
|
||||||
@@ -40,7 +41,7 @@ export default function AdminVotingDetail() {
|
|||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
onLoadData();
|
onLoadData();
|
||||||
}, [id])
|
}, [id]),
|
||||||
);
|
);
|
||||||
|
|
||||||
const onLoadData = async () => {
|
const onLoadData = async () => {
|
||||||
@@ -169,26 +170,28 @@ export default function AdminVotingDetail() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ViewWrapper
|
<NewWrapper
|
||||||
|
hideFooter
|
||||||
headerComponent={<AdminBackButtonAntTitle title={`Detail Data`} />}
|
headerComponent={<AdminBackButtonAntTitle title={`Detail Data`} />}
|
||||||
>
|
>
|
||||||
<BaseBox>
|
<BaseBox>
|
||||||
<StackCustom>
|
<StackCustom>
|
||||||
{listData.map((item, i) => (
|
{listData.map((item, i) => (
|
||||||
<GridSpan_4_8
|
<GridTwoView
|
||||||
key={i}
|
key={i}
|
||||||
label={<TextCustom bold>{item.label}</TextCustom>}
|
spanLeft={5}
|
||||||
value={<TextCustom>{item.value}</TextCustom>}
|
spanRight={7}
|
||||||
|
leftItem={<TextCustom bold>{item.label}</TextCustom>}
|
||||||
|
rightItem={<TextCustom>{item.value}</TextCustom>}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</StackCustom>
|
</StackCustom>
|
||||||
</BaseBox>
|
</BaseBox>
|
||||||
|
|
||||||
{status === "publish" ||
|
{(status === "publish" || status === "history") && (
|
||||||
(status === "history" && (
|
<BaseBox>
|
||||||
<BaseBox>
|
<TextCustom bold align="center">
|
||||||
<TextCustom bold align="center">
|
Hasil Voting
|
||||||
Hasil Voting
|
|
||||||
</TextCustom>
|
</TextCustom>
|
||||||
<Spacing />
|
<Spacing />
|
||||||
<Grid>
|
<Grid>
|
||||||
@@ -209,11 +212,11 @@ export default function AdminVotingDetail() {
|
|||||||
</TextCustom>
|
</TextCustom>
|
||||||
</StackCustom>
|
</StackCustom>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
)
|
),
|
||||||
)}
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
</BaseBox>
|
</BaseBox>
|
||||||
))}
|
)}
|
||||||
|
|
||||||
{data &&
|
{data &&
|
||||||
data?.catatan &&
|
data?.catatan &&
|
||||||
@@ -250,7 +253,7 @@ export default function AdminVotingDetail() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Spacing />
|
<Spacing />
|
||||||
</ViewWrapper>
|
</NewWrapper>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,117 +1,5 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
import { Admin_ScreenVotingStatus } from "@/screens/Admin/Voting/ScreenVotingStatus";
|
||||||
import {
|
|
||||||
ActionIcon,
|
|
||||||
LoaderCustom,
|
|
||||||
SearchInput,
|
|
||||||
StackCustom,
|
|
||||||
TextCustom,
|
|
||||||
ViewWrapper,
|
|
||||||
} from "@/components";
|
|
||||||
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
|
|
||||||
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
|
|
||||||
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
|
|
||||||
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
|
|
||||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
|
||||||
import { apiAdminVoting } from "@/service/api-admin/api-admin-voting";
|
|
||||||
import { Octicons } from "@expo/vector-icons";
|
|
||||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
|
||||||
import _ from "lodash";
|
|
||||||
import { useCallback, useState } from "react";
|
|
||||||
import { Divider } from "react-native-paper";
|
|
||||||
|
|
||||||
export default function AdminVotingStatus() {
|
export default function AdminVotingStatus() {
|
||||||
const { status } = useLocalSearchParams();
|
return <Admin_ScreenVotingStatus />;
|
||||||
const [list, setList] = useState<any | null>(null);
|
|
||||||
const [loadList, setLoadList] = useState(false);
|
|
||||||
const [search, setSearch] = useState<string>("");
|
|
||||||
|
|
||||||
useFocusEffect(
|
|
||||||
useCallback(() => {
|
|
||||||
onLoadData();
|
|
||||||
}, [status, search])
|
|
||||||
);
|
|
||||||
|
|
||||||
const onLoadData = async () => {
|
|
||||||
try {
|
|
||||||
setLoadList(true);
|
|
||||||
const response = await apiAdminVoting({
|
|
||||||
category: status as "publish" | "review" | "reject" as any,
|
|
||||||
search,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.success) {
|
|
||||||
setList(response.data);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log("[ERROR]", error);
|
|
||||||
} finally {
|
|
||||||
setLoadList(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const rightComponent = (
|
|
||||||
<SearchInput
|
|
||||||
containerStyle={{ width: "100%", marginBottom: 0 }}
|
|
||||||
placeholder="Cari"
|
|
||||||
value={search}
|
|
||||||
onChangeText={setSearch}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<ViewWrapper headerComponent={<AdminTitlePage title="Voting" />}>
|
|
||||||
<AdminComp_BoxTitle
|
|
||||||
title={`${_.startCase(status as string)}`}
|
|
||||||
rightComponent={rightComponent}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<StackCustom gap={"sm"}>
|
|
||||||
<AdminTitleTable
|
|
||||||
title1="Aksi"
|
|
||||||
title2="Username"
|
|
||||||
title3="Judul Voting"
|
|
||||||
/>
|
|
||||||
<Divider />
|
|
||||||
|
|
||||||
{loadList ? (
|
|
||||||
<LoaderCustom />
|
|
||||||
) : _.isEmpty(list) ? (
|
|
||||||
<TextCustom align="center" bold color="gray">
|
|
||||||
Belum ada data
|
|
||||||
</TextCustom>
|
|
||||||
) : (
|
|
||||||
list.map((item: any, i: number) => (
|
|
||||||
<AdminTableValue
|
|
||||||
key={i}
|
|
||||||
value1={
|
|
||||||
<ActionIcon
|
|
||||||
icon={
|
|
||||||
<Octicons
|
|
||||||
name="eye"
|
|
||||||
size={ICON_SIZE_BUTTON}
|
|
||||||
color="black"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
onPress={() => {
|
|
||||||
router.push(`/admin/voting/${item.id}/${status}`);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
value2={
|
|
||||||
<TextCustom truncate={1}>
|
|
||||||
{item?.Author?.username || "-"}
|
|
||||||
</TextCustom>
|
|
||||||
}
|
|
||||||
value3={
|
|
||||||
<TextCustom truncate={2}>
|
|
||||||
{item?.title || "-"}
|
|
||||||
</TextCustom>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</StackCustom>
|
|
||||||
</ViewWrapper>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,104 +1,5 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
import { Admin_ScreenVotingHistory } from "@/screens/Admin/Voting/ScreenVotingHistory";
|
||||||
import {
|
|
||||||
ActionIcon,
|
|
||||||
LoaderCustom,
|
|
||||||
SearchInput,
|
|
||||||
StackCustom,
|
|
||||||
TextCustom,
|
|
||||||
ViewWrapper
|
|
||||||
} from "@/components";
|
|
||||||
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
|
|
||||||
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
|
|
||||||
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
|
|
||||||
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
|
|
||||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
|
||||||
import { apiAdminVoting } from "@/service/api-admin/api-admin-voting";
|
|
||||||
import { Octicons } from "@expo/vector-icons";
|
|
||||||
import { router, useFocusEffect } from "expo-router";
|
|
||||||
import _ from "lodash";
|
|
||||||
import { useCallback, useState } from "react";
|
|
||||||
import { Divider } from "react-native-paper";
|
|
||||||
|
|
||||||
export default function AdminVotingHistory() {
|
export default function AdminVotingHistory() {
|
||||||
const [list, setList] = useState<any | null>(null);
|
return <Admin_ScreenVotingHistory />;
|
||||||
const [loadList, setLoadList] = useState(false);
|
|
||||||
const [search, setSearch] = useState<string>("");
|
|
||||||
|
|
||||||
useFocusEffect(
|
|
||||||
useCallback(() => {
|
|
||||||
onLoadData();
|
|
||||||
}, [ search])
|
|
||||||
);
|
|
||||||
|
|
||||||
const onLoadData = async () => {
|
|
||||||
try {
|
|
||||||
setLoadList(true);
|
|
||||||
const response = await apiAdminVoting({
|
|
||||||
category: "history",
|
|
||||||
search,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.success) {
|
|
||||||
setList(response.data);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log("[ERROR]", error);
|
|
||||||
} finally {
|
|
||||||
setLoadList(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const rightComponent = (
|
|
||||||
<SearchInput
|
|
||||||
containerStyle={{ width: "100%", marginBottom: 0 }}
|
|
||||||
placeholder="Cari"
|
|
||||||
value={search}
|
|
||||||
onChangeText={setSearch}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<ViewWrapper headerComponent={<AdminTitlePage title="Voting" />}>
|
|
||||||
<AdminComp_BoxTitle
|
|
||||||
title="Riwayat"
|
|
||||||
rightComponent={rightComponent}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<StackCustom gap={"sm"}>
|
|
||||||
<AdminTitleTable
|
|
||||||
title1="Aksi"
|
|
||||||
title2="Username"
|
|
||||||
title3="Judul Voting"
|
|
||||||
/>
|
|
||||||
<Divider />
|
|
||||||
|
|
||||||
{loadList ? <LoaderCustom/> : _.isEmpty(list) ? <TextCustom align="center" bold color="gray">Belum ada data</TextCustom> : list.map((item: any, i: number) => (
|
|
||||||
<AdminTableValue
|
|
||||||
key={i}
|
|
||||||
value1={
|
|
||||||
<ActionIcon
|
|
||||||
icon={
|
|
||||||
<Octicons
|
|
||||||
name="eye"
|
|
||||||
size={ICON_SIZE_BUTTON}
|
|
||||||
color="black"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
onPress={() => {
|
|
||||||
router.push(`/admin/voting/${item.id}/history`);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
value2={<TextCustom truncate={1}>{item?.Author?.username || "-"}</TextCustom>}
|
|
||||||
value3={
|
|
||||||
<TextCustom truncate={2}>
|
|
||||||
{item?.title || "-"}
|
|
||||||
</TextCustom>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</StackCustom>
|
|
||||||
</ViewWrapper>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
34
bun.lock
34
bun.lock
@@ -45,7 +45,7 @@
|
|||||||
"moti": "^0.30.0",
|
"moti": "^0.30.0",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0",
|
||||||
"react-native": "0.81.4",
|
"react-native": "0.81.5",
|
||||||
"react-native-dotenv": "^3.4.11",
|
"react-native-dotenv": "^3.4.11",
|
||||||
"react-native-gesture-handler": "~2.28.0",
|
"react-native-gesture-handler": "~2.28.0",
|
||||||
"react-native-international-phone-number": "^0.9.3",
|
"react-native-international-phone-number": "^0.9.3",
|
||||||
@@ -702,21 +702,21 @@
|
|||||||
|
|
||||||
"@react-native-firebase/messaging": ["@react-native-firebase/messaging@23.8.6", "", { "peerDependencies": { "@react-native-firebase/app": "23.8.6", "expo": ">=47.0.0" }, "optionalPeers": ["expo"] }, "sha512-48eW4OFl+XKRgxmgwhNCCT7zUGttm3oAxKJxVQ2Iv9o+wVUTQCLELK3ihC/OrTwCWomM9ylIICqKaK4pdmA22Q=="],
|
"@react-native-firebase/messaging": ["@react-native-firebase/messaging@23.8.6", "", { "peerDependencies": { "@react-native-firebase/app": "23.8.6", "expo": ">=47.0.0" }, "optionalPeers": ["expo"] }, "sha512-48eW4OFl+XKRgxmgwhNCCT7zUGttm3oAxKJxVQ2Iv9o+wVUTQCLELK3ihC/OrTwCWomM9ylIICqKaK4pdmA22Q=="],
|
||||||
|
|
||||||
"@react-native/assets-registry": ["@react-native/assets-registry@0.81.4", "", {}, "sha512-AMcDadefBIjD10BRqkWw+W/VdvXEomR6aEZ0fhQRAv7igrBzb4PTn4vHKYg+sUK0e3wa74kcMy2DLc/HtnGcMA=="],
|
"@react-native/assets-registry": ["@react-native/assets-registry@0.81.5", "", {}, "sha512-705B6x/5Kxm1RKRvSv0ADYWm5JOnoiQ1ufW7h8uu2E6G9Of/eE6hP/Ivw3U5jI16ERqZxiKQwk34VJbB0niX9w=="],
|
||||||
|
|
||||||
"@react-native/babel-plugin-codegen": ["@react-native/babel-plugin-codegen@0.83.2", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@react-native/codegen": "0.83.2" } }, "sha512-XbcN/BEa64pVlb0Hb/E/Ph2SepjVN/FcNKrJcQvtaKZA6mBSO8pW8Eircdlr61/KBH94LihHbQoQDzkQFpeaTg=="],
|
"@react-native/babel-plugin-codegen": ["@react-native/babel-plugin-codegen@0.83.2", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@react-native/codegen": "0.83.2" } }, "sha512-XbcN/BEa64pVlb0Hb/E/Ph2SepjVN/FcNKrJcQvtaKZA6mBSO8pW8Eircdlr61/KBH94LihHbQoQDzkQFpeaTg=="],
|
||||||
|
|
||||||
"@react-native/babel-preset": ["@react-native/babel-preset@0.83.2", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-transform-arrow-functions": "^7.24.7", "@babel/plugin-transform-async-generator-functions": "^7.25.4", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoping": "^7.25.0", "@babel/plugin-transform-class-properties": "^7.25.4", "@babel/plugin-transform-classes": "^7.25.4", "@babel/plugin-transform-computed-properties": "^7.24.7", "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-for-of": "^7.24.7", "@babel/plugin-transform-function-name": "^7.25.1", "@babel/plugin-transform-literals": "^7.25.2", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", "@babel/plugin-transform-numeric-separator": "^7.24.7", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-optional-catch-binding": "^7.24.7", "@babel/plugin-transform-optional-chaining": "^7.24.8", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-react-display-name": "^7.24.7", "@babel/plugin-transform-react-jsx": "^7.25.2", "@babel/plugin-transform-react-jsx-self": "^7.24.7", "@babel/plugin-transform-react-jsx-source": "^7.24.7", "@babel/plugin-transform-regenerator": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/plugin-transform-shorthand-properties": "^7.24.7", "@babel/plugin-transform-spread": "^7.24.7", "@babel/plugin-transform-sticky-regex": "^7.24.7", "@babel/plugin-transform-typescript": "^7.25.2", "@babel/plugin-transform-unicode-regex": "^7.24.7", "@babel/template": "^7.25.0", "@react-native/babel-plugin-codegen": "0.83.2", "babel-plugin-syntax-hermes-parser": "0.32.0", "babel-plugin-transform-flow-enums": "^0.0.2", "react-refresh": "^0.14.0" } }, "sha512-X/RAXDfe6W+om/Fw1i6htTxQXFhBJ2jgNOWx3WpI3KbjeIWbq7ib6vrpTeIAW2NUMg+K3mML1NzgD4dpZeqdjA=="],
|
"@react-native/babel-preset": ["@react-native/babel-preset@0.83.2", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-transform-arrow-functions": "^7.24.7", "@babel/plugin-transform-async-generator-functions": "^7.25.4", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoping": "^7.25.0", "@babel/plugin-transform-class-properties": "^7.25.4", "@babel/plugin-transform-classes": "^7.25.4", "@babel/plugin-transform-computed-properties": "^7.24.7", "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-for-of": "^7.24.7", "@babel/plugin-transform-function-name": "^7.25.1", "@babel/plugin-transform-literals": "^7.25.2", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", "@babel/plugin-transform-numeric-separator": "^7.24.7", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-optional-catch-binding": "^7.24.7", "@babel/plugin-transform-optional-chaining": "^7.24.8", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-react-display-name": "^7.24.7", "@babel/plugin-transform-react-jsx": "^7.25.2", "@babel/plugin-transform-react-jsx-self": "^7.24.7", "@babel/plugin-transform-react-jsx-source": "^7.24.7", "@babel/plugin-transform-regenerator": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/plugin-transform-shorthand-properties": "^7.24.7", "@babel/plugin-transform-spread": "^7.24.7", "@babel/plugin-transform-sticky-regex": "^7.24.7", "@babel/plugin-transform-typescript": "^7.25.2", "@babel/plugin-transform-unicode-regex": "^7.24.7", "@babel/template": "^7.25.0", "@react-native/babel-plugin-codegen": "0.83.2", "babel-plugin-syntax-hermes-parser": "0.32.0", "babel-plugin-transform-flow-enums": "^0.0.2", "react-refresh": "^0.14.0" } }, "sha512-X/RAXDfe6W+om/Fw1i6htTxQXFhBJ2jgNOWx3WpI3KbjeIWbq7ib6vrpTeIAW2NUMg+K3mML1NzgD4dpZeqdjA=="],
|
||||||
|
|
||||||
"@react-native/codegen": ["@react-native/codegen@0.81.4", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.25.3", "glob": "^7.1.1", "hermes-parser": "0.29.1", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" } }, "sha512-LWTGUTzFu+qOQnvkzBP52B90Ym3stZT8IFCzzUrppz8Iwglg83FCtDZAR4yLHI29VY/x/+pkcWAMCl3739XHdw=="],
|
"@react-native/codegen": ["@react-native/codegen@0.81.5", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.25.3", "glob": "^7.1.1", "hermes-parser": "0.29.1", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" } }, "sha512-a2TDA03Up8lpSa9sh5VRGCQDXgCTOyDOFH+aqyinxp1HChG8uk89/G+nkJ9FPd0rqgi25eCTR16TWdS3b+fA6g=="],
|
||||||
|
|
||||||
"@react-native/community-cli-plugin": ["@react-native/community-cli-plugin@0.81.4", "", { "dependencies": { "@react-native/dev-middleware": "0.81.4", "debug": "^4.4.0", "invariant": "^2.2.4", "metro": "^0.83.1", "metro-config": "^0.83.1", "metro-core": "^0.83.1", "semver": "^7.1.3" }, "peerDependencies": { "@react-native-community/cli": "*", "@react-native/metro-config": "*" }, "optionalPeers": ["@react-native-community/cli", "@react-native/metro-config"] }, "sha512-8mpnvfcLcnVh+t1ok6V9eozWo8Ut+TZhz8ylJ6gF9d6q9EGDQX6s8jenan5Yv/pzN4vQEKI4ib2pTf/FELw+SA=="],
|
"@react-native/community-cli-plugin": ["@react-native/community-cli-plugin@0.81.5", "", { "dependencies": { "@react-native/dev-middleware": "0.81.5", "debug": "^4.4.0", "invariant": "^2.2.4", "metro": "^0.83.1", "metro-config": "^0.83.1", "metro-core": "^0.83.1", "semver": "^7.1.3" }, "peerDependencies": { "@react-native-community/cli": "*", "@react-native/metro-config": "*" }, "optionalPeers": ["@react-native-community/cli", "@react-native/metro-config"] }, "sha512-yWRlmEOtcyvSZ4+OvqPabt+NS36vg0K/WADTQLhrYrm9qdZSuXmq8PmdJWz/68wAqKQ+4KTILiq2kjRQwnyhQw=="],
|
||||||
|
|
||||||
"@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.81.5", "", {}, "sha512-bnd9FSdWKx2ncklOetCgrlwqSGhMHP2zOxObJbOWXoj7GHEmih4MKarBo5/a8gX8EfA1EwRATdfNBQ81DY+h+w=="],
|
"@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.81.5", "", {}, "sha512-bnd9FSdWKx2ncklOetCgrlwqSGhMHP2zOxObJbOWXoj7GHEmih4MKarBo5/a8gX8EfA1EwRATdfNBQ81DY+h+w=="],
|
||||||
|
|
||||||
"@react-native/dev-middleware": ["@react-native/dev-middleware@0.81.5", "", { "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.81.5", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", "debug": "^4.4.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", "ws": "^6.2.3" } }, "sha512-WfPfZzboYgo/TUtysuD5xyANzzfka8Ebni6RIb2wDxhb56ERi7qDrE4xGhtPsjCL4pQBXSVxyIlCy0d8I6EgGA=="],
|
"@react-native/dev-middleware": ["@react-native/dev-middleware@0.81.5", "", { "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.81.5", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", "debug": "^4.4.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", "ws": "^6.2.3" } }, "sha512-WfPfZzboYgo/TUtysuD5xyANzzfka8Ebni6RIb2wDxhb56ERi7qDrE4xGhtPsjCL4pQBXSVxyIlCy0d8I6EgGA=="],
|
||||||
|
|
||||||
"@react-native/gradle-plugin": ["@react-native/gradle-plugin@0.81.4", "", {}, "sha512-T7fPcQvDDCSusZFVSg6H1oVDKb/NnVYLnsqkcHsAF2C2KGXyo3J7slH/tJAwNfj/7EOA2OgcWxfC1frgn9TQvw=="],
|
"@react-native/gradle-plugin": ["@react-native/gradle-plugin@0.81.5", "", {}, "sha512-hORRlNBj+ReNMLo9jme3yQ6JQf4GZpVEBLxmTXGGlIL78MAezDZr5/uq9dwElSbcGmLEgeiax6e174Fie6qPLg=="],
|
||||||
|
|
||||||
"@react-native/js-polyfills": ["@react-native/js-polyfills@0.83.2", "", {}, "sha512-dk6fIY2OrKW/2Nk2HydfYNrQau8g6LOtd7NVBrgaqa+lvuRyIML5iimShP5qPqQnx2ofHuzjFw+Ya0b5Q7nDbA=="],
|
"@react-native/js-polyfills": ["@react-native/js-polyfills@0.83.2", "", {}, "sha512-dk6fIY2OrKW/2Nk2HydfYNrQau8g6LOtd7NVBrgaqa+lvuRyIML5iimShP5qPqQnx2ofHuzjFw+Ya0b5Q7nDbA=="],
|
||||||
|
|
||||||
@@ -726,7 +726,7 @@
|
|||||||
|
|
||||||
"@react-native/normalize-colors": ["@react-native/normalize-colors@0.81.5", "", {}, "sha512-0HuJ8YtqlTVRXGZuGeBejLE04wSQsibpTI+RGOyVqxZvgtlLLC/Ssw0UmbHhT4lYMp2fhdtvKZSs5emWB1zR/g=="],
|
"@react-native/normalize-colors": ["@react-native/normalize-colors@0.81.5", "", {}, "sha512-0HuJ8YtqlTVRXGZuGeBejLE04wSQsibpTI+RGOyVqxZvgtlLLC/Ssw0UmbHhT4lYMp2fhdtvKZSs5emWB1zR/g=="],
|
||||||
|
|
||||||
"@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.81.4", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.1.0", "react": "*", "react-native": "*" }, "optionalPeers": ["@types/react"] }, "sha512-hBM+rMyL6Wm1Q4f/WpqGsaCojKSNUBqAXLABNGoWm1vabZ7cSnARMxBvA/2vo3hLcoR4v7zDK8tkKm9+O0LjVA=="],
|
"@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.81.5", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.1.0", "react": "*", "react-native": "*" }, "optionalPeers": ["@types/react"] }, "sha512-UVXgV/db25OPIvwZySeToXD/9sKKhOdkcWmmf4Jh8iBZuyfML+/5CasaZ1E7Lqg6g3uqVQq75NqIwkYmORJMPw=="],
|
||||||
|
|
||||||
"@react-navigation/bottom-tabs": ["@react-navigation/bottom-tabs@7.13.0", "", { "dependencies": { "@react-navigation/elements": "^2.9.5", "color": "^4.2.3", "sf-symbols-typescript": "^2.1.0" }, "peerDependencies": { "@react-navigation/native": "^7.1.28", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-qxxjRDpjhZ4vIZqG4rBU1Vx2jgOAO/ciUKc9sJqVlTM005E2E+aK1EaE3lGaBDyZxTpjonollAucZcqL7OTscQ=="],
|
"@react-navigation/bottom-tabs": ["@react-navigation/bottom-tabs@7.13.0", "", { "dependencies": { "@react-navigation/elements": "^2.9.5", "color": "^4.2.3", "sf-symbols-typescript": "^2.1.0" }, "peerDependencies": { "@react-navigation/native": "^7.1.28", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-qxxjRDpjhZ4vIZqG4rBU1Vx2jgOAO/ciUKc9sJqVlTM005E2E+aK1EaE3lGaBDyZxTpjonollAucZcqL7OTscQ=="],
|
||||||
|
|
||||||
@@ -2104,7 +2104,7 @@
|
|||||||
|
|
||||||
"react-is": ["react-is@19.2.4", "", {}, "sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA=="],
|
"react-is": ["react-is@19.2.4", "", {}, "sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA=="],
|
||||||
|
|
||||||
"react-native": ["react-native@0.81.4", "", { "dependencies": { "@jest/create-cache-key-function": "^29.7.0", "@react-native/assets-registry": "0.81.4", "@react-native/codegen": "0.81.4", "@react-native/community-cli-plugin": "0.81.4", "@react-native/gradle-plugin": "0.81.4", "@react-native/js-polyfills": "0.81.4", "@react-native/normalize-colors": "0.81.4", "@react-native/virtualized-lists": "0.81.4", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", "babel-jest": "^29.7.0", "babel-plugin-syntax-hermes-parser": "0.29.1", "base64-js": "^1.5.1", "commander": "^12.0.0", "flow-enums-runtime": "^0.0.6", "glob": "^7.1.1", "invariant": "^2.2.4", "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", "metro-runtime": "^0.83.1", "metro-source-map": "^0.83.1", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", "react-devtools-core": "^6.1.5", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", "scheduler": "0.26.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0", "ws": "^6.2.3", "yargs": "^17.6.2" }, "peerDependencies": { "@types/react": "^19.1.0", "react": "^19.1.0" }, "optionalPeers": ["@types/react"], "bin": { "react-native": "cli.js" } }, "sha512-bt5bz3A/+Cv46KcjV0VQa+fo7MKxs17RCcpzjftINlen4ZDUl0I6Ut+brQ2FToa5oD0IB0xvQHfmsg2EDqsZdQ=="],
|
"react-native": ["react-native@0.81.5", "", { "dependencies": { "@jest/create-cache-key-function": "^29.7.0", "@react-native/assets-registry": "0.81.5", "@react-native/codegen": "0.81.5", "@react-native/community-cli-plugin": "0.81.5", "@react-native/gradle-plugin": "0.81.5", "@react-native/js-polyfills": "0.81.5", "@react-native/normalize-colors": "0.81.5", "@react-native/virtualized-lists": "0.81.5", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", "babel-jest": "^29.7.0", "babel-plugin-syntax-hermes-parser": "0.29.1", "base64-js": "^1.5.1", "commander": "^12.0.0", "flow-enums-runtime": "^0.0.6", "glob": "^7.1.1", "invariant": "^2.2.4", "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", "metro-runtime": "^0.83.1", "metro-source-map": "^0.83.1", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", "react-devtools-core": "^6.1.5", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", "scheduler": "0.26.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0", "ws": "^6.2.3", "yargs": "^17.6.2" }, "peerDependencies": { "@types/react": "^19.1.0", "react": "^19.1.0" }, "optionalPeers": ["@types/react"], "bin": { "react-native": "cli.js" } }, "sha512-1w+/oSjEXZjMqsIvmkCRsOc8UBYv163bTWKTI8+1mxztvQPhCRYGTvZ/PL1w16xXHneIj/SLGfxWg2GWN2uexw=="],
|
||||||
|
|
||||||
"react-native-country-codes-picker": ["react-native-country-codes-picker@2.3.5", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-dDQhd0bVvlmgb84NPhTOmTk5UVYPHtk3lqZI+BPb61H1rC2IDrTvPWENg6u1DMGliqWHQDBYpeH37zvxxQL71w=="],
|
"react-native-country-codes-picker": ["react-native-country-codes-picker@2.3.5", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-dDQhd0bVvlmgb84NPhTOmTk5UVYPHtk3lqZI+BPb61H1rC2IDrTvPWENg6u1DMGliqWHQDBYpeH37zvxxQL71w=="],
|
||||||
|
|
||||||
@@ -2688,8 +2688,6 @@
|
|||||||
|
|
||||||
"@react-native/codegen/hermes-parser": ["hermes-parser@0.29.1", "", { "dependencies": { "hermes-estree": "0.29.1" } }, "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA=="],
|
"@react-native/codegen/hermes-parser": ["hermes-parser@0.29.1", "", { "dependencies": { "hermes-estree": "0.29.1" } }, "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA=="],
|
||||||
|
|
||||||
"@react-native/community-cli-plugin/@react-native/dev-middleware": ["@react-native/dev-middleware@0.81.4", "", { "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.81.4", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", "debug": "^4.4.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", "ws": "^6.2.3" } }, "sha512-hu1Wu5R28FT7nHXs2wWXvQ++7W7zq5GPY83llajgPlYKznyPLAY/7bArc5rAzNB7b0kwnlaoPQKlvD/VP9LZug=="],
|
|
||||||
|
|
||||||
"@react-native/community-cli-plugin/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
|
"@react-native/community-cli-plugin/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
|
||||||
|
|
||||||
"@react-native/dev-middleware/open": ["open@7.4.2", "", { "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" } }, "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q=="],
|
"@react-native/dev-middleware/open": ["open@7.4.2", "", { "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" } }, "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q=="],
|
||||||
@@ -2902,9 +2900,7 @@
|
|||||||
|
|
||||||
"react-devtools-core/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="],
|
"react-devtools-core/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="],
|
||||||
|
|
||||||
"react-native/@react-native/js-polyfills": ["@react-native/js-polyfills@0.81.4", "", {}, "sha512-sr42FaypKXJHMVHhgSbu2f/ZJfrLzgaoQ+HdpRvKEiEh2mhFf6XzZwecyLBvWqf2pMPZa+CpPfNPiejXjKEy8w=="],
|
"react-native/@react-native/js-polyfills": ["@react-native/js-polyfills@0.81.5", "", {}, "sha512-fB7M1CMOCIUudTRuj7kzxIBTVw2KXnsgbQ6+4cbqSxo8NmRRhA0Ul4ZUzZj3rFd3VznTL4Brmocv1oiN0bWZ8w=="],
|
||||||
|
|
||||||
"react-native/@react-native/normalize-colors": ["@react-native/normalize-colors@0.81.4", "", {}, "sha512-9nRRHO1H+tcFqjb9gAM105Urtgcanbta2tuqCVY0NATHeFPDEAB7gPyiLxCHKMi1NbhP6TH0kxgSWXKZl1cyRg=="],
|
|
||||||
|
|
||||||
"react-native/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="],
|
"react-native/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="],
|
||||||
|
|
||||||
@@ -3062,10 +3058,6 @@
|
|||||||
|
|
||||||
"@react-native/codegen/hermes-parser/hermes-estree": ["hermes-estree@0.29.1", "", {}, "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ=="],
|
"@react-native/codegen/hermes-parser/hermes-estree": ["hermes-estree@0.29.1", "", {}, "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ=="],
|
||||||
|
|
||||||
"@react-native/community-cli-plugin/@react-native/dev-middleware/@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.81.4", "", {}, "sha512-SU05w1wD0nKdQFcuNC9D6De0ITnINCi8MEnx9RsTD2e4wN83ukoC7FpXaPCYyP6+VjFt5tUKDPgP1O7iaNXCqg=="],
|
|
||||||
|
|
||||||
"@react-native/community-cli-plugin/@react-native/dev-middleware/open": ["open@7.4.2", "", { "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" } }, "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q=="],
|
|
||||||
|
|
||||||
"@react-native/dev-middleware/open/is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="],
|
"@react-native/dev-middleware/open/is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="],
|
||||||
|
|
||||||
"@testing-library/react-native/pretty-format/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="],
|
"@testing-library/react-native/pretty-format/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="],
|
||||||
@@ -3224,8 +3216,6 @@
|
|||||||
|
|
||||||
"@istanbuljs/load-nyc-config/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="],
|
"@istanbuljs/load-nyc-config/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="],
|
||||||
|
|
||||||
"@react-native/community-cli-plugin/@react-native/dev-middleware/open/is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="],
|
|
||||||
|
|
||||||
"@testing-library/react-native/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="],
|
"@testing-library/react-native/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="],
|
||||||
|
|
||||||
"babel-preset-expo/@react-native/babel-preset/@react-native/babel-plugin-codegen/@react-native/codegen": ["@react-native/codegen@0.79.6", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.25.3", "glob": "^7.1.1", "hermes-parser": "0.25.1", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" } }, "sha512-iRBX8Lgbqypwnfba7s6opeUwVyaR23mowh9ILw7EcT2oLz3RqMmjJdrbVpWhGSMGq2qkPfqAH7bhO8C7O+xfjQ=="],
|
"babel-preset-expo/@react-native/babel-preset/@react-native/babel-plugin-codegen/@react-native/codegen": ["@react-native/codegen@0.79.6", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.25.3", "glob": "^7.1.1", "hermes-parser": "0.25.1", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" } }, "sha512-iRBX8Lgbqypwnfba7s6opeUwVyaR23mowh9ILw7EcT2oLz3RqMmjJdrbVpWhGSMGq2qkPfqAH7bhO8C7O+xfjQ=="],
|
||||||
@@ -3298,8 +3288,6 @@
|
|||||||
|
|
||||||
"babel-preset-expo/@react-native/babel-preset/@react-native/babel-plugin-codegen/@react-native/codegen/hermes-parser": ["hermes-parser@0.25.1", "", { "dependencies": { "hermes-estree": "0.25.1" } }, "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA=="],
|
"babel-preset-expo/@react-native/babel-preset/@react-native/babel-plugin-codegen/@react-native/codegen/hermes-parser": ["hermes-parser@0.25.1", "", { "dependencies": { "hermes-estree": "0.25.1" } }, "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA=="],
|
||||||
|
|
||||||
"expo/babel-preset-expo/@react-native/babel-preset/@react-native/babel-plugin-codegen/@react-native/codegen": ["@react-native/codegen@0.81.5", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.25.3", "glob": "^7.1.1", "hermes-parser": "0.29.1", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" } }, "sha512-a2TDA03Up8lpSa9sh5VRGCQDXgCTOyDOFH+aqyinxp1HChG8uk89/G+nkJ9FPd0rqgi25eCTR16TWdS3b+fA6g=="],
|
|
||||||
|
|
||||||
"logkitty/yargs/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="],
|
"logkitty/yargs/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="],
|
||||||
|
|
||||||
"pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
|
"pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
|
||||||
@@ -3326,10 +3314,6 @@
|
|||||||
|
|
||||||
"babel-preset-expo/@react-native/babel-preset/@react-native/babel-plugin-codegen/@react-native/codegen/hermes-parser/hermes-estree": ["hermes-estree@0.25.1", "", {}, "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw=="],
|
"babel-preset-expo/@react-native/babel-preset/@react-native/babel-plugin-codegen/@react-native/codegen/hermes-parser/hermes-estree": ["hermes-estree@0.25.1", "", {}, "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw=="],
|
||||||
|
|
||||||
"expo/babel-preset-expo/@react-native/babel-preset/@react-native/babel-plugin-codegen/@react-native/codegen/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
|
|
||||||
|
|
||||||
"expo/babel-preset-expo/@react-native/babel-preset/@react-native/babel-plugin-codegen/@react-native/codegen/hermes-parser": ["hermes-parser@0.29.1", "", { "dependencies": { "hermes-estree": "0.29.1" } }, "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA=="],
|
|
||||||
|
|
||||||
"logkitty/yargs/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
|
"logkitty/yargs/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
|
||||||
|
|
||||||
"qrcode/yargs/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
|
"qrcode/yargs/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
|
||||||
@@ -3343,7 +3327,5 @@
|
|||||||
"@expo/fingerprint/glob/minimatch/brace-expansion/balanced-match/jackspeak/@isaacs/cliui": ["@isaacs/cliui@9.0.0", "", {}, "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg=="],
|
"@expo/fingerprint/glob/minimatch/brace-expansion/balanced-match/jackspeak/@isaacs/cliui": ["@isaacs/cliui@9.0.0", "", {}, "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg=="],
|
||||||
|
|
||||||
"@expo/metro-config/glob/minimatch/brace-expansion/balanced-match/jackspeak/@isaacs/cliui": ["@isaacs/cliui@9.0.0", "", {}, "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg=="],
|
"@expo/metro-config/glob/minimatch/brace-expansion/balanced-match/jackspeak/@isaacs/cliui": ["@isaacs/cliui@9.0.0", "", {}, "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg=="],
|
||||||
|
|
||||||
"expo/babel-preset-expo/@react-native/babel-preset/@react-native/babel-plugin-codegen/@react-native/codegen/hermes-parser/hermes-estree": ["hermes-estree@0.29.1", "", {}, "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ=="],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ import Grid from "../Grid/GridCustom";
|
|||||||
export default function GridTwoView({
|
export default function GridTwoView({
|
||||||
spanLeft = 6,
|
spanLeft = 6,
|
||||||
spanRight = 6,
|
spanRight = 6,
|
||||||
leftIcon,
|
leftItem,
|
||||||
rightIcon,
|
rightItem,
|
||||||
styleLeft,
|
styleLeft,
|
||||||
styleRight,
|
styleRight,
|
||||||
}: {
|
}: {
|
||||||
spanLeft?: number;
|
spanLeft?: number;
|
||||||
spanRight?: number;
|
spanRight?: number;
|
||||||
leftIcon?: React.ReactNode;
|
leftItem?: React.ReactNode;
|
||||||
rightIcon?: React.ReactNode;
|
rightItem?: React.ReactNode;
|
||||||
styleLeft?: ViewStyle;
|
styleLeft?: ViewStyle;
|
||||||
styleRight?: ViewStyle;
|
styleRight?: ViewStyle;
|
||||||
}) {
|
}) {
|
||||||
@@ -24,13 +24,13 @@ export default function GridTwoView({
|
|||||||
span={spanLeft}
|
span={spanLeft}
|
||||||
style={styleLeft ? { ...baseStyle, ...styleLeft } : baseStyle}
|
style={styleLeft ? { ...baseStyle, ...styleLeft } : baseStyle}
|
||||||
>
|
>
|
||||||
{leftIcon}
|
{leftItem}
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
<Grid.Col
|
<Grid.Col
|
||||||
span={spanRight}
|
span={spanRight}
|
||||||
style={styleRight ? { ...baseStyle, ...styleRight } : baseStyle}
|
style={styleRight ? { ...baseStyle, ...styleRight } : baseStyle}
|
||||||
>
|
>
|
||||||
{rightIcon}
|
{rightItem}
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
|
|||||||
28
docs/CHANGE_LOG.md
Normal file
28
docs/CHANGE_LOG.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# CHANGE LOG - fixed-admin/18-feb-26
|
||||||
|
|
||||||
|
## Perubahan Tampilan Admin
|
||||||
|
|
||||||
|
### File Baru (4)
|
||||||
|
- `screens/Admin/Voting/ScreenVotingStatus.tsx`
|
||||||
|
- `screens/Admin/Voting/ScreenVotingHistory.tsx`
|
||||||
|
- `screens/Admin/Voting/ScreenEventTypeOfEvent.tsx`
|
||||||
|
- `screens/Admin/Voting/BoxVotingStatus.tsx`
|
||||||
|
|
||||||
|
### File Diubah (3)
|
||||||
|
- `app/(application)/admin/voting/[status]/status.tsx` → 5 baris
|
||||||
|
- `app/(application)/admin/voting/history.tsx` → 5 baris
|
||||||
|
- `app/(application)/admin/event/type-of-event.tsx` → 5 baris
|
||||||
|
|
||||||
|
### API Updates (2)
|
||||||
|
- `service/api-admin/api-admin-voting.ts` → tambah param `page`
|
||||||
|
- `service/api-admin/api-master-admin.ts` → tambah param `page`
|
||||||
|
|
||||||
|
## Fitur Baru
|
||||||
|
- Pagination (infinite scroll)
|
||||||
|
- Pull-to-Refresh
|
||||||
|
- Skeleton Loading
|
||||||
|
- Empty State
|
||||||
|
- Search Functionality
|
||||||
|
|
||||||
|
## Stats
|
||||||
|
+305 baris, -531 baris (net: -226)
|
||||||
@@ -53,18 +53,12 @@ Terapkan NewWrapper pada file: app/(application)/(user)/donation/create.tsx
|
|||||||
Component yang digunakan: components/_ShareComponent/NewWrapper.tsx
|
Component yang digunakan: components/_ShareComponent/NewWrapper.tsx
|
||||||
<!-- End Penerapan NewWrapper -->
|
<!-- End Penerapan NewWrapper -->
|
||||||
|
|
||||||
<!-- Start Random Prompt -->
|
|
||||||
|
|
||||||
|
|
||||||
Gunakan bahasa indonesia pada cli agar saya mudah membacanya.eclar
|
|
||||||
<!-- End Random Prompt -->
|
|
||||||
|
|
||||||
<!-- START Prompt Admin Refactoring -->
|
<!-- START Prompt Admin Refactoring -->
|
||||||
<!-- Pindah kode ke Screen Component -->
|
<!-- Pindah kode ke Screen Component -->
|
||||||
File source: app/(application)/admin/event/[id]/list-of-participants.tsx
|
File source: app/(application)/admin/event/type-of-event.tsx
|
||||||
Folder tujuan: screens/Admin/Event
|
Folder tujuan: screens/Admin/Voting
|
||||||
Nama file utama: ScreenEventListOfParticipants.tsx
|
Nama file utama: ScreenEventTypeOfEvent.tsx
|
||||||
Nama function utama: Admin_ScreenEventListOfParticipants
|
Nama function utama: Admin_ScreenEventTypeOfEvent
|
||||||
File komponen wrapper: components/_ShareComponent/NewWrapper.tsx
|
File komponen wrapper: components/_ShareComponent/NewWrapper.tsx
|
||||||
|
|
||||||
Buat file baru pada "Folder tujuan" dengan nama "Nama file utama" dan ubah nama function menjadi "Nama function utama" kemudian clean code, import dan panggil function tersebut pada file "File source"
|
Buat file baru pada "Folder tujuan" dengan nama "Nama file utama" dan ubah nama function menjadi "Nama function utama" kemudian clean code, import dan panggil function tersebut pada file "File source"
|
||||||
@@ -72,8 +66,8 @@ Analisa juga file "Nama file utama" , jika belum menggunakan NewWrapper pada fil
|
|||||||
|
|
||||||
|
|
||||||
<!-- Penerapan Pagination -->
|
<!-- Penerapan Pagination -->
|
||||||
Function fecth: apiAdminEventListOfParticipants
|
Function fecth: apiAdminMasterTypeOfEvent
|
||||||
File function fetch: service/api-admin/api-admin-event.ts
|
File function fetch: service/api-admin/api-master-admin.ts
|
||||||
|
|
||||||
Terapkan pagination pada file "Nama file utama"
|
Terapkan pagination pada file "Nama file utama"
|
||||||
Komponen pagination yang digunaka berada pada file hooks/use-pagination.tsx dan helpers/paginationHelpers.tsx
|
Komponen pagination yang digunaka berada pada file hooks/use-pagination.tsx dan helpers/paginationHelpers.tsx
|
||||||
@@ -84,6 +78,10 @@ Kemudian rapikan code nya pisah komponen seperti render item dan lainnya agar le
|
|||||||
Gunakan bahasa indonesia pada cli agar saya mudah membacanya.
|
Gunakan bahasa indonesia pada cli agar saya mudah membacanya.
|
||||||
<!-- END Prompt Admin Refactoring -->
|
<!-- END Prompt Admin Refactoring -->
|
||||||
|
|
||||||
|
<!-- Additional -->
|
||||||
|
File refrensi: screens/Admin/Event/ScreenVotingStatus.tsx
|
||||||
|
Anda bisa menggunakan refrensi dari "File refrensi" jika butuh pemahaman dengan tipe fitur yang hampir sama
|
||||||
|
|
||||||
<!-- Use Prompt Now -->
|
<!-- Use Prompt Now -->
|
||||||
Terapkan NewWrapper pada file: screens/Admin/App-Information/InformationBankSection.tsx
|
Terapkan NewWrapper pada file: screens/Admin/App-Information/InformationBankSection.tsx
|
||||||
Component yang digunakan: components/_ShareComponent/NewWrapper.tsx
|
Component yang digunakan: components/_ShareComponent/NewWrapper.tsx
|
||||||
@@ -95,6 +93,8 @@ Terapkan pagination pada file "Nama file utama"
|
|||||||
Komponen pagination yang digunaka berada pada file hooks/use-pagination.tsx dan helpers/paginationHelpers.tsx
|
Komponen pagination yang digunaka berada pada file hooks/use-pagination.tsx dan helpers/paginationHelpers.tsx
|
||||||
Perbaiki fetch "Function fecth" , pada file "File function fetch"
|
Perbaiki fetch "Function fecth" , pada file "File function fetch"
|
||||||
Jika tidak ada props page maka tambahkan props page dan default page: "1" ( string )
|
Jika tidak ada props page maka tambahkan props page dan default page: "1" ( string )
|
||||||
|
|
||||||
|
|
||||||
<!-- Baru -->
|
<!-- Baru -->
|
||||||
File Utama: screens/Admin/App-Information/InformationBankSection.tsx
|
File Utama: screens/Admin/App-Information/InformationBankSection.tsx
|
||||||
Terapkan FlatList dan pagination pada file "File Utama"
|
Terapkan FlatList dan pagination pada file "File Utama"
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>20</string>
|
<string>21</string>
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
"moti": "^0.30.0",
|
"moti": "^0.30.0",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0",
|
||||||
"react-native": "0.81.4",
|
"react-native": "0.81.5",
|
||||||
"react-native-dotenv": "^3.4.11",
|
"react-native-dotenv": "^3.4.11",
|
||||||
"react-native-gesture-handler": "~2.28.0",
|
"react-native-gesture-handler": "~2.28.0",
|
||||||
"react-native-international-phone-number": "^0.9.3",
|
"react-native-international-phone-number": "^0.9.3",
|
||||||
|
|||||||
54
screens/Admin/Voting/BoxVotingStatus.tsx
Normal file
54
screens/Admin/Voting/BoxVotingStatus.tsx
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import { Divider, StackCustom, TextCustom } from "@/components";
|
||||||
|
import AdminBasicBox from "@/components/_ShareComponent/Admin/AdminBasicBox";
|
||||||
|
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
|
||||||
|
import { dateTimeView } from "@/utils/dateTimeView";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
import { View } from "react-native";
|
||||||
|
|
||||||
|
interface BoxVotingStatusProps {
|
||||||
|
item: any;
|
||||||
|
status?: string;
|
||||||
|
path: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Admin_BoxVotingStatus({
|
||||||
|
item,
|
||||||
|
status,
|
||||||
|
path,
|
||||||
|
}: BoxVotingStatusProps) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<AdminBasicBox
|
||||||
|
style={{ marginHorizontal: 10, marginVertical: 5 }}
|
||||||
|
onPress={() => {
|
||||||
|
router.push(path);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<StackCustom gap={0}>
|
||||||
|
<View style={{ paddingBlock: 8 }}>
|
||||||
|
<TextCustom size={"large"} bold truncate={2}>
|
||||||
|
{item?.title || "-"}
|
||||||
|
</TextCustom>
|
||||||
|
</View>
|
||||||
|
<Divider />
|
||||||
|
<GridSpan_4_8
|
||||||
|
label={<TextCustom>Mulai</TextCustom>}
|
||||||
|
value={
|
||||||
|
<TextCustom>
|
||||||
|
{dateTimeView({ date: item?.awalVote }) || "-"}
|
||||||
|
</TextCustom>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<GridSpan_4_8
|
||||||
|
label={<TextCustom>Berakhir</TextCustom>}
|
||||||
|
value={
|
||||||
|
<TextCustom>
|
||||||
|
{dateTimeView({ date: item?.akhirVote }) || "-"}
|
||||||
|
</TextCustom>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</StackCustom>
|
||||||
|
</AdminBasicBox>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
152
screens/Admin/Voting/ScreenEventTypeOfEvent.tsx
Normal file
152
screens/Admin/Voting/ScreenEventTypeOfEvent.tsx
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
import { BadgeCustom, TextCustom } from "@/components";
|
||||||
|
import AdminActionIconPlus from "@/components/_ShareComponent/Admin/ActionIconPlus";
|
||||||
|
import AdminBasicBox from "@/components/_ShareComponent/Admin/AdminBasicBox";
|
||||||
|
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
|
||||||
|
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
||||||
|
import { GridViewCustomSpan } from "@/components/_ShareComponent/GridViewCustomSpan";
|
||||||
|
import NewWrapper from "@/components/_ShareComponent/NewWrapper";
|
||||||
|
import { PAGINATION_DEFAULT_TAKE } from "@/constants/constans-value";
|
||||||
|
import { createPaginationComponents } from "@/helpers/paginationHelpers";
|
||||||
|
import { usePagination } from "@/hooks/use-pagination";
|
||||||
|
import { apiAdminMasterTypeOfEvent } from "@/service/api-admin/api-master-admin";
|
||||||
|
import { router, useFocusEffect } from "expo-router";
|
||||||
|
import { useCallback, useMemo, useState } from "react";
|
||||||
|
import { RefreshControl, View } from "react-native";
|
||||||
|
|
||||||
|
export function Admin_ScreenEventTypeOfEvent() {
|
||||||
|
const [search, setSearch] = useState<string>("");
|
||||||
|
|
||||||
|
// Gunakan hook pagination
|
||||||
|
const pagination = usePagination({
|
||||||
|
fetchFunction: async (page, searchQuery) => {
|
||||||
|
const response = await apiAdminMasterTypeOfEvent({
|
||||||
|
page: String(page),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.success) {
|
||||||
|
return { data: response.data };
|
||||||
|
} else {
|
||||||
|
return { data: [] };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
pageSize: PAGINATION_DEFAULT_TAKE,
|
||||||
|
searchQuery: search,
|
||||||
|
dependencies: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Komponen action plus untuk header
|
||||||
|
const rightComponent = useMemo(
|
||||||
|
() => (
|
||||||
|
<AdminActionIconPlus
|
||||||
|
onPress={() => {
|
||||||
|
router.push(`/admin/event/type-create`);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Header component untuk title
|
||||||
|
const headerComponent = useMemo(
|
||||||
|
() => (
|
||||||
|
<AdminComp_BoxTitle title="Tipe Acara" rightComponent={rightComponent} />
|
||||||
|
),
|
||||||
|
[rightComponent],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Render header tabel (Aksi, Status, Tipe Acara)
|
||||||
|
const renderTableHeader = useMemo(
|
||||||
|
() => (
|
||||||
|
<>
|
||||||
|
<GridViewCustomSpan
|
||||||
|
span1={2}
|
||||||
|
span2={5}
|
||||||
|
span3={5}
|
||||||
|
component1={
|
||||||
|
<TextCustom bold align="center">
|
||||||
|
Aksi
|
||||||
|
</TextCustom>
|
||||||
|
}
|
||||||
|
component2={
|
||||||
|
<TextCustom bold align="center">
|
||||||
|
Status
|
||||||
|
</TextCustom>
|
||||||
|
}
|
||||||
|
component3={<TextCustom bold>Tipe Acara</TextCustom>}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Render item untuk daftar tipe event (mengikuti pattern InformationBankSection)
|
||||||
|
const renderItem = useCallback(
|
||||||
|
({ item, index }: { item: any; index: number }) => (
|
||||||
|
<AdminBasicBox
|
||||||
|
onPress={() => {
|
||||||
|
router.push(`/admin/event/type-update?id=${item.id}`);
|
||||||
|
}}
|
||||||
|
style={{ marginHorizontal: 10, marginVertical: 5 }}
|
||||||
|
>
|
||||||
|
<GridTwoView
|
||||||
|
leftItem={<TextCustom bold>{item?.name || "-"}</TextCustom>}
|
||||||
|
rightItem={
|
||||||
|
<View>
|
||||||
|
{item?.active ? (
|
||||||
|
<BadgeCustom color="green">Aktif</BadgeCustom>
|
||||||
|
) : (
|
||||||
|
<BadgeCustom color="red">Tidak Aktif</BadgeCustom>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
spanLeft={8}
|
||||||
|
spanRight={4}
|
||||||
|
styleRight={{
|
||||||
|
alignItems: "flex-end",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</AdminBasicBox>
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
useFocusEffect(
|
||||||
|
useCallback(() => {
|
||||||
|
pagination.onRefresh();
|
||||||
|
}, []),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Buat komponen-komponen pagination
|
||||||
|
const { ListEmptyComponent, ListFooterComponent } =
|
||||||
|
createPaginationComponents({
|
||||||
|
loading: pagination.loading,
|
||||||
|
refreshing: pagination.refreshing,
|
||||||
|
listData: pagination.listData,
|
||||||
|
searchQuery: search,
|
||||||
|
emptyMessage: "Belum ada data",
|
||||||
|
emptySearchMessage: "Tidak ada hasil pencarian",
|
||||||
|
isInitialLoad: pagination.isInitialLoad,
|
||||||
|
skeletonCount: PAGINATION_DEFAULT_TAKE,
|
||||||
|
skeletonHeight: 100,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NewWrapper
|
||||||
|
listData={pagination.listData}
|
||||||
|
renderItem={renderItem}
|
||||||
|
keyExtractor={(item: any) => item.id?.toString() || `fallback-${item.id}`}
|
||||||
|
headerComponent={headerComponent}
|
||||||
|
ListEmptyComponent={ListEmptyComponent}
|
||||||
|
ListFooterComponent={ListFooterComponent}
|
||||||
|
onEndReached={pagination.loadMore}
|
||||||
|
refreshControl={
|
||||||
|
<RefreshControl
|
||||||
|
refreshing={pagination.refreshing}
|
||||||
|
onRefresh={pagination.onRefresh}
|
||||||
|
tintColor="#E1B525"
|
||||||
|
colors={["#E1B525"]}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
102
screens/Admin/Voting/ScreenVotingHistory.tsx
Normal file
102
screens/Admin/Voting/ScreenVotingHistory.tsx
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
import { SearchInput } from "@/components";
|
||||||
|
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
|
||||||
|
import NewWrapper from "@/components/_ShareComponent/NewWrapper";
|
||||||
|
import {
|
||||||
|
PAGINATION_DEFAULT_TAKE
|
||||||
|
} from "@/constants/constans-value";
|
||||||
|
import { createPaginationComponents } from "@/helpers/paginationHelpers";
|
||||||
|
import { usePagination } from "@/hooks/use-pagination";
|
||||||
|
import { apiAdminVoting } from "@/service/api-admin/api-admin-voting";
|
||||||
|
import { useCallback, useMemo, useState } from "react";
|
||||||
|
import { RefreshControl } from "react-native";
|
||||||
|
import Admin_BoxVotingStatus from "./BoxVotingStatus";
|
||||||
|
|
||||||
|
export function Admin_ScreenVotingHistory() {
|
||||||
|
const [search, setSearch] = useState<string>("");
|
||||||
|
|
||||||
|
// Gunakan hook pagination
|
||||||
|
const pagination = usePagination({
|
||||||
|
fetchFunction: async (page, searchQuery) => {
|
||||||
|
const response = await apiAdminVoting({
|
||||||
|
category: "history",
|
||||||
|
search: searchQuery,
|
||||||
|
page: String(page),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.success) {
|
||||||
|
return { data: response.data };
|
||||||
|
} else {
|
||||||
|
return { data: [] };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
pageSize: PAGINATION_DEFAULT_TAKE,
|
||||||
|
searchQuery: search,
|
||||||
|
dependencies: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Komponen search input untuk header
|
||||||
|
const rightComponent = useMemo(
|
||||||
|
() => (
|
||||||
|
<SearchInput
|
||||||
|
containerStyle={{ width: "100%", marginBottom: 0 }}
|
||||||
|
placeholder="Cari"
|
||||||
|
value={search}
|
||||||
|
onChangeText={(value) => setSearch(value)}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
[search],
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderItem = useCallback(
|
||||||
|
({ item, index }: { item: any; index: number }) => (
|
||||||
|
<Admin_BoxVotingStatus
|
||||||
|
key={index}
|
||||||
|
item={item}
|
||||||
|
path={`/admin/voting/${item.id}/history`}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Header component dengan judul voting history
|
||||||
|
const headerComponent = useMemo(
|
||||||
|
() => (
|
||||||
|
<AdminComp_BoxTitle title="Riwayat" rightComponent={rightComponent} />
|
||||||
|
),
|
||||||
|
[rightComponent],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Buat komponen-komponen pagination
|
||||||
|
const { ListEmptyComponent, ListFooterComponent } =
|
||||||
|
createPaginationComponents({
|
||||||
|
loading: pagination.loading,
|
||||||
|
refreshing: pagination.refreshing,
|
||||||
|
listData: pagination.listData,
|
||||||
|
searchQuery: search,
|
||||||
|
emptyMessage: "Belum ada data",
|
||||||
|
emptySearchMessage: "Tidak ada hasil pencarian",
|
||||||
|
isInitialLoad: pagination.isInitialLoad,
|
||||||
|
skeletonCount: PAGINATION_DEFAULT_TAKE,
|
||||||
|
skeletonHeight: 80,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NewWrapper
|
||||||
|
listData={pagination.listData}
|
||||||
|
renderItem={renderItem}
|
||||||
|
keyExtractor={(item: any) => item.id?.toString() || `fallback-${item.id}`}
|
||||||
|
headerComponent={headerComponent}
|
||||||
|
ListEmptyComponent={ListEmptyComponent}
|
||||||
|
ListFooterComponent={ListFooterComponent}
|
||||||
|
onEndReached={pagination.loadMore}
|
||||||
|
refreshControl={
|
||||||
|
<RefreshControl
|
||||||
|
refreshing={pagination.refreshing}
|
||||||
|
onRefresh={pagination.onRefresh}
|
||||||
|
tintColor="#E1B525"
|
||||||
|
colors={["#E1B525"]}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
110
screens/Admin/Voting/ScreenVotingStatus.tsx
Normal file
110
screens/Admin/Voting/ScreenVotingStatus.tsx
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
import { SearchInput } from "@/components";
|
||||||
|
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
|
||||||
|
import NewWrapper from "@/components/_ShareComponent/NewWrapper";
|
||||||
|
import {
|
||||||
|
PAGINATION_DEFAULT_TAKE
|
||||||
|
} from "@/constants/constans-value";
|
||||||
|
import { createPaginationComponents } from "@/helpers/paginationHelpers";
|
||||||
|
import { usePagination } from "@/hooks/use-pagination";
|
||||||
|
import { apiAdminVoting } from "@/service/api-admin/api-admin-voting";
|
||||||
|
import { useLocalSearchParams } from "expo-router";
|
||||||
|
import _ from "lodash";
|
||||||
|
import { useCallback, useMemo, useState } from "react";
|
||||||
|
import { RefreshControl } from "react-native";
|
||||||
|
import Admin_BoxVotingStatus from "./BoxVotingStatus";
|
||||||
|
|
||||||
|
export function Admin_ScreenVotingStatus() {
|
||||||
|
const { status } = useLocalSearchParams();
|
||||||
|
const [search, setSearch] = useState<string>("");
|
||||||
|
|
||||||
|
// Gunakan hook pagination
|
||||||
|
const pagination = usePagination({
|
||||||
|
fetchFunction: async (page, searchQuery) => {
|
||||||
|
const response = await apiAdminVoting({
|
||||||
|
category: status as any,
|
||||||
|
search: searchQuery,
|
||||||
|
page: String(page),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.success) {
|
||||||
|
return { data: response.data };
|
||||||
|
} else {
|
||||||
|
return { data: [] };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
pageSize: PAGINATION_DEFAULT_TAKE,
|
||||||
|
searchQuery: search,
|
||||||
|
dependencies: [status],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Komponen search input untuk header
|
||||||
|
const rightComponent = useMemo(
|
||||||
|
() => (
|
||||||
|
<SearchInput
|
||||||
|
containerStyle={{ width: "100%", marginBottom: 0 }}
|
||||||
|
placeholder="Cari"
|
||||||
|
value={search}
|
||||||
|
onChangeText={(value) => setSearch(value)}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
[search],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Render item untuk daftar voting
|
||||||
|
const renderItem = useCallback(
|
||||||
|
({ item, index }: { item: any; index: number }) => (
|
||||||
|
<Admin_BoxVotingStatus
|
||||||
|
key={index}
|
||||||
|
item={item}
|
||||||
|
status={status as string}
|
||||||
|
path={`/admin/voting/${item.id}/${status}`}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
[status],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Header component dengan judul status voting
|
||||||
|
const headerComponent = useMemo(
|
||||||
|
() => (
|
||||||
|
<AdminComp_BoxTitle
|
||||||
|
title={`Voting ${_.startCase(status as string)}`}
|
||||||
|
rightComponent={rightComponent}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
[status, rightComponent],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Buat komponen-komponen pagination
|
||||||
|
const { ListEmptyComponent, ListFooterComponent } =
|
||||||
|
createPaginationComponents({
|
||||||
|
loading: pagination.loading,
|
||||||
|
refreshing: pagination.refreshing,
|
||||||
|
listData: pagination.listData,
|
||||||
|
searchQuery: search,
|
||||||
|
emptyMessage: "Belum ada data",
|
||||||
|
emptySearchMessage: "Tidak ada hasil pencarian",
|
||||||
|
isInitialLoad: pagination.isInitialLoad,
|
||||||
|
skeletonCount: PAGINATION_DEFAULT_TAKE,
|
||||||
|
skeletonHeight: 80,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NewWrapper
|
||||||
|
listData={pagination.listData}
|
||||||
|
renderItem={renderItem}
|
||||||
|
keyExtractor={(item: any) => item.id?.toString() || `fallback-${item.id}`}
|
||||||
|
headerComponent={headerComponent}
|
||||||
|
ListEmptyComponent={ListEmptyComponent}
|
||||||
|
ListFooterComponent={ListFooterComponent}
|
||||||
|
onEndReached={pagination.loadMore}
|
||||||
|
refreshControl={
|
||||||
|
<RefreshControl
|
||||||
|
refreshing={pagination.refreshing}
|
||||||
|
onRefresh={pagination.onRefresh}
|
||||||
|
tintColor="#E1B525"
|
||||||
|
colors={["#E1B525"]}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import {
|
import {
|
||||||
ViewWrapper,
|
ButtonCustom,
|
||||||
DrawerCustom,
|
DrawerCustom,
|
||||||
DummyLandscapeImage,
|
DummyLandscapeImage,
|
||||||
Spacing,
|
Grid,
|
||||||
StackCustom,
|
Spacing,
|
||||||
TextCustom,
|
StackCustom,
|
||||||
Grid,
|
TextCustom,
|
||||||
ButtonCustom,
|
ViewWrapper,
|
||||||
} from "@/components";
|
} from "@/components";
|
||||||
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
||||||
import API_IMAGE from "@/constants/api-storage";
|
import API_IMAGE from "@/constants/api-storage";
|
||||||
@@ -15,8 +15,8 @@ import { apiMapsGetAll } from "@/service/api-client/api-maps";
|
|||||||
import { openInDeviceMaps } from "@/utils/openInDeviceMaps";
|
import { openInDeviceMaps } from "@/utils/openInDeviceMaps";
|
||||||
import { FontAwesome, Ionicons } from "@expo/vector-icons";
|
import { FontAwesome, Ionicons } from "@expo/vector-icons";
|
||||||
import { Image } from "expo-image";
|
import { Image } from "expo-image";
|
||||||
import { useFocusEffect, router } from "expo-router";
|
import { router, useFocusEffect } from "expo-router";
|
||||||
import { useState, useCallback } from "react";
|
import { useCallback, useState } from "react";
|
||||||
import { View } from "react-native";
|
import { View } from "react-native";
|
||||||
import MapView, { Marker } from "react-native-maps";
|
import MapView, { Marker } from "react-native-maps";
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ export default function MapsView() {
|
|||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
handlerLoadList();
|
handlerLoadList();
|
||||||
}, [])
|
}, []),
|
||||||
);
|
);
|
||||||
|
|
||||||
const handlerLoadList = async () => {
|
const handlerLoadList = async () => {
|
||||||
@@ -146,52 +146,52 @@ export default function MapsView() {
|
|||||||
<GridTwoView
|
<GridTwoView
|
||||||
spanLeft={2}
|
spanLeft={2}
|
||||||
spanRight={10}
|
spanRight={10}
|
||||||
leftIcon={
|
leftItem={
|
||||||
<FontAwesome
|
<FontAwesome
|
||||||
name="building-o"
|
name="building-o"
|
||||||
size={ICON_SIZE_SMALL}
|
size={ICON_SIZE_SMALL}
|
||||||
color="white"
|
color="white"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
rightIcon={<TextCustom>{selected.namePin}</TextCustom>}
|
rightItem={<TextCustom>{selected.namePin}</TextCustom>}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<GridTwoView
|
<GridTwoView
|
||||||
spanLeft={2}
|
spanLeft={2}
|
||||||
spanRight={10}
|
spanRight={10}
|
||||||
leftIcon={
|
leftItem={
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="list-outline"
|
name="list-outline"
|
||||||
size={ICON_SIZE_SMALL}
|
size={ICON_SIZE_SMALL}
|
||||||
color="white"
|
color="white"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
rightIcon={<TextCustom>{selected.bidangBisnis}</TextCustom>}
|
rightItem={<TextCustom>{selected.bidangBisnis}</TextCustom>}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<GridTwoView
|
<GridTwoView
|
||||||
spanLeft={2}
|
spanLeft={2}
|
||||||
spanRight={10}
|
spanRight={10}
|
||||||
leftIcon={
|
leftItem={
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="call-outline"
|
name="call-outline"
|
||||||
size={ICON_SIZE_SMALL}
|
size={ICON_SIZE_SMALL}
|
||||||
color="white"
|
color="white"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
rightIcon={<TextCustom>{selected.nomorTelepon}</TextCustom>}
|
rightItem={<TextCustom>{selected.nomorTelepon}</TextCustom>}
|
||||||
/>
|
/>
|
||||||
<GridTwoView
|
<GridTwoView
|
||||||
spanLeft={2}
|
spanLeft={2}
|
||||||
spanRight={10}
|
spanRight={10}
|
||||||
leftIcon={
|
leftItem={
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="location-outline"
|
name="location-outline"
|
||||||
size={ICON_SIZE_SMALL}
|
size={ICON_SIZE_SMALL}
|
||||||
color="white"
|
color="white"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
rightIcon={<TextCustom>{selected.alamatBisnis}</TextCustom>}
|
rightItem={<TextCustom>{selected.alamatBisnis}</TextCustom>}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
|
|||||||
@@ -4,13 +4,15 @@ import { apiConfig } from "../api-config";
|
|||||||
export async function apiAdminVoting({
|
export async function apiAdminVoting({
|
||||||
category,
|
category,
|
||||||
search,
|
search,
|
||||||
|
page = "1",
|
||||||
}: {
|
}: {
|
||||||
category: "dashboard" | "history" | "publish" | "review" | "report";
|
category: "dashboard" | "history" | "publish" | "review" | "report";
|
||||||
search?: string;
|
search?: string;
|
||||||
|
page?: string;
|
||||||
}) {
|
}) {
|
||||||
try {
|
try {
|
||||||
const response = await apiConfig.get(
|
const response = await apiConfig.get(
|
||||||
`/mobile/admin/voting?category=${category}&search=${search}`
|
`/mobile/admin/voting?category=${category}&search=${search}&page=${page}`
|
||||||
);
|
);
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -135,9 +135,9 @@ export async function apiAdminMasterBusinessFieldCreate({
|
|||||||
// ================== END BUSINNES FIELD ================== //
|
// ================== END BUSINNES FIELD ================== //
|
||||||
|
|
||||||
// ================== START EVENT ================== //
|
// ================== START EVENT ================== //
|
||||||
export async function apiAdminMasterTypeOfEvent() {
|
export async function apiAdminMasterTypeOfEvent({ page = "1" }: { page?: string }) {
|
||||||
try {
|
try {
|
||||||
const response = await apiConfig.get(`/mobile/admin/master/type-of-event`);
|
const response = await apiConfig.get(`/mobile/admin/master/type-of-event?page=${page}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
Reference in New Issue
Block a user