Compare commits

...

36 Commits

Author SHA1 Message Date
d0eb812adc feat: Complete Admin Phase 2 Voting screens migration
- Migrate 5 admin voting screens to OS_Wrapper (dashboard, lists, detail, form)
- Add enableKeyboardHandling to reject-input form screen
- Update TASK-005 with Admin Phase 2 completion status
- Total: 146 files migrated (~85% complete)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-14 17:37:15 +08:00
6d4dc0f7f7 feat: Complete Admin Phase 1 Event screens migration
- Migrate 8 admin event screens to OS_Wrapper (dashboard, lists, detail, forms, utility)
- Add enableKeyboardHandling to 3 form screens (reject-input, type-create, type-update)
- Migrate ScreenEventTypeOfEvent from Voting to OS_Wrapper
- Update TASK-005 with Admin Phase 1 completion status
- Total: 140 files migrated (~83% complete)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-14 16:55:41 +08:00
0823a1c26a feat: Complete Admin Phase 6 Job screens migration
- Migrate 4 admin job screens to OS_Wrapper (dashboard, list, detail, form)
- Add enableKeyboardHandling to reject-input form screen
- Update TASK-005 with Admin Phase 6 completion status
- Total: 132 files migrated (~79% complete)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-14 12:24:58 +08:00
eb64c30d49 feat: Complete User Phase 9 Investment screens migration + note known upload issue
- Migrate 24 investment screens to OS_Wrapper (tabs, list, detail, forms, transaction flow)
- Add contentPadding={PADDING_INLINE} to 9 list/tabs screens for consistent spacing
- Add enableKeyboardHandling to 6 form screens
- Fix investment tabs layout height to use OS_IOS_HEIGHT/OS_ANDROID_HEIGHT constants
- Update TASK-005 with known issue: upload image returns 500 error in dev env
- Note: Investment feature not fully complete - upload issue needs investigation tomorrow

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-13 17:56:49 +08:00
2f87776d8b docs: Add User Phase 9 Investment screens details to TASK-005
- Document 24 investment screens to migrate
- Include tabs, list/document, detail, form, and transaction flow screens
- Note tabs layout height fix needed for investment

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-13 16:45:15 +08:00
243313b8eb feat: Complete User Phase 8 Donation screens + add PADDING_INLINE to all list/recap screens
- Migrate 25 donation screens to OS_Wrapper (tabs, list, detail, forms, transaction flow)
- Add contentPadding={PADDING_INLINE} to 7 list/recap screens for consistent spacing
- Migrate crowdfunding screen to OS_Wrapper
- Fix voting tabs layout height to use OS_IOS_HEIGHT/OS_ANDROID_HEIGHT constants
- Migrate news detail screen to OS_Wrapper
- Update TASK-005 progress to 73% complete (104 files migrated)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-13 16:24:14 +08:00
8e61c980af fix: Remove PADDING_INLINE from non-tabs ScreenListOfContributor + update task
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-13 12:25:12 +08:00
c709dffd20 feat: Complete User Phase 7 Voting screens migration to OS_Wrapper
- Migrate 5 list screens (Beranda, Contribution, History, Status, ListOfContributor)
- Migrate 2 form screens (create, edit) with enableKeyboardHandling
- Migrate 4 detail screens (index, contribution, history, detail)
- Add PADDING_INLINE to tabs screens for consistent spacing
- Update TASK-005 progress to 80% complete (71/89 files)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-13 12:24:23 +08:00
54537d2449 feat: Complete Phase 6 Event screens migration + add PADDING_INLINE to tabs
User Phase 6 - Event Screens (16 files):
- Beranda, Status, History, Contribution (tabs screens)
  → NewWrapper → OS_Wrapper + contentPadding={PADDING_INLINE}
- create.tsx & edit.tsx → Forms with enableKeyboardHandling + contentPaddingBottom={250}
- [id]/publish.tsx, history.tsx, contribution.tsx, confirmation.tsx → Static detail screens
- [id]/[status]/detail-event.tsx → Status detail screen
- detail/[id].tsx → Detail route screen
- ScreenListOfParticipants.tsx → Participants list screen

Key Improvements:
- Added contentPadding={PADDING_INLINE} to all Event (tabs) screens to prevent tight edge margins.
- Form screens (create, edit) use enableKeyboardHandling + contentPaddingBottom={250}.
- Removed all ViewWrapper and NewWrapper instances from Event feature.

Documentation:
- Update TASK-005 with Phase 6 completion details and new progress totals.
- Added note about PADDING_INLINE usage for tab screens.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-10 13:50:59 +08:00
66792186ca feat: Complete Forum & Admin User Access migration + fix scroll issues
Forum Screens (User Phase 5 - 17 files):
- Migrate all forum list, detail, create, and report screens to OS_Wrapper.
- ViewBeranda, ViewBeranda2, ViewBeranda3: List screens with pull-to-refresh.
- DetailForum, DetailForum2: Comment sections with headers (apply disableFlexGrow fix).
- create, edit, report-*, other-report-*, preview-report-*: Forms with keyboard handling.

Admin Phase 9 (User Access - 2 files):
- index.tsx: List with search and pagination.
- [id]/index.tsx: Detail with status toggle footer.

Scroll Fixes (Critical Bugs):
- Fix "Ghost Scroll" in Android FlatList: Removed TouchableWithoutFeedback and KeyboardAvoidingView wrappers in List Mode.
- Fix Large Header Cut-off: Added optional disableFlexGrow={true} to OS_Wrapper for screens with complex ListHeaderComponents (e.g., Forum Detail).
- Fix Keyboard Dismiss: Changed keyboardShouldPersistTaps to "handled" so taps on empty areas dismiss the keyboard while allowing scroll.

Documentation:
- Update TASK-005 with complete Phase 5 details and new progress totals.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-09 17:48:51 +08:00
c3cf354c28 feat: Migrate Portfolio & Maps screens + perbaiki bug auto-scroll keyboard
Phase 3 - Portfolio Screens (6 files):
- [id]/index.tsx: ViewWrapper → OS_Wrapper (detail dengan pull-to-refresh)
- [id]/edit.tsx: NewWrapper → OS_Wrapper (form + keyboard handling)
- [id]/edit-logo.tsx: ViewWrapper → OS_Wrapper (upload logo)
- [id]/edit-social-media.tsx: ViewWrapper → OS_Wrapper (form + keyboard handling)
- ViewListPortofolio.tsx: NewWrapper → OS_Wrapper (pagination list)
- ScreenPortofolioCreate.tsx: NewWrapper → OS_Wrapper (form + keyboard handling)

Phase 4 - Maps Screens (2 files):
- ScreenMapsCreate.tsx: NewWrapper → OS_Wrapper (form + keyboard handling)
- ScreenMapsEdit.tsx: ViewWrapper → OS_Wrapper (form + keyboard handling)

Bug Fixes:
- Perbaiki auto-scroll keyboard yang membuat input paling atas 'terlempar' keluar layar
- Gunakan UIManager.measure untuk mendapatkan posisi absolut input (pageY) secara akurat
- Logika conditional scroll:
  * Jika input terlihat (di atas keyboard) → TIDAK SCROLL
  * Jika input tertutup keyboard → Scroll secukupnya
- Helper cloneChildrenWithFocusHandler sekarang aktif menyuntikan onFocus handler ke semua TextInput/TextArea/PhoneInput/Select
- Hapus KeyboardAvoidingView dari AndroidWrapper static mode (tidak diperlukan lagi)

Pattern yang diterapkan:
- List screens: contentPaddingBottom=100 (default)
- Form screens: contentPaddingBottom={250} + enableKeyboardHandling
- NO PADDING_INLINE (sesuai preferensi user - mencegah box menyempit)

Dokumentasi:
- Update TASK-005 dengan status lengkap Phase 1-4 (27 files migrated)
- Tambahkan urutan phase baru: Event (Phase 5), Voting (Phase 6), Forum (Phase 7), Donation (Phase 8)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-08 17:27:06 +08:00
6ec839fd67 feat: Migrate Profile, Waiting Room, and Delete Account to OS_Wrapper
Profile Screens (8 files):
- [id]/index.tsx: NewWrapper → OS_Wrapper (list with refresh)
- [id]/edit.tsx: ViewWrapper → OS_Wrapper (form + keyboard handling)
- create.tsx: ViewWrapper → OS_Wrapper (form + keyboard handling)
- [id]/blocked-list.tsx: NewWrapper → OS_Wrapper (pagination list)
- [id]/detail-blocked.tsx: NewWrapper → OS_Wrapper (static with footer)
- [id]/update-background.tsx: ViewWrapper → OS_Wrapper (static with footer)
- [id]/update-photo.tsx: ViewWrapper → OS_Wrapper (static with footer)
- All Profile forms use enableKeyboardHandling + contentPaddingBottom={250}

Other Screens (2 files):
- waiting-room.tsx: NewWrapper → OS_Wrapper (static with refresh + footer)
- delete-account.tsx: ViewWrapper → OS_Wrapper (form + keyboard handling)

Bug Fixes:
- AndroidWrapper: Add refreshControl to ScrollView (fix pull-to-refresh on static mode)

Pattern Applied:
- List screens: contentPaddingBottom=100 (default)
- Form screens: contentPaddingBottom=250 (with TextInput)
- No PADDING_INLINE (user preference - prevents box narrowing)

Documentation:
- Update TASK-005 with Phase 1 completion details

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-08 14:32:11 +08:00
b8f8a361d6 refactor: Adjust OS_Wrapper defaults for better spacing
- Reduce default contentPaddingBottom from 250 to 100
  - Better for list screens (less empty space)
  - Only form screens with TextInput need 250px

- Set OS_ANDROID_PADDING_TOP to 6px
  - More compact tabs on Android

- Update form screens (Create/Edit):
  - Explicit contentPaddingBottom={250}
  - Only screens with TextInput use larger spacing

- Remove unnecessary PADDING_INLINE from detail screens
  - Detail screen doesn't need inline padding

Pattern:
- Default: contentPaddingBottom=100 (list screens)
- Forms: contentPaddingBottom=250 (screens with TextInput)
- contentPadding=0 (per-screen control)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-08 10:31:36 +08:00
1a5ca78041 feat: Complete OS_Wrapper implementation with keyboard handling and PADDING_INLINE
OS_Wrapper System:
- Simplify API: Remove PageWrapper, merge keyboard props into OS_Wrapper
- Add auto-scroll when keyboard appears (Android only)
- Add tap-to-dismiss keyboard for both Static and List modes
- Fix contentPaddingBottom default to 250px (prevent keyboard overlap)
- Change default contentPadding to 0 (per-screen control)
- Remove Platform.OS checks from IOSWrapper and AndroidWrapper

Constants:
- Add PADDING_INLINE constant (16px) for consistent inline padding
- Add OS_PADDING_TOP constants for tab layouts

Job Screens Migration (9 files):
- Apply PADDING_INLINE to all Job screens:
  - ScreenBeranda, ScreenBeranda2
  - ScreenArchive, ScreenArchive2
  - MainViewStatus, MainViewStatus2
  - ScreenJobCreate, ScreenJobEdit
  - Job detail screen

Keyboard Handling:
- Simplified useKeyboardForm hook
- Auto-scroll by keyboard height when keyboard appears
- Track scroll position for accurate scroll targets
- TouchableWithoutFeedback wraps all content for tap-to-dismiss

Documentation:
- Update TASK-005 with Phase 1 completion status
- Update Quick Reference with unified API examples

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-07 17:50:15 +08:00
502cd7bc65 feat: Implement OS_Wrapper system and migrate all Job screens
Create OS-specific wrapper system:
- Add IOSWrapper (based on NewWrapper for iOS)
- Add AndroidWrapper (based on NewWrapper_V2 with keyboard handling)
- Add OS_Wrapper (auto platform detection)
- Add PageWrapper (with keyboard handling for Android forms)

Migrate all Job screens (8 files):
- ScreenJobCreate: NewWrapper_V2 → PageWrapper
- ScreenJobEdit: NewWrapper_V2 → PageWrapper
- ScreenBeranda2: NewWrapper_V2 → OS_Wrapper
- ScreenArchive2: NewWrapper_V2 → OS_Wrapper
- MainViewStatus2: NewWrapper_V2 → OS_Wrapper
- ScreenBeranda: ViewWrapper → OS_Wrapper
- ScreenArchive: ViewWrapper → OS_Wrapper
- MainViewStatus: ViewWrapper → OS_Wrapper

Benefits:
- Automatic platform detection (no manual Platform.OS checks)
- Consistent tabs behavior across iOS and Android
- Keyboard handling for forms (Android only)
- Cleaner code with unified API

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-07 14:14:00 +08:00
44d9025afe refactor: Update header components and improve job edit footer layout
- Replace Waiting Room header with AppHeader component
- Replace Profile Create header with AppHeader with showBack=false
- Wrap Job Edit submit button with BoxButtonOnFooter for consistent footer layout

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-06 17:49:28 +08:00
b34bc3799e feat: Add default contentPadding to NewWrapper_V2
- Set default contentPadding to 16px for consistent spacing
- Added contentPadding prop to BaseProps interface
- Updated documentation in TASK-004

Benefits:
- All screens automatically have 16px padding
- Cleaner code (no need to specify padding everywhere)
- Still customizable (set to 0 or custom value if needed)
- Box content not too tight to screen edges

Phase 1 completed with consistent padding!

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-02 17:16:19 +08:00
7cb4f30ae9 refactor: Replace NewWrapper with NewWrapper_V2 for all Job screens
- ScreenBeranda2.tsx: NewWrapper → NewWrapper_V2
- ScreenArchive2.tsx: NewWrapper → NewWrapper_V2
- MainViewStatus2.tsx: NewWrapper → NewWrapper_V2

All Job screens now using NewWrapper_V2 with:
- Better keyboard handling
- Footer width 100%
- Content padding bottom 80px
- Auto-scroll to focused input (for forms)
- No white area when keyboard close

Phase 1 completed: All Job screens migrated!

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-02 16:13:23 +08:00
0f552443c4 refactor: Cleanup test files and migrate Job Detail screen
- Delete ScreenJobCreate2.tsx and ScreenJobEdit2.tsx (test files)
- Delete TestWrapper.tsx and TestKeyboardInput.tsx (test components)
- Delete test pages (test-keyboard.tsx, test-keyboard-bug.tsx)
- Update create.tsx to use ScreenJobCreate (not test version)
- Update edit.tsx to use ScreenJobEdit (not test version)
- Migrate Job Detail screen to NewWrapper_V2
- Remove TestWrapper from exports
- Clean up imports

Phase 1 cleanup completed!

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-02 15:31:26 +08:00
90bc8ae343 feat: Migrate Job screens to NewWrapper_V2 with keyboard handling
- Migrate ScreenJobCreate.tsx to NewWrapper_V2
    - Migrate ScreenJobEdit.tsx to NewWrapper_V2
    - Add NewWrapper_V2 component with auto-scroll keyboard handling
    - Add useKeyboardForm hook for keyboard management
    - Add FormWrapper component for forms
    - Create ScreenJobEdit.tsx from edit route (separation of concerns)
    - Add documentation for keyboard implementation
    - Add TASK-004 migration plan
    - Fix: Footer width 100% with safe positioning
    - Fix: Content padding bottom 80px for navigation bar
    - Fix: Auto-scroll to focused input
    - Fix: No white area when keyboard close
    - Fix: Footer not raised after keyboard close

    Phase 1 completed: Job screens migrated

### No Issue
2026-04-02 15:07:10 +08:00
98f8c7e2bf Fix layout tabs pada komponen
Fix home tabs

### No Issue
2026-04-01 17:17:12 +08:00
81bbd8e6b0 Clean project and release with new domain: hipmi.muku.id
### No issue
2026-03-31 17:07:27 +08:00
57159d2c45 update app config domain
### No Issue
2026-03-31 14:29:19 +08:00
66373fa65b Clean code
Update android domain

### No Issue
2026-03-31 14:28:43 +08:00
6d545f2af9 Fix change yang tertinggal 2026-03-30 17:39:53 +08:00
eeb95336f2 Fix version & tabs android
### No Issue
2026-03-30 17:38:31 +08:00
6fb3b229c3 Fix andorid 2026-03-27 17:59:13 +08:00
76deec9c53 Fix tabs agar bisa di klik
### Issue: Di android batas atas kurang turun
2026-03-26 17:37:31 +08:00
31948f71db Fix: NewWrapper footer position dengan SafeAreaView
Problem:
- Footer component tertutup atau scroll melebihi layar
- Tabs tidak bisa diklik karena footer floating
- Height OS_HEIGHT tidak konsisten di berbagai device

Solution:
 Footer menggunakan position: absolute untuk stay di bawah
 Konten ScrollView/FlatList mendapat paddingBottom: OS_HEIGHT
 SafeAreaView hanya untuk area aman, bukan height control
 Footer tetap visible di semua ukuran layar

Changes:
- Add styles.footerContainer dengan position: absolute
- Add paddingBottom ke contentContainerStyle (ScrollView & FlatList)
- Remove height: OS_HEIGHT dari SafeAreaView
- Footer stay di bottom dengan proper safe area handling

Result:
- Footer selalu terlihat di bawah layar
- Konten tidak tertutup footer (ada padding)
- Tabs bisa diklik dengan baik
- Konsisten di iOS & Android
- Respect safe area insets

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-26 12:28:07 +08:00
16decd89c8 Refactor: apply PhoneInputCustom to PortofolioEdit
Changes:
- Replace react-native-international-phone-number with PhoneInputCustom
- Remove ICountry dependency, use CountryData from constants
- Add phone number state management
- Implement country detection from existing phone number
- Auto-detect country based on calling code on load
- Improve phone number formatting logic

Features Applied:
 NO emoji flags - only calling codes (+62, +65, etc)
 Clean, professional UI
 Modal country picker with search
 Auto-detect country from saved phone number
 Real-time phone number formatting
 Auto-update country code on change
 Consistent with LoginView & ScreenPortofolioCreate

Phone Detection Logic:
- Load existing phone number from API
- Detect country by matching calling code
- Extract phone number without country code for display
- Set detected country for country picker
- Re-format on country change

UI:
- Phone Input: [+62 ⌄ | xxx-xxx-xxx]
- Country Picker: Modal with search
- Display: Country name + calling code only

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-26 12:17:05 +08:00
ecbcc12abf Refactor: apply PhoneInputCustom to ScreenPortofolioCreate
Changes:
- Replace react-native-international-phone-number with PhoneInputCustom
- Remove ICountry dependency, use CountryData from constants
- Update state management (inputValue → phoneNumber)
- Improve phone number formatting logic
- Add handleCountryChange for better country switching

Features Applied:
 NO emoji flags - only calling codes (+62, +65, etc)
 Clean, professional UI
 Modal country picker with search
 Real-time phone number formatting
 Auto-update country code on change
 Consistent with LoginView implementation

Phone Input Logic:
- Format on every phone change
- Re-format when country changes
- Remove duplicate country codes
- Remove leading zeros
- Store E.164 format in API data

UI:
- Phone Input: [+62 ⌄ | xxx-xxx-xxx]
- Country Picker: Modal with search
- Display: Country name + calling code only

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-26 11:42:54 +08:00
0cb734e790 Refactor: apply PhoneInputCustom to LoginView
Changes:
- Replace react-native-international-phone-number with PhoneInputCustom
- Remove dependency on ICountry, use CountryData from constants
- Add KeyboardAvoidingView for better iOS keyboard handling
- Improve validation with libphonenumber-js
- Add proper phone number formatting
- Update state management (inputValue → phoneNumber)

Features Applied:
 NO emoji flags - only calling codes (+62, +65, etc)
 Clean, professional UI
 Modal country picker with search
 Better keyboard handling on iOS
 Real-time validation with libphonenumber-js
 Auto-formatting for international numbers
 Reusable component

UI:
- Phone Input: [+62 ⌄ | 812-3456-7890]
- Country Picker: Modal with search
- Display: Country name + calling code only

Validation:
- Check phone number length
- Validate with libphonenumber-js
- Format to E.164 on login
- Error handling with Toast

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-26 11:33:18 +08:00
0d2fef1878 Feat: add reusable PhoneInput component without flags
New Components:
- PhoneInputCustom: Reusable phone input without emoji flags
- constants/countries.ts: Country data with calling codes only

Features:
 NO emoji flags - only country name + calling code (+62, +65, etc)
 Clean, professional UI
 Modal country picker with search
 15 countries supported
 Helper functions: getCountryByCallingCode, getCountryByCode, searchCountries
 Fully typed with TypeScript
 Reusable across the app
 Maximum compatibility (no emoji rendering issues)

UI Design:
- Phone Input: [+62 ⌄ | 812-3456-7890]
- Country Picker: Modal with search
- Display: Country name + calling code only

Usage:
import { PhoneInputCustom } from '@/components';
import { DEFAULT_COUNTRY } from '@/constants/countries';

<PhoneInputCustom
  value={phoneNumber}
  onChangePhoneNumber={setPhoneNumber}
  selectedCountry={selectedCountry}
  onChangeCountry={setSelectedCountry}
/>

Benefits:
 Works on ALL iOS versions (no emoji issues)
 Consistent across all platforms
 Faster render (no emoji/image loading)
 Cleaner code structure
 Easy to maintain

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-26 11:27:59 +08:00
2e58f8c7b4 Docs: add task breakdown untuk fix phone input iOS 16+
- Add TASKS/fix-phone-input-ios-16.md dengan analisis lengkap
- 3 opsi solusi: KeyboardAvoidingView, Keyboard Controller, Custom Input
- Detailed implementation guidelines
- Testing checklist untuk iOS 16, 17, 18

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-25 16:39:48 +08:00
b6cd308b0b Refactor pagination implementation dan perbaikan UI
- Add default page parameter di apiAllUser
- Refactor MainView_V2.tsx dengan separate render functions
- Update pagination pageSize menjadi 10 di Forum
- Fix iOS height constant dan tab styling
- Rename Admin_ScreenPortofolioCreate ke ScreenPortofolioCreate
- Add TASKS documentation folder

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-25 16:22:54 +08:00
f68deab8c0 Fix App Header
Layouts & Navigation
- app/(application)/_layout.tsx
- app/(application)/(user)/_layout.tsx
- app/(application)/(user)/event/(tabs)/_layout.tsx
- app/(application)/(user)/job/(tabs)/_layout.tsx
- app/(application)/(user)/voting/(tabs)/_layout.tsx
- app/(application)/(user)/portofolio/_layout.tsx
- app/(application)/(user)/profile/_layout.tsx
- app/(application)/admin/_layout.tsx
- app/+not-found.tsx

User – File
- app/(application)/(file)/[id].tsx

User – Collaboration
- app/(application)/(user)/collaboration/[id]/index.tsx
- app/(application)/(user)/collaboration/[id]/detail-project-main.tsx
- app/(application)/(user)/collaboration/[id]/detail-participant.tsx
- app/(application)/(user)/collaboration/[id]/[detail]/info.tsx
- app/(application)/(user)/collaboration/[id]/[detail]/room-chat.tsx

User – Donation
- app/(application)/(user)/donation/[id]/index.tsx
- app/(application)/(user)/donation/[id]/[status]/detail.tsx
- app/(application)/(user)/donation/[id]/(news)/[news]/index.tsx

User – Event
- app/(application)/(user)/event/[id]/[status]/detail-event.tsx
- app/(application)/(user)/event/[id]/confirmation.tsx
- app/(application)/(user)/event/[id]/contribution.tsx
- app/(application)/(user)/event/[id]/history.tsx
- app/(application)/(user)/event/[id]/publish.tsx

User – Investment
- app/(application)/(user)/investment/[id]/index.tsx
- app/(application)/(user)/investment/[id]/[status]/detail.tsx
- app/(application)/(user)/investment/[id]/(my-holding)/[id].tsx
- app/(application)/(user)/investment/[id]/(news)/[news]/index.tsx

User – Job
- app/(application)/(user)/job/[id]/[status]/detail.tsx

User – Portofolio
- app/(application)/(user)/portofolio/[id]/index.tsx

User – Profile
- app/(application)/(user)/profile/[id]/index.tsx

User – Voting
- app/(application)/(user)/voting/[id]/index.tsx
- app/(application)/(user)/voting/[id]/[status]/detail.tsx
- app/(application)/(user)/voting/[id]/contribution.tsx
- app/(application)/(user)/voting/[id]/history.tsx

Components
- components/Button/BackButtonFromNotification.tsx
- components/_ShareComponent/AppHeader.tsx

Admin Screens
- screens/Admin/Notification-Admin/ScreenNotificationAdmin.tsx
- screens/Admin/Notification-Admin/ScreenNotificationAdmin2.tsx

Screens – Donation
- screens/Donation/ScreenListOfNews.tsx
- screens/Donation/ScreenRecapOfNews.tsx

Screens – Forum
- screens/Forum/ViewBeranda.tsx
- screens/Forum/ViewBeranda2.tsx
- screens/Forum/ViewBeranda3.tsx

Screens – Investment
- screens/Invesment/Document/ScreenRecapOfDocument.tsx
- screens/Invesment/News/ScreenListOfNews.tsx
- screens/Invesment/News/ScreenRecapOfNews.tsx

Screens – Notification
- screens/Notification/ScreenNotification_V1.tsx
- screens/Notification/ScreenNotification_V2.tsx

iOS
- ios/HIPMIBadungConnect.xcodeproj/project.pbxproj

Docs
- QWEN.md

### Issue: Tabs can't clicked
2026-03-13 16:41:34 +08:00
213 changed files with 6755 additions and 3073 deletions

3
.gitignore vendored
View File

@@ -81,4 +81,7 @@ yarn-error.*
# typescript # typescript
*.tsbuildinfo *.tsbuildinfo
# secrets
secrets/
# @end expo-cli # @end expo-cli

8
.qwen/settings.json Normal file
View File

@@ -0,0 +1,8 @@
{
"permissions": {
"allow": [
"Bash(git add *)"
]
},
"$version": 3
}

7
.qwen/settings.json.orig Normal file
View File

@@ -0,0 +1,7 @@
{
"permissions": {
"allow": [
"Bash(git add *)"
]
}
}

30
QWEN.md
View File

@@ -387,7 +387,7 @@ apiConfig.interceptors.request.use(async (config) => {
### Deep Linking ### Deep Linking
- Scheme: `hipmimobile://` - Scheme: `hipmimobile://`
- HTTPS: `cld-dkr-staging-hipmi.wibudev.com` - HTTPS: `cld-dkr-hipmi-stg.wibudev.com`
- Configured for both platforms - Configured for both platforms
### Camera ### Camera
@@ -513,3 +513,31 @@ When using Maplibre MapView on iOS, prevent "Attempt to recycle a mounted view"
- [Expo Router Documentation](https://docs.expo.dev/router/introduction/) - [Expo Router Documentation](https://docs.expo.dev/router/introduction/)
- [TypeScript Documentation](https://www.typescriptlang.org/docs/) - [TypeScript Documentation](https://www.typescriptlang.org/docs/)
- [Maplibre React Native](https://github.com/maplibre/maplibre-react-native) - [Maplibre React Native](https://github.com/maplibre/maplibre-react-native)
## Qwen Added Memories
- OS_Wrapper contentPaddingBottom pattern:
- Default: contentPaddingBottom=100 (untuk list screens)
- Forms: contentPaddingBottom=250 (HANYA untuk screens yang punya TextInput/TextArea)
- contentPadding=0 (default, per-screen control)
- OS_ANDROID_PADDING_TOP=6 (compact tabs)
- OS_IOS_PADDING_TOP=12
- PADDING_INLINE=16 (constant)
Contoh:
```tsx
// List screen (default 100px)
<OS_Wrapper listData={data} renderItem={renderItem} />
// Form screen (explicit 250px)
<OS_Wrapper enableKeyboardHandling contentPaddingBottom={250}>
<FormWithTextInput />
</OS_Wrapper>
```
- PADDING_INLINE usage pattern - User preference:
- PADDING_INLINE (16px) TIDAK selalu diperlukan
- User remove PADDING_INLINE dari Profile screens karena mempersempit box tampilan
- Decision: Tambahkan PADDING_INLINE HANYA jika diperlukan per-screen, jangan default
- User akan review dan tambahkan sendiri jika perlu
Profile screens: PADDING_INLINE dihapus dari edit.tsx dan create.tsx
- User ingin mengecek semua user layout tabs setelah perubahan height layout tabs donation di constants. Pattern yang perlu dicek: semua tabs screens harus pakai contentPadding={PADDING_INLINE} untuk konsistensi layout.

View File

@@ -100,7 +100,7 @@ packagingOptions {
applicationId 'com.bip.hipmimobileapp' applicationId 'com.bip.hipmimobileapp'
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1 versionCode 5
versionName "1.0.2" versionName "1.0.2"
buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\"" buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\""

View File

@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" tools:replace="android:usesCleartextTraffic" />
</manifest>

View File

@@ -37,7 +37,7 @@
</intent-filter> </intent-filter>
<intent-filter android:autoVerify="true" data-generated="true"> <intent-filter android:autoVerify="true" data-generated="true">
<action android:name="android.intent.action.VIEW"/> <action android:name="android.intent.action.VIEW"/>
<data android:scheme="https" android:host="cld-dkr-hipmi-stg.wibudev.com" android:pathPrefix="/"/> <data android:scheme="https" android:host="hipmi.muku.id" android:pathPrefix="/"/>
<category android:name="android.intent.category.BROWSABLE"/> <category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT"/>
</intent-filter> </intent-filter>

View File

@@ -6,32 +6,17 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.google.gms:google-services:4.4.1' classpath 'com.google.gms:google-services:4.4.1'
classpath('com.android.tools.build:gradle') classpath('com.android.tools.build:gradle')
classpath('com.facebook.react:react-native-gradle-plugin') classpath('com.facebook.react:react-native-gradle-plugin')
classpath('org.jetbrains.kotlin:kotlin-gradle-plugin') classpath('org.jetbrains.kotlin:kotlin-gradle-plugin')
} }
} }
allprojects {
repositories {
google()
mavenCentral()
maven { url 'https://www.jitpack.io' }
}
}
apply plugin: "expo-root-project"
apply plugin: "com.facebook.react.rootproject"
// @generated begin @rnmapbox/maps-v2-maven - expo prebuild (DO NOT MODIFY) sync-d4ccbfdff48fdba3138b02a8ba41b9722af001d8
allprojects { allprojects {
repositories { repositories {
maven { maven {
url 'https://api.mapbox.com/downloads/v2/releases/maven' url 'https://api.mapbox.com/downloads/v2/releases/maven'
// Authentication is no longer required as per Mapbox's removal of download token requirement
// See: https://github.com/mapbox/mapbox-maps-flutter/issues/775
// Keeping this as optional for backward compatibility
def token = project.properties['MAPBOX_DOWNLOADS_TOKEN'] ?: System.getenv('RNMAPBOX_MAPS_DOWNLOAD_TOKEN') def token = project.properties['MAPBOX_DOWNLOADS_TOKEN'] ?: System.getenv('RNMAPBOX_MAPS_DOWNLOAD_TOKEN')
if (token) { if (token) {
authentication { basic(BasicAuthentication) } authentication { basic(BasicAuthentication) }
@@ -41,7 +26,11 @@ allprojects {
} }
} }
} }
google()
mavenCentral()
maven { url 'https://www.jitpack.io' }
} }
} }
// @generated end @rnmapbox/maps-v2-maven apply plugin: "expo-root-project"
apply plugin: "com.facebook.react.rootproject"

View File

@@ -25,27 +25,27 @@ export default {
ios: { ios: {
supportsTablet: true, supportsTablet: true,
bundleIdentifier: "com.anonymous.hipmi-mobile", bundleIdentifier: "com.anonymous.hipmi-mobile",
googleServicesFile: "./ios/HIPMIBadungConnect/GoogleService-Info.plist", googleServicesFile: "./secrets/GoogleService-Info.plist",
infoPlist: { infoPlist: {
ITSAppUsesNonExemptEncryption: false, ITSAppUsesNonExemptEncryption: false,
NSLocationWhenInUseUsageDescription: NSLocationWhenInUseUsageDescription:
"Aplikasi membutuhkan akses lokasi untuk menampilkan peta.", "Aplikasi membutuhkan akses lokasi untuk menampilkan peta.",
}, },
associatedDomains: [ associatedDomains: [
"applinks:cld-dkr-hipmi-stg.wibudev.com", "applinks:hipmi.muku.id",
], ],
buildNumber: "5", buildNumber: "7",
}, },
android: { android: {
googleServicesFile: "./google-services.json", googleServicesFile: "./secrets/google-services.json",
adaptiveIcon: { adaptiveIcon: {
foregroundImage: "./assets/images/splash-icon.png", foregroundImage: "./assets/images/splash-icon.png",
backgroundColor: "#ffffff", backgroundColor: "#ffffff",
}, },
edgeToEdgeEnabled: true, edgeToEdgeEnabled: true,
package: "com.bip.hipmimobileapp", package: "com.bip.hipmimobileapp",
versionCode: 1, versionCode: 5,
// softwareKeyboardLayoutMode: 'resize', // option: untuk mengatur keyboard pada room chst collaboration // softwareKeyboardLayoutMode: 'resize', // option: untuk mengatur keyboard pada room chst collaboration
intentFilters: [ intentFilters: [
{ {
@@ -54,7 +54,7 @@ export default {
data: [ data: [
{ {
scheme: "https", scheme: "https",
host: "cld-dkr-hipmi-stg.wibudev.com", host: "hipmi.muku.id",
pathPrefix: "/", pathPrefix: "/",
}, },
], ],
@@ -70,6 +70,7 @@ export default {
}, },
plugins: [ plugins: [
"./plugins/withCustomConfig",
"expo-router", "expo-router",
"expo-web-browser", "expo-web-browser",
[ [

View File

@@ -1,4 +1,5 @@
import { BackButton } from "@/components"; import { BackButton } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import PdfViewer from "@/components/_ShareComponent/PdfViewer"; import PdfViewer from "@/components/_ShareComponent/PdfViewer";
import API_STRORAGE from "@/constants/base-url-api-strorage"; import API_STRORAGE from "@/constants/base-url-api-strorage";
import { Stack, useLocalSearchParams } from "expo-router"; import { Stack, useLocalSearchParams } from "expo-router";
@@ -7,13 +8,12 @@ import { SafeAreaView } from "react-native-safe-area-context";
export default function FileScreen() { export default function FileScreen() {
const { id } = useLocalSearchParams(); const { id } = useLocalSearchParams();
const url = API_STRORAGE.GET({ fileId: id as string }); const url = API_STRORAGE.GET({ fileId: id as string });
return ( return (
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: "File", header: () => <AppHeader title="File" left={<BackButton />} />,
headerLeft: () => <BackButton />,
}} }}
/> />
<SafeAreaView style={{ flex: 1 }} edges={["bottom"]}> <SafeAreaView style={{ flex: 1 }} edges={["bottom"]}>

View File

@@ -1,29 +1,27 @@
import { BackButton } from "@/components"; import { BackButton } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { IconPlus } from "@/components/_Icon"; import { IconPlus } from "@/components/_Icon";
import { IconDot } from "@/components/_Icon/IconComponent"; import { IconDot } from "@/components/_Icon/IconComponent";
import LeftButtonCustom from "@/components/Button/BackButton"; import LeftButtonCustom from "@/components/Button/BackButton";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_SMALL } from "@/constants/constans-value"; import { ICON_SIZE_SMALL } from "@/constants/constans-value";
import { HeaderStyles } from "@/styles/header-styles";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import { router, Stack } from "expo-router"; import { router, Stack } from "expo-router";
export default function UserLayout() { export default function UserLayout() {
return ( return (
<> <>
<Stack screenOptions={HeaderStyles}> <Stack>
<Stack.Screen <Stack.Screen
name="delete-account" name="delete-account"
options={{ options={{
title: "Hapus Akun", header: () => <AppHeader title="Hapus Akun" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="waiting-room" name="waiting-room"
options={{ options={{
title: "Waiting Room", header: () => <AppHeader title="Waiting Room" />,
headerBackVisible: false,
}} }}
/> />
@@ -47,8 +45,7 @@ export default function UserLayout() {
<Stack.Screen <Stack.Screen
name="user-search/index" name="user-search/index"
options={{ options={{
title: "Pencarian Pengguna", header: () => <AppHeader title="Pencarian Pengguna" />,
headerLeft: () => <BackButton />,
}} }}
/> />
@@ -71,10 +68,18 @@ export default function UserLayout() {
{/* ========== Event Section ========= */} {/* ========== Event Section ========= */}
{/* <Stack.Screen
name="event/(tabs)"
options={{
header: () => <AppHeader title="Event" left={<BackButton path="/home" />} />,
}}
/> */}
<Stack.Screen <Stack.Screen
name="event/(tabs)" name="event/(tabs)"
options={{ options={{
title: "Event", title: "Event",
header: () => <AppHeader title="Event" left={<BackButton path="/home" />} />,
// NOTE: DIPINDAH DI FILE /Event/(Tabs)/_layout.tsx // NOTE: DIPINDAH DI FILE /Event/(Tabs)/_layout.tsx
// headerLeft: () => ( // headerLeft: () => (
// <LeftButtonCustom path="/(application)/(user)/home" /> // <LeftButtonCustom path="/(application)/(user)/home" />
@@ -85,32 +90,28 @@ export default function UserLayout() {
<Stack.Screen <Stack.Screen
name="event/create" name="event/create"
options={{ options={{
title: "Tambah Event", header: () => <AppHeader title="Tambah Event" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="event/detail/[id]" name="event/detail/[id]"
options={{ options={{
title: "Event Detail", header: () => <AppHeader title="Event Detail" left={<LeftButtonCustom />} />,
headerLeft: () => <LeftButtonCustom />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="event/[id]/edit" name="event/[id]/edit"
options={{ options={{
title: "Edit Event", header: () => <AppHeader title="Edit Event" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="event/[id]/list-of-participants" name="event/[id]/list-of-participants"
options={{ options={{
title: "Daftar peserta", header: () => <AppHeader title="Daftar peserta" />,
headerLeft: () => <BackButton />,
}} }}
/> />
{/* ========== End Event Section ========= */} {/* ========== End Event Section ========= */}
@@ -119,22 +120,19 @@ export default function UserLayout() {
<Stack.Screen <Stack.Screen
name="collaboration/(tabs)" name="collaboration/(tabs)"
options={{ options={{
title: "Collaboration", header: () => <AppHeader title="Collaboration" left={<BackButton path="/home" />} />,
headerLeft: () => <BackButton path="/home" />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="collaboration/create" name="collaboration/create"
options={{ options={{
title: "Tambah Proyek", header: () => <AppHeader title="Tambah Proyek" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="collaboration/[id]/list-of-participants" name="collaboration/[id]/list-of-participants"
options={{ options={{
title: "Daftar Partisipan", header: () => <AppHeader title="Daftar Partisipan" />,
headerLeft: () => <BackButton />,
}} }}
/> />
{/* <Stack.Screen {/* <Stack.Screen
@@ -147,22 +145,19 @@ export default function UserLayout() {
<Stack.Screen <Stack.Screen
name="collaboration/[id]/edit" name="collaboration/[id]/edit"
options={{ options={{
title: "Edit Proyek", header: () => <AppHeader title="Edit Proyek" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="collaboration/[id]/create-pacticipants" name="collaboration/[id]/create-pacticipants"
options={{ options={{
title: "Ajukan Partisipasi", header: () => <AppHeader title="Ajukan Partisipasi" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="collaboration/[id]/select-of-participants" name="collaboration/[id]/select-of-participants"
options={{ options={{
title: "Pilih Partisipan", header: () => <AppHeader title="Pilih Partisipan" />,
headerLeft: () => <BackButton />,
}} }}
/> />
@@ -172,29 +167,25 @@ export default function UserLayout() {
<Stack.Screen <Stack.Screen
name="voting/create" name="voting/create"
options={{ options={{
title: "Tambah Voting", header: () => <AppHeader title="Tambah Voting" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="voting/(tabs)" name="voting/(tabs)"
options={{ options={{
title: "Voting", header: () => <AppHeader title="Voting" left={<BackButton path="/home" />} />,
headerLeft: () => <BackButton path="/home" />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="voting/[id]/edit" name="voting/[id]/edit"
options={{ options={{
title: "Edit Voting", header: () => <AppHeader title="Edit Voting" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="voting/[id]/list-of-contributor" name="voting/[id]/list-of-contributor"
options={{ options={{
title: "Daftar Kontributor", header: () => <AppHeader title="Daftar Kontributor" />,
headerLeft: () => <BackButton />,
}} }}
/> />
@@ -204,8 +195,7 @@ export default function UserLayout() {
<Stack.Screen <Stack.Screen
name="crowdfunding/index" name="crowdfunding/index"
options={{ options={{
title: "Crowdfunding", header: () => <AppHeader title="Crowdfunding" left={<BackButton path="/home" />} />,
headerLeft: () => <BackButton path="/home" />,
}} }}
/> />
@@ -215,103 +205,95 @@ export default function UserLayout() {
<Stack.Screen <Stack.Screen
name="investment/(tabs)" name="investment/(tabs)"
options={{ options={{
title: "Investasi", header: () => <AppHeader title="Investasi" left={<BackButton path="/crowdfunding" />} />,
headerLeft: () => <BackButton path="/crowdfunding" />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="investment/create" name="investment/create"
options={{ options={{
title: "Tambah Investasi", header: () => <AppHeader title="Tambah Investasi" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="investment/[id]/index" name="investment/[id]/index"
options={{ options={{
title: "Detail Investasi", header: () => <AppHeader title="Detail Investasi" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="investment/[id]/edit" name="investment/[id]/edit"
options={{ options={{
title: "Edit Investasi", header: () => <AppHeader title="Edit Investasi" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="investment/[id]/edit-prospectus" name="investment/[id]/edit-prospectus"
options={{ options={{
title: "Edit Prospektus", header: () => <AppHeader title="Edit Prospektus" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="investment/[id]/(document)/list-of-document" name="investment/[id]/(document)/list-of-document"
options={{ options={{
title: "Daftar Dokumen", header: () => <AppHeader title="Daftar Dokumen" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="investment/[id]/(document)/add-document" name="investment/[id]/(document)/add-document"
options={{ options={{
title: "Tambah Dokumen", header: () => <AppHeader title="Tambah Dokumen" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="investment/[id]/(document)/edit-document" name="investment/[id]/(document)/edit-document"
options={{ options={{
title: "Edit Dokumen", header: () => <AppHeader title="Edit Dokumen" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="investment/[id]/(news)/add-news" name="investment/[id]/(news)/add-news"
options={{ options={{
title: "Tambah Berita", header: () => <AppHeader title="Tambah Berita" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="investment/[id]/investor" name="investment/[id]/investor"
options={{ options={{
title: "Investor", header: () => <AppHeader title="Investor" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="investment/[id]/(transaction-flow)/index" name="investment/[id]/(transaction-flow)/index"
options={{ options={{
title: "Pembelian Saham", header: () => <AppHeader title="Pembelian Saham" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="investment/[id]/(transaction-flow)/select-bank" name="investment/[id]/(transaction-flow)/select-bank"
options={{ options={{
title: "Pilih Bank", header: () => <AppHeader title="Pilih Bank" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="investment/[id]/(transaction-flow)/invoice" name="investment/[id]/(transaction-flow)/invoice"
options={{ options={{
title: "Invoice", header: () => (
headerLeft: () => ( <AppHeader
<Ionicons title="Invoice"
name="close" left={
size={ICON_SIZE_SMALL} <Ionicons
color={MainColor.yellow} name="close"
onPress={() => size={ICON_SIZE_SMALL}
router.navigate(`/investment/(tabs)/transaction`) color={MainColor.yellow}
onPress={() =>
router.navigate(`/investment/(tabs)/transaction`)
}
/>
} }
/> />
), ),
@@ -320,14 +302,18 @@ export default function UserLayout() {
<Stack.Screen <Stack.Screen
name="investment/[id]/(transaction-flow)/process" name="investment/[id]/(transaction-flow)/process"
options={{ options={{
title: "Proses", header: () => (
headerLeft: () => ( <AppHeader
<Ionicons title="Proses"
name="close" left={
size={ICON_SIZE_SMALL} <Ionicons
color={MainColor.yellow} name="close"
onPress={() => size={ICON_SIZE_SMALL}
router.navigate(`/investment/(tabs)/transaction`) color={MainColor.yellow}
onPress={() =>
router.navigate(`/investment/(tabs)/transaction`)
}
/>
} }
/> />
), ),
@@ -336,23 +322,20 @@ export default function UserLayout() {
<Stack.Screen <Stack.Screen
name="investment/[id]/(transaction-flow)/success" name="investment/[id]/(transaction-flow)/success"
options={{ options={{
title: "Transaksi Berhasil", header: () => <AppHeader title="Transaksi Berhasil" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="investment/[id]/(transaction-flow)/failed" name="investment/[id]/(transaction-flow)/failed"
options={{ options={{
title: "Transaksi Gagal", header: () => <AppHeader title="Transaksi Gagal" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="investment/[id]/(my-holding)/[id]" name="investment/[id]/(my-holding)/[id]"
options={{ options={{
title: "Detail Saham Saya", header: () => <AppHeader title="Detail Saham Saya" />,
headerLeft: () => <BackButton />,
}} }}
/> />
{/* ========== End Investment Section ========= */} {/* ========== End Investment Section ========= */}
@@ -361,122 +344,111 @@ export default function UserLayout() {
<Stack.Screen <Stack.Screen
name="donation/(tabs)" name="donation/(tabs)"
options={{ options={{
title: "Donasi", header: () => <AppHeader title="Donasi" left={<BackButton path="/crowdfunding" />} />,
headerLeft: () => <BackButton path="/crowdfunding" />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="donation/create" name="donation/create"
options={{ options={{
title: "Tambah Donasi", header: () => <AppHeader title="Tambah Donasi" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="donation/create-story" name="donation/create-story"
options={{ options={{
title: "Tambah Donasi", header: () => <AppHeader title="Tambah Donasi" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="donation/[id]/edit" name="donation/[id]/edit"
options={{ options={{
title: "Edit Donasi", header: () => <AppHeader title="Edit Donasi" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="donation/[id]/edit-story" name="donation/[id]/edit-story"
options={{ options={{
title: "Edit Donasi", header: () => <AppHeader title="Edit Donasi" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="donation/[id]/edit-rekening" name="donation/[id]/edit-rekening"
options={{ options={{
title: "Edit Rekening", header: () => <AppHeader title="Edit Rekening" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="donation/[id]/detail-story" name="donation/[id]/detail-story"
options={{ options={{
title: "Cerita Penggalang", header: () => <AppHeader title="Cerita Penggalang" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="donation/[id]/infromation-fundrising" name="donation/[id]/infromation-fundrising"
options={{ options={{
title: "Informasi Penggalang Dana", header: () => <AppHeader title="Informasi Penggalang Dana" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="donation/[id]/list-of-donatur" name="donation/[id]/list-of-donatur"
options={{ options={{
title: "Daftar Donatur", header: () => <AppHeader title="Daftar Donatur" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="donation/[id]/fund-disbursement" name="donation/[id]/fund-disbursement"
options={{ options={{
title: "Pencairan Dana", header: () => <AppHeader title="Pencairan Dana" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="donation/[id]/(news)/recap-of-news" name="donation/[id]/(news)/recap-of-news"
options={{ options={{
title: "Rekap Kabar", header: () => <AppHeader title="Rekap Kabar" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="donation/[id]/(news)/add-news" name="donation/[id]/(news)/add-news"
options={{ options={{
title: "Tambah Berita", header: () => <AppHeader title="Tambah Berita" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="donation/[id]/(news)/[news]/edit-news" name="donation/[id]/(news)/[news]/edit-news"
options={{ options={{
title: "Edit Berita", header: () => <AppHeader title="Edit Berita" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="donation/[id]/(transaction-flow)/index" name="donation/[id]/(transaction-flow)/index"
options={{ options={{
title: "Donasi", header: () => <AppHeader title="Donasi" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="donation/[id]/(transaction-flow)/select-bank" name="donation/[id]/(transaction-flow)/select-bank"
options={{ options={{
title: "Pilih Bank", header: () => <AppHeader title="Pilih Bank" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="donation/[id]/(transaction-flow)/[invoiceId]/invoice" name="donation/[id]/(transaction-flow)/[invoiceId]/invoice"
options={{ options={{
title: "Invoice", header: () => (
headerLeft: () => ( <AppHeader
<Ionicons title="Invoice"
name="close" left={
size={ICON_SIZE_SMALL} <Ionicons
color={MainColor.yellow} name="close"
onPress={() => router.navigate(`/donation/(tabs)/my-donation`)} size={ICON_SIZE_SMALL}
color={MainColor.yellow}
onPress={() => router.navigate(`/donation/(tabs)/my-donation`)}
/>
}
/> />
), ),
}} }}
@@ -484,13 +456,17 @@ export default function UserLayout() {
<Stack.Screen <Stack.Screen
name="donation/[id]/(transaction-flow)/[invoiceId]/process" name="donation/[id]/(transaction-flow)/[invoiceId]/process"
options={{ options={{
title: "Proses", header: () => (
headerLeft: () => ( <AppHeader
<Ionicons title="Proses"
name="close" left={
size={ICON_SIZE_SMALL} <Ionicons
color={MainColor.yellow} name="close"
onPress={() => router.navigate(`/donation/(tabs)/my-donation`)} size={ICON_SIZE_SMALL}
color={MainColor.yellow}
onPress={() => router.navigate(`/donation/(tabs)/my-donation`)}
/>
}
/> />
), ),
}} }}
@@ -498,55 +474,51 @@ export default function UserLayout() {
<Stack.Screen <Stack.Screen
name="donation/[id]/(transaction-flow)/[invoiceId]/success" name="donation/[id]/(transaction-flow)/[invoiceId]/success"
options={{ options={{
title: "Donasi Berhasil", header: () => <AppHeader title="Donasi Berhasil" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="donation/[id]/(transaction-flow)/[invoiceId]/failed" name="donation/[id]/(transaction-flow)/[invoiceId]/failed"
options={{ options={{
title: "Donasi Gagal", header: () => <AppHeader title="Donasi Gagal" />,
headerLeft: () => <BackButton />,
}} }}
/> />
{/* ========== End Donation Section ========= */} {/* ========== End Donation Section ========= */}
{/* ========== Job Section ========= */} {/* ========== Job Section ========= */}
<Stack.Screen <Stack.Screen
name="job/create" name="job/create"
options={{ options={{
title: "Tambah Job", header: () => <AppHeader title="Tambah Job" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="job/(tabs)" name="job/(tabs)"
options={{ options={{
title: "Job Vacancy", title: "Job Vacancy",
// headerLeft: () => <BackButton path="/home" />,
// NOTE: headerLeft di pindahkan ke Tabs Layout // NOTE: headerLeft di pindahkan ke Tabs Layout
header: () => <AppHeader title="Job Vacancy" left={<BackButton path="/home" />} />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="job/[id]/index" name="job/[id]/index"
options={{ options={{
title: "Detail Job", header: () => <AppHeader title="Detail Job" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="job/[id]/edit" name="job/[id]/edit"
options={{ options={{
title: "Edit Job", header: () => <AppHeader title="Edit Job" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="job/[id]/archive" name="job/[id]/archive"
options={{ options={{
title: "Arsip Job", header: () => <AppHeader title="Arsip Job" />,
headerLeft: () => <BackButton />,
}} }}
/> />
@@ -556,78 +528,67 @@ export default function UserLayout() {
<Stack.Screen <Stack.Screen
name="forum/create" name="forum/create"
options={{ options={{
title: "Tambah Diskusi", header: () => <AppHeader title="Tambah Diskusi" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="forum/[id]/edit" name="forum/[id]/edit"
options={{ options={{
title: "Edit Diskusi", header: () => <AppHeader title="Edit Diskusi" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="forum/[id]/forumku" name="forum/[id]/forumku"
options={{ options={{
title: "Forumku", header: () => <AppHeader title="Forumku" left={<BackButton icon={"close"} />} />,
headerLeft: () => <BackButton icon={"close"} />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="forum/[id]/index" name="forum/[id]/index"
options={{ options={{
title: "Detail", header: () => <AppHeader title="Detail" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="forum/[id]/report-commentar" name="forum/[id]/report-commentar"
options={{ options={{
title: "Laporkan Komentar", header: () => <AppHeader title="Laporkan Komentar" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="forum/[id]/other-report-commentar" name="forum/[id]/other-report-commentar"
options={{ options={{
title: "Laporkan Komentar", header: () => <AppHeader title="Laporkan Komentar" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="forum/[id]/report-posting" name="forum/[id]/report-posting"
options={{ options={{
title: "Laporkan Diskusi", header: () => <AppHeader title="Laporkan Diskusi" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="forum/[id]/other-report-posting" name="forum/[id]/other-report-posting"
options={{ options={{
title: "Laporkan Diskusi", header: () => <AppHeader title="Laporkan Diskusi" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="forum/terms" name="forum/terms"
options={{ options={{
title: "Syarat & Ketentuan Forum", header: () => <AppHeader title="Syarat & Ketentuan Forum" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="forum/[id]/preview-report-posting" name="forum/[id]/preview-report-posting"
options={{ options={{
title: "Laporan Postingan", header: () => <AppHeader title="Laporan Postingan" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="forum/[id]/preview-report-comment" name="forum/[id]/preview-report-comment"
options={{ options={{
title: "Laporan Komentar", header: () => <AppHeader title="Laporan Komentar" />,
headerLeft: () => <BackButton />,
}} }}
/> />
@@ -635,29 +596,25 @@ export default function UserLayout() {
<Stack.Screen <Stack.Screen
name="maps/index" name="maps/index"
options={{ options={{
title: "Maps", header: () => <AppHeader title="Maps" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="maps/create" name="maps/create"
options={{ options={{
title: "Tambah Maps", header: () => <AppHeader title="Tambah Maps" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="maps/[id]/edit" name="maps/[id]/edit"
options={{ options={{
title: "Edit Maps", header: () => <AppHeader title="Edit Maps" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="maps/[id]/custom-pin" name="maps/[id]/custom-pin"
options={{ options={{
title: "Custom Pin Maps", header: () => <AppHeader title="Custom Pin Maps" />,
headerLeft: () => <BackButton />,
}} }}
/> />
@@ -665,8 +622,7 @@ export default function UserLayout() {
<Stack.Screen <Stack.Screen
name="marketplace/index" name="marketplace/index"
options={{ options={{
title: "Market Place", header: () => <AppHeader title="Market Place" />,
headerLeft: () => <BackButton />,
}} }}
/> />
</Stack> </Stack>

View File

@@ -2,35 +2,64 @@ import { IconHome } from "@/components/_Icon";
import { TabsStyles } from "@/styles/tabs-styles"; import { TabsStyles } from "@/styles/tabs-styles";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import { Tabs } from "expo-router"; import { Tabs } from "expo-router";
import { View } from "react-native";
import { MainColor } from "@/constants/color-palet";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { Platform } from "react-native";
function CollaborationTabsWrapper() {
const insets = useSafeAreaInsets();
const paddingBottom = Platform.OS === "android" ? insets.bottom : 0;
export default function CollaborationTabsLayout() {
return ( return (
<Tabs screenOptions={TabsStyles}> <View style={{ flex: 1, backgroundColor: MainColor.darkblue }}>
<Tabs.Screen <Tabs
name="index" screenOptions={{
options={{ ...TabsStyles,
title: "Beranda", tabBarStyle: Platform.select({
tabBarIcon: ({ color }) => <IconHome color={color} />, ios: {
borderTopWidth: 0,
paddingTop: 12,
height: 80,
},
android: {
borderTopWidth: 0,
paddingTop: 5,
height: 70 + paddingBottom,
},
}),
}} }}
/> >
<Tabs.Screen <Tabs.Screen
name="participant" name="index"
options={{ options={{
title: "Partisipan", title: "Beranda",
tabBarIcon: ({ color }) => ( tabBarIcon: ({ color }) => <IconHome color={color} />,
<Ionicons size={20} name="people" color={color} /> }}
), />
}} <Tabs.Screen
/> name="participant"
<Tabs.Screen options={{
name="group" title: "Partisipan",
options={{ tabBarIcon: ({ color }) => (
title: "Grup", <Ionicons size={20} name="people" color={color} />
tabBarIcon: ({ color }) => ( ),
<Ionicons size={20} name="chatbox-ellipses" color={color} /> }}
), />
}} <Tabs.Screen
/> name="group"
</Tabs> options={{
title: "Grup",
tabBarIcon: ({ color }) => (
<Ionicons size={20} name="chatbox-ellipses" color={color} />
),
}}
/>
</Tabs>
</View>
); );
} }
export default function CollaborationTabsLayout() {
return <CollaborationTabsWrapper />;
}

View File

@@ -10,6 +10,7 @@ import {
TextCustom, TextCustom,
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { apiCollaborationGroup } from "@/service/api-client/api-collaboration"; import { apiCollaborationGroup } from "@/service/api-client/api-collaboration";
import { Stack, useFocusEffect, useLocalSearchParams } from "expo-router"; import { Stack, useFocusEffect, useLocalSearchParams } from "expo-router";
import { useState, useCallback } from "react"; import { useState, useCallback } from "react";
@@ -40,8 +41,7 @@ export default function CollaborationRoomInfo() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: `Info`, header: () => <AppHeader title="Info" left={<BackButton />} />,
headerLeft: () => <BackButton />,
}} }}
/> />

View File

@@ -1,4 +1,5 @@
import { BackButton } from "@/components"; import { BackButton } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_SMALL } from "@/constants/constans-value"; import { ICON_SIZE_SMALL } from "@/constants/constans-value";
import ChatScreen from "@/screens/Collaboration/GroupChatSection"; import ChatScreen from "@/screens/Collaboration/GroupChatSection";
@@ -12,14 +13,18 @@ export default function CollaborationRoomChat() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: `Proyek ${detail}`, header: () => (
headerLeft: () => <BackButton />, <AppHeader
headerRight: () => ( title={`Proyek ${detail}`}
<Feather left={<BackButton />}
name="info" right={
size={ICON_SIZE_SMALL} <Feather
color={MainColor.yellow} name="info"
onPress={() => router.push(`/collaboration/${id}/${detail}/info`)} size={ICON_SIZE_SMALL}
color={MainColor.yellow}
onPress={() => router.push(`/collaboration/${id}/${detail}/info`)}
/>
}
/> />
), ),
}} }}

View File

@@ -6,6 +6,7 @@ import {
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
ViewWrapper ViewWrapper
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import Collaboration_BoxDetailSection from "@/screens/Collaboration/BoxDetailSection"; import Collaboration_BoxDetailSection from "@/screens/Collaboration/BoxDetailSection";
import { apiCollaborationGetOne } from "@/service/api-client/api-collaboration"; import { apiCollaborationGetOne } from "@/service/api-client/api-collaboration";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
@@ -38,10 +39,14 @@ export default function CollaborationDetailParticipant() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: "Detail Proyek", header: () => (
headerLeft: () => <BackButton />, <AppHeader
headerRight: () => ( title="Detail Proyek"
<DotButton onPress={() => setOpenDrawerParticipant(true)} /> left={<BackButton />}
right={
<DotButton onPress={() => setOpenDrawerParticipant(true)} />
}
/>
), ),
}} }}
/> />

View File

@@ -8,6 +8,7 @@ import {
Spacing, Spacing,
ViewWrapper ViewWrapper
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { IconEdit } from "@/components/_Icon"; import { IconEdit } from "@/components/_Icon";
import Collaboration_BoxDetailSection from "@/screens/Collaboration/BoxDetailSection"; import Collaboration_BoxDetailSection from "@/screens/Collaboration/BoxDetailSection";
import { import {
@@ -66,9 +67,13 @@ export default function CollaborationDetailProjectMain() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: "Proyek Saya", header: () => (
headerLeft: () => <BackButton />, <AppHeader
headerRight: () => <DotButton onPress={() => setOpenDrawer(true)} />, title="Proyek Saya"
left={<BackButton />}
right={<DotButton onPress={() => setOpenDrawer(true)} />}
/>
),
}} }}
/> />
<ViewWrapper> <ViewWrapper>

View File

@@ -9,6 +9,7 @@ import {
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
import Collaboration_BoxDetailSection from "@/screens/Collaboration/BoxDetailSection"; import Collaboration_BoxDetailSection from "@/screens/Collaboration/BoxDetailSection";
import { import {
@@ -74,10 +75,14 @@ export default function CollaborationDetail() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: "Detail Proyek", header: () => (
headerLeft: () => <BackButton />, <AppHeader
headerRight: () => ( title="Detail Proyek"
<DotButton onPress={() => setOpenDrawerMenu(true)} /> left={<BackButton />}
right={
<DotButton onPress={() => setOpenDrawerMenu(true)} />
}
/>
), ),
}} }}
/> />

View File

@@ -1,9 +1,9 @@
import { import {
BaseBox, BaseBox,
Grid, Grid,
OS_Wrapper,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_SMALL } from "@/constants/constans-value"; import { ICON_SIZE_SMALL } from "@/constants/constans-value";
@@ -25,7 +25,7 @@ export default function Crowdfunding() {
]; ];
return ( return (
<ViewWrapper> <OS_Wrapper>
<StackCustom> <StackCustom>
<Image <Image
source={require("@/assets/images/constants/crowd-hipmi.png")} source={require("@/assets/images/constants/crowd-hipmi.png")}
@@ -63,6 +63,6 @@ export default function Crowdfunding() {
</BaseBox> </BaseBox>
))} ))}
</StackCustom> </StackCustom>
</ViewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -3,10 +3,10 @@ import {
BaseBox, BaseBox,
ButtonCustom, ButtonCustom,
CenterCustom, CenterCustom,
OS_Wrapper,
StackCustom, StackCustom,
TextCustom, TextCustom,
TextInputCustom, TextInputCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
import { apiDeleteUser } from "@/service/api-client/api-user"; import { apiDeleteUser } from "@/service/api-client/api-user";
@@ -68,7 +68,10 @@ export default function DeleteAccount() {
return ( return (
<> <>
<ViewWrapper> <OS_Wrapper
enableKeyboardHandling
contentPaddingBottom={250}
>
<StackCustom> <StackCustom>
<BaseBox> <BaseBox>
<StackCustom> <StackCustom>
@@ -105,7 +108,7 @@ export default function DeleteAccount() {
</StackCustom> </StackCustom>
</BaseBox> </BaseBox>
</StackCustom> </StackCustom>
</ViewWrapper> </OS_Wrapper>
</> </>
); );
} }

View File

@@ -1,37 +1,66 @@
import { IconHome, IconStatus } from "@/components/_Icon"; import { IconHome, IconStatus } from "@/components/_Icon";
import { ICON_SIZE_SMALL } from "@/constants/constans-value"; import { ICON_SIZE_SMALL, OS_ANDROID_HEIGHT, OS_IOS_HEIGHT } from "@/constants/constans-value";
import { TabsStyles } from "@/styles/tabs-styles"; import { TabsStyles } from "@/styles/tabs-styles";
import { import {
FontAwesome5 FontAwesome5
} from "@expo/vector-icons"; } from "@expo/vector-icons";
import { Tabs } from "expo-router"; import { Tabs } from "expo-router";
import { View } from "react-native";
import { MainColor } from "@/constants/color-palet";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { Platform } from "react-native";
function DonationTabsWrapper() {
const insets = useSafeAreaInsets();
const paddingBottom = Platform.OS === "android" ? insets.bottom : 0;
export default function InvestmentTabsLayout() {
return ( return (
<Tabs screenOptions={TabsStyles}> <View style={{ flex: 1, backgroundColor: MainColor.darkblue }}>
<Tabs.Screen <Tabs
name="index" screenOptions={{
options={{ ...TabsStyles,
title: "Beranda", tabBarStyle: Platform.select({
tabBarIcon: ({ color }) => <IconHome color={color} />, ios: {
borderTopWidth: 0,
paddingTop: 12,
height: OS_IOS_HEIGHT,
},
android: {
borderTopWidth: 0,
paddingTop: 5,
height: OS_ANDROID_HEIGHT + paddingBottom,
},
}),
}} }}
/> >
<Tabs.Screen <Tabs.Screen
name="status" name="index"
options={{ options={{
title: "Galang Dana", title: "Beranda",
tabBarIcon: ({ color }) => <IconStatus color={color} />, tabBarIcon: ({ color }) => <IconHome color={color} />,
}} }}
/> />
<Tabs.Screen <Tabs.Screen
name="my-donation" name="status"
options={{ options={{
title: "Donasi Saya", title: "Galang Dana",
tabBarIcon: ({ color }) => ( tabBarIcon: ({ color }) => <IconStatus color={color} />,
<FontAwesome5 name="donate" color={color} size={ICON_SIZE_SMALL} /> }}
), />
}} <Tabs.Screen
/> name="my-donation"
</Tabs> options={{
title: "Donasi Saya",
tabBarIcon: ({ color }) => (
<FontAwesome5 name="donate" color={color} size={ICON_SIZE_SMALL} />
),
}}
/>
</Tabs>
</View>
); );
} }
export default function DonationTabsLayout() {
return <DonationTabsWrapper />;
}

View File

@@ -5,11 +5,11 @@ import {
ButtonCustom, ButtonCustom,
InformationBox, InformationBox,
LandscapeFrameUploaded, LandscapeFrameUploaded,
OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
TextAreaCustom, TextAreaCustom,
TextInputCustom, TextInputCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import API_STRORAGE from "@/constants/base-url-api-strorage"; import API_STRORAGE from "@/constants/base-url-api-strorage";
import DIRECTORY_ID from "@/constants/directory-id"; import DIRECTORY_ID from "@/constants/directory-id";
@@ -105,7 +105,9 @@ export default function DonationEditNews() {
}; };
return ( return (
<ViewWrapper <OS_Wrapper
enableKeyboardHandling
contentPaddingBottom={250}
footerComponent={ footerComponent={
<BoxButtonOnFooter> <BoxButtonOnFooter>
<ButtonCustom <ButtonCustom
@@ -165,6 +167,6 @@ export default function DonationEditNews() {
<Spacing /> <Spacing />
</StackCustom> </StackCustom>
<Spacing /> <Spacing />
</ViewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -7,10 +7,11 @@ import {
DrawerCustom, DrawerCustom,
DummyLandscapeImage, DummyLandscapeImage,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
OS_Wrapper,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { IconEdit } from "@/components/_Icon"; import { IconEdit } from "@/components/_Icon";
import { IconTrash } from "@/components/_Icon/IconTrash"; import { IconTrash } from "@/components/_Icon/IconTrash";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
@@ -27,6 +28,7 @@ import {
} from "expo-router"; } from "expo-router";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import Toast from "react-native-toast-message"; import Toast from "react-native-toast-message";
import { dateTimeView } from "@/utils/dateTimeView";
export default function DonationNews() { export default function DonationNews() {
const { user } = useAuth(); const { user } = useAuth();
@@ -57,19 +59,24 @@ export default function DonationNews() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: "Detail Kabar", header: () => (
headerLeft: () => <BackButton />, <AppHeader
headerRight: () => title="Detail Kabar"
user?.id === data?.authorId && ( left={<BackButton />}
<DotButton onPress={() => setOpenDrawer(true)} /> right={
), user?.id === data?.authorId && (
<DotButton onPress={() => setOpenDrawer(true)} />
)
}
/>
),
}} }}
/> />
<ViewWrapper> <OS_Wrapper>
<BaseBox> <BaseBox>
<StackCustom> <StackCustom>
<TextCustom style={{ alignSelf: "flex-end" }}> <TextCustom color="gray" size={"small"} style={{ alignSelf: "flex-end" }}>
{formatChatTime(data?.createdAt)} {dateTimeView({date: data?.createdAt})}
</TextCustom> </TextCustom>
{data && data.imageId && ( {data && data.imageId && (
@@ -83,7 +90,7 @@ export default function DonationNews() {
<TextCustom>{data?.deskripsi || "-"}</TextCustom> <TextCustom>{data?.deskripsi || "-"}</TextCustom>
</StackCustom> </StackCustom>
</BaseBox> </BaseBox>
</ViewWrapper> </OS_Wrapper>
<DrawerCustom <DrawerCustom
isVisible={openDrawer} isVisible={openDrawer}

View File

@@ -4,12 +4,11 @@ import {
ButtonCustom, ButtonCustom,
InformationBox, InformationBox,
LandscapeFrameUploaded, LandscapeFrameUploaded,
NewWrapper, OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
TextAreaCustom, TextAreaCustom,
TextInputCustom, TextInputCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import DIRECTORY_ID from "@/constants/directory-id"; import DIRECTORY_ID from "@/constants/directory-id";
import { apiDonationCreateNews } from "@/service/api-client/api-donation"; import { apiDonationCreateNews } from "@/service/api-client/api-donation";
@@ -72,7 +71,9 @@ export default function DonationAddNews() {
}; };
return ( return (
<NewWrapper <OS_Wrapper
enableKeyboardHandling
contentPaddingBottom={250}
footerComponent={ footerComponent={
<BoxButtonOnFooter> <BoxButtonOnFooter>
<ButtonCustom <ButtonCustom
@@ -133,6 +134,6 @@ export default function DonationAddNews() {
<Spacing /> <Spacing />
</StackCustom> </StackCustom>
</NewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -2,10 +2,10 @@
import { import {
BaseBox, BaseBox,
Grid, Grid,
OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { apiDonationGetInvoiceById } from "@/service/api-client/api-donation"; import { apiDonationGetInvoiceById } from "@/service/api-client/api-donation";
@@ -63,7 +63,7 @@ export default function DonasiFailed() {
]; ];
return ( return (
<ViewWrapper> <OS_Wrapper>
<StackCustom> <StackCustom>
<BaseBox> <BaseBox>
<StackCustom> <StackCustom>
@@ -105,6 +105,6 @@ export default function DonasiFailed() {
</StackCustom> </StackCustom>
</BaseBox> </BaseBox>
</StackCustom> </StackCustom>
</ViewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -6,10 +6,10 @@ import {
ButtonCustom, ButtonCustom,
Grid, Grid,
InformationBox, InformationBox,
OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import CopyButton from "@/components/Button/CoyButton"; import CopyButton from "@/components/Button/CoyButton";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
@@ -101,8 +101,7 @@ export default function DonationInvoice() {
return ( return (
<> <>
<ViewWrapper <OS_Wrapper
hideFooter
footerComponent={ footerComponent={
<BoxButtonOnFooter> <BoxButtonOnFooter>
<ButtonCustom <ButtonCustom
@@ -222,7 +221,7 @@ export default function DonationInvoice() {
</BaseBox> </BaseBox>
</StackCustom> </StackCustom>
<Spacing /> <Spacing />
</ViewWrapper> </OS_Wrapper>
</> </>
); );
} }

View File

@@ -1,11 +1,11 @@
import { BaseBox, StackCustom, TextCustom, ViewWrapper } from "@/components"; import { BaseBox, OS_Wrapper, StackCustom, TextCustom } from "@/components";
import MoneyTransferAnimation from "@/components/_ShareComponent/MoneyTransferAnimation"; import MoneyTransferAnimation from "@/components/_ShareComponent/MoneyTransferAnimation";
import { View } from "react-native"; import { View } from "react-native";
export default function DonationProcess() { export default function DonationProcess() {
return ( return (
<> <>
<ViewWrapper> <OS_Wrapper>
<BaseBox> <BaseBox>
<StackCustom> <StackCustom>
<TextCustom align="center" bold> <TextCustom align="center" bold>
@@ -35,7 +35,7 @@ export default function DonationProcess() {
</Grid.Col> </Grid.Col>
</Grid> </Grid>
</BaseBox> */} </BaseBox> */}
</ViewWrapper> </OS_Wrapper>
</> </>
); );
} }

View File

@@ -2,10 +2,10 @@
import { import {
BaseBox, BaseBox,
Grid, Grid,
OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { apiDonationGetInvoiceById } from "@/service/api-client/api-donation"; import { apiDonationGetInvoiceById } from "@/service/api-client/api-donation";
@@ -63,7 +63,7 @@ export default function DonationSuccess() {
]; ];
return ( return (
<ViewWrapper> <OS_Wrapper>
<StackCustom> <StackCustom>
<BaseBox> <BaseBox>
<StackCustom> <StackCustom>
@@ -105,7 +105,7 @@ export default function DonationSuccess() {
</StackCustom> </StackCustom>
</BaseBox> </BaseBox>
</StackCustom> </StackCustom>
</ViewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -3,9 +3,9 @@ import {
BoxButtonOnFooter, BoxButtonOnFooter,
ButtonCustom, ButtonCustom,
Grid, Grid,
OS_Wrapper,
TextCustom, TextCustom,
TextInputCustom, TextInputCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_SMALL } from "@/constants/constans-value"; import { ICON_SIZE_SMALL } from "@/constants/constans-value";
@@ -64,7 +64,7 @@ export default function InvestmentInputDonation() {
); );
return ( return (
<> <>
<ViewWrapper footerComponent={bottomComponent}> <OS_Wrapper enableKeyboardHandling contentPaddingBottom={250} footerComponent={bottomComponent}>
{listData.map((item, i) => ( {listData.map((item, i) => (
<BaseBox key={i} onPress={() => setNominal(item.value)}> <BaseBox key={i} onPress={() => setNominal(item.value)}>
<Grid> <Grid>
@@ -98,7 +98,7 @@ export default function InvestmentInputDonation() {
Minimal donasi Rp. 10.000 Minimal donasi Rp. 10.000
</TextCustom> </TextCustom>
</BaseBox> </BaseBox>
</ViewWrapper> </OS_Wrapper>
</> </>
); );
} }

View File

@@ -2,7 +2,7 @@ import {
BaseBox, BaseBox,
BoxButtonOnFooter, BoxButtonOnFooter,
ButtonCustom, ButtonCustom,
ViewWrapper, OS_Wrapper,
} from "@/components"; } from "@/components";
import { RadioCustom, RadioGroup } from "@/components/Radio/RadioCustom"; import { RadioCustom, RadioGroup } from "@/components/Radio/RadioCustom";
import { LOCAL_STORAGE_KEY } from "@/constants/local-storage-key"; import { LOCAL_STORAGE_KEY } from "@/constants/local-storage-key";
@@ -91,7 +91,7 @@ export default function DonationSelectBank() {
); );
}; };
return ( return (
<ViewWrapper footerComponent={buttonSubmit()}> <OS_Wrapper footerComponent={buttonSubmit()}>
<RadioGroup value={select} onChange={setSelect}> <RadioGroup value={select} onChange={setSelect}>
{_.isEmpty(listBank) {_.isEmpty(listBank)
? [] ? []
@@ -101,6 +101,6 @@ export default function DonationSelectBank() {
</BaseBox> </BaseBox>
))} ))}
</RadioGroup> </RadioGroup>
</ViewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -4,9 +4,10 @@ import {
DotButton, DotButton,
DrawerCustom, DrawerCustom,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
NewWrapper, OS_Wrapper,
Spacing, Spacing,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { IconEdit, IconNews } from "@/components/_Icon"; import { IconEdit, IconNews } from "@/components/_Icon";
import { IMenuDrawerItem } from "@/components/_Interface/types"; import { IMenuDrawerItem } from "@/components/_Interface/types";
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom"; import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
@@ -97,17 +98,22 @@ export default function DonasiDetailStatus() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: `Detail ${_.startCase(status as string)}`, header: () => (
headerLeft: () => <BackButton />, <AppHeader
headerRight: () => title={`Detail ${_.startCase(status as string)}`}
status === "draft" ? ( left={<BackButton />}
<DotButton onPress={() => setOpenDrawer(true)} /> right={
) : status === "publish" ? ( status === "draft" ? (
<DotButton onPress={() => setOpenDrawerPublish(true)} /> <DotButton onPress={() => setOpenDrawer(true)} />
) : null, ) : status === "publish" ? (
<DotButton onPress={() => setOpenDrawerPublish(true)} />
) : null
}
/>
),
}} }}
/> />
<NewWrapper <OS_Wrapper
refreshControl={ refreshControl={
<RefreshControl <RefreshControl
refreshing={refreshing} refreshing={refreshing}
@@ -150,7 +156,7 @@ export default function DonasiDetailStatus() {
<Spacing /> <Spacing />
</> </>
)} )}
</NewWrapper> </OS_Wrapper>
<DrawerCustom <DrawerCustom
isVisible={openDrawer} isVisible={openDrawer}

View File

@@ -1,9 +1,9 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { import {
DummyLandscapeImage, DummyLandscapeImage,
OS_Wrapper,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import { apiDonationGetOne } from "@/service/api-client/api-donation"; import { apiDonationGetOne } from "@/service/api-client/api-donation";
import { useFocusEffect, useLocalSearchParams } from "expo-router"; import { useFocusEffect, useLocalSearchParams } from "expo-router";
@@ -32,12 +32,12 @@ export default function DonationDetailStory() {
} }
}; };
return ( return (
<ViewWrapper> <OS_Wrapper>
<StackCustom> <StackCustom>
<TextCustom>{data?.pembukaan || "-"}</TextCustom> <TextCustom>{data?.pembukaan || "-"}</TextCustom>
<DummyLandscapeImage imageId={data?.imageId} /> <DummyLandscapeImage imageId={data?.imageId} />
<TextCustom>{data?.cerita || "-"}</TextCustom> <TextCustom>{data?.cerita || "-"}</TextCustom>
</StackCustom> </StackCustom>
</ViewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -1,6 +1,6 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { import {
ViewWrapper, OS_Wrapper,
StackCustom, StackCustom,
InformationBox, InformationBox,
TextInputCustom, TextInputCustom,
@@ -76,7 +76,7 @@ export default function DonationEditRekening() {
}; };
return ( return (
<ViewWrapper> <OS_Wrapper enableKeyboardHandling contentPaddingBottom={250}>
<StackCustom gap={"xs"}> <StackCustom gap={"xs"}>
<InformationBox text="Pastikan Anda mengisi nama bank dan nomor rekening dengan benar. Informasi ini akan membantu admin memverifikasi dan memproses penggalangan dana Anda dengan cepat dan tepat setelah penggalangan dana dipublikasikan." /> <InformationBox text="Pastikan Anda mengisi nama bank dan nomor rekening dengan benar. Informasi ini akan membantu admin memverifikasi dan memproses penggalangan dana Anda dengan cepat dan tepat setelah penggalangan dana dipublikasikan." />
<TextInputCustom <TextInputCustom
@@ -105,6 +105,6 @@ export default function DonationEditRekening() {
</ButtonCustom> </ButtonCustom>
</StackCustom> </StackCustom>
<Spacing /> <Spacing />
</ViewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -4,10 +4,10 @@ import {
ButtonCustom, ButtonCustom,
InformationBox, InformationBox,
LandscapeFrameUploaded, LandscapeFrameUploaded,
OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
TextAreaCustom, TextAreaCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import API_IMAGE from "@/constants/api-storage"; import API_IMAGE from "@/constants/api-storage";
import DIRECTORY_ID from "@/constants/directory-id"; import DIRECTORY_ID from "@/constants/directory-id";
@@ -93,7 +93,7 @@ export default function DonationEditStory() {
}; };
return ( return (
<ViewWrapper> <OS_Wrapper enableKeyboardHandling contentPaddingBottom={250}>
<StackCustom gap={"xs"}> <StackCustom gap={"xs"}>
<InformationBox text="Cerita Anda adalah kunci untuk menginspirasi kebaikan. Jelaskan dengan jujur dan jelas tujuan penggalangan dana ini agar calon donatur memahami dampak positif yang dapat mereka wujudkan melalui kontribusi mereka." /> <InformationBox text="Cerita Anda adalah kunci untuk menginspirasi kebaikan. Jelaskan dengan jujur dan jelas tujuan penggalangan dana ini agar calon donatur memahami dampak positif yang dapat mereka wujudkan melalui kontribusi mereka." />
<TextAreaCustom <TextAreaCustom
@@ -146,6 +146,6 @@ export default function DonationEditStory() {
</ButtonCustom> </ButtonCustom>
</StackCustom> </StackCustom>
<Spacing /> <Spacing />
</ViewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -6,12 +6,11 @@ import {
InformationBox, InformationBox,
LandscapeFrameUploaded, LandscapeFrameUploaded,
LoaderCustom, LoaderCustom,
NewWrapper, OS_Wrapper,
SelectCustom, SelectCustom,
Spacing, Spacing,
StackCustom, StackCustom,
TextInputCustom, TextInputCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import ListSkeletonComponent from "@/components/_ShareComponent/ListSkeletonComponent"; import ListSkeletonComponent from "@/components/_ShareComponent/ListSkeletonComponent";
import API_IMAGE from "@/constants/api-storage"; import API_IMAGE from "@/constants/api-storage";
@@ -184,8 +183,9 @@ export default function DonationEdit() {
}; };
return ( return (
<NewWrapper <OS_Wrapper
hideFooter enableKeyboardHandling
contentPaddingBottom={250}
footerComponent={ footerComponent={
<BoxButtonOnFooter> <BoxButtonOnFooter>
<ButtonCustom <ButtonCustom
@@ -279,6 +279,6 @@ export default function DonationEdit() {
</StackCustom> </StackCustom>
)} )}
<Spacing /> <Spacing />
</NewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -6,10 +6,10 @@ import {
DotButton, DotButton,
DrawerCustom, DrawerCustom,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
NewWrapper, OS_Wrapper,
StackCustom, StackCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { IconNews } from "@/components/_Icon"; import { IconNews } from "@/components/_Icon";
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom"; import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
@@ -90,15 +90,20 @@ export default function DonasiDetailBeranda() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: `Detail Donasi`, header: () => (
headerLeft: () => <BackButton />, <AppHeader
headerRight: () => title="Detail Donasi"
user?.id === data?.Author?.id ? ( left={<BackButton />}
<DotButton onPress={() => setOpenDrawer(true)} /> right={
) : null, user?.id === data?.Author?.id ? (
<DotButton onPress={() => setOpenDrawer(true)} />
) : null
}
/>
),
}} }}
/> />
<NewWrapper footerComponent={buttonSection}> <OS_Wrapper footerComponent={buttonSection}>
{!data ? ( {!data ? (
<CustomSkeleton height={400} /> <CustomSkeleton height={400} />
) : ( ) : (
@@ -121,7 +126,7 @@ export default function DonasiDetailBeranda() {
/> />
</StackCustom> </StackCustom>
)} )}
</NewWrapper> </OS_Wrapper>
<DrawerCustom <DrawerCustom
isVisible={openDrawer} isVisible={openDrawer}

View File

@@ -5,9 +5,9 @@ import {
ButtonCustom, ButtonCustom,
Grid, Grid,
LoaderCustom, LoaderCustom,
OS_Wrapper,
Spacing, Spacing,
TextCustom, TextCustom,
ViewWrapper
} from "@/components"; } from "@/components";
import Donation_BoxPublish from "@/screens/Donation/BoxPublish"; import Donation_BoxPublish from "@/screens/Donation/BoxPublish";
import { apiDonationFundrising } from "@/service/api-client/api-donation"; import { apiDonationFundrising } from "@/service/api-client/api-donation";
@@ -44,7 +44,7 @@ export default function DonationInformationFunrising() {
return ( return (
<> <>
<ViewWrapper> <OS_Wrapper>
<BaseBox> <BaseBox>
<Grid> <Grid>
<Grid.Col span={6} style={{ justifyContent: "center" }}> <Grid.Col span={6} style={{ justifyContent: "center" }}>
@@ -80,7 +80,7 @@ export default function DonationInformationFunrising() {
<Donation_BoxPublish key={index} id={item?.id} data={item} /> <Donation_BoxPublish key={index} id={item?.id} data={item} />
)) ))
)} )}
</ViewWrapper> </OS_Wrapper>
</> </>
); );
} }

View File

@@ -10,7 +10,7 @@ import {
TextAreaCustom, TextAreaCustom,
TextInputCustom, TextInputCustom,
} from "@/components"; } from "@/components";
import NewWrapper from "@/components/_ShareComponent/NewWrapper"; import OS_Wrapper from "@/components/_ShareComponent/OS_Wrapper";
import DIRECTORY_ID from "@/constants/directory-id"; import DIRECTORY_ID from "@/constants/directory-id";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
import { import {
@@ -113,8 +113,9 @@ export default function DonationCreateStory() {
}; };
return ( return (
<NewWrapper <OS_Wrapper
hideFooter enableKeyboardHandling
contentPaddingBottom={250}
footerComponent={ footerComponent={
<> <>
<BoxButtonOnFooter> <BoxButtonOnFooter>
@@ -185,6 +186,6 @@ export default function DonationCreateStory() {
/> />
</StackCustom> </StackCustom>
<Spacing /> <Spacing />
</NewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -5,12 +5,12 @@ import {
InformationBox, InformationBox,
LandscapeFrameUploaded, LandscapeFrameUploaded,
LoaderCustom, LoaderCustom,
OS_Wrapper,
SelectCustom, SelectCustom,
Spacing, Spacing,
StackCustom, StackCustom,
TextInputCustom, TextInputCustom,
} from "@/components"; } from "@/components";
import NewWrapper from "@/components/_ShareComponent/NewWrapper";
import DIRECTORY_ID from "@/constants/directory-id"; import DIRECTORY_ID from "@/constants/directory-id";
import { apiDonationCreate } from "@/service/api-client/api-donation"; import { apiDonationCreate } from "@/service/api-client/api-donation";
import { apiMasterDonation } from "@/service/api-client/api-master"; import { apiMasterDonation } from "@/service/api-client/api-master";
@@ -126,8 +126,9 @@ export default function DonationCreate() {
}; };
return ( return (
<NewWrapper <OS_Wrapper
hideFooter enableKeyboardHandling
contentPaddingBottom={250}
footerComponent={ footerComponent={
<> <>
<BoxButtonOnFooter> <BoxButtonOnFooter>
@@ -221,6 +222,6 @@ export default function DonationCreate() {
)} )}
</StackCustom> </StackCustom>
<Spacing /> <Spacing />
</NewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -4,64 +4,87 @@ import {
IconHome, IconHome,
IconStatus, IconStatus,
} from "@/components/_Icon"; } from "@/components/_Icon";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import BackButtonFromNotification from "@/components/Button/BackButtonFromNotification"; import BackButtonFromNotification from "@/components/Button/BackButtonFromNotification";
import { TabsStyles } from "@/styles/tabs-styles"; import { TabsStyles } from "@/styles/tabs-styles";
import { router, Tabs, useLocalSearchParams, useNavigation } from "expo-router"; import { router, Tabs, useLocalSearchParams } from "expo-router";
import { useLayoutEffect } from "react"; import { View } from "react-native";
import { MainColor } from "@/constants/color-palet";
export default function EventTabsLayout() { import { useSafeAreaInsets } from "react-native-safe-area-context";
const navigation = useNavigation(); import { Platform } from "react-native";
import { OS_ANDROID_HEIGHT, OS_IOS_HEIGHT } from "@/constants/constans-value";
function EventTabsWrapper() {
const insets = useSafeAreaInsets();
const paddingBottom = Platform.OS === "android" ? insets.bottom : 0;
const { from, category } = useLocalSearchParams<{ const { from, category } = useLocalSearchParams<{
from?: string; from?: string;
category?: string; category?: string;
}>(); }>();
console.log("from", from);
console.log("category", category);
// Atur header secara dinamis
useLayoutEffect(() => {
navigation.setOptions({
headerLeft: () => (
<BackButtonFromNotification
from={from as string}
category={category as string}
/>
),
});
}, [from, router, navigation]);
return ( return (
<Tabs screenOptions={TabsStyles}> <View style={{ flex: 1, backgroundColor: MainColor.darkblue }}>
<Tabs.Screen <Tabs
name="index" screenOptions={{
options={{ ...TabsStyles,
title: "Beranda", tabBarStyle: Platform.select({
tabBarIcon: ({ color }) => <IconHome color={color} />, ios: {
borderTopWidth: 0,
paddingTop: 12,
height: OS_IOS_HEIGHT,
},
android: {
borderTopWidth: 0,
paddingTop: 5,
height: OS_ANDROID_HEIGHT + paddingBottom,
},
}),
header: () => (
<AppHeader
title="Event"
left={
<BackButtonFromNotification
from={from || ""}
category={category}
/>
}
/>
),
}} }}
/> >
<Tabs.Screen <Tabs.Screen
name="status" name="index"
options={{ options={{
title: "Status", title: "Beranda",
tabBarIcon: ({ color }) => <IconStatus color={color} />, tabBarIcon: ({ color }) => <IconHome color={color} />,
}} }}
/> />
<Tabs.Screen <Tabs.Screen
name="contribution" name="status"
options={{ options={{
title: "Kontribusi", title: "Status",
tabBarIcon: ({ color }) => <IconContribution color={color} />, tabBarIcon: ({ color }) => <IconStatus color={color} />,
}} }}
/> />
<Tabs.Screen <Tabs.Screen
name="history" name="contribution"
options={{ options={{
title: "Riwayat", title: "Kontribusi",
tabBarIcon: ({ color }) => <IconHistory color={color} />, tabBarIcon: ({ color }) => <IconContribution color={color} />,
}} }}
/> />
</Tabs> <Tabs.Screen
name="history"
options={{
title: "Riwayat",
tabBarIcon: ({ color }) => <IconHistory color={color} />,
}}
/>
</Tabs>
</View>
); );
} }
export default function EventTabsLayout() {
return <EventTabsWrapper />;
}

View File

@@ -5,11 +5,12 @@ import {
DrawerCustom, DrawerCustom,
Grid, Grid,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { IMenuDrawerItem } from "@/components/_Interface/types"; import { IMenuDrawerItem } from "@/components/_Interface/types";
import LeftButtonCustom from "@/components/Button/BackButton"; import LeftButtonCustom from "@/components/Button/BackButton";
import Event_ButtonStatusSection from "@/screens/Event/ButtonStatusSection"; import Event_ButtonStatusSection from "@/screens/Event/ButtonStatusSection";
@@ -81,15 +82,20 @@ export default function EventDetailStatus() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: `Detail ${status === "publish" ? "" : status}`, header: () => (
headerLeft: () => <LeftButtonCustom />, <AppHeader
headerRight: () => title={`Detail ${status === "publish" ? "" : status}`}
status === "draft" ? ( left={<LeftButtonCustom />}
<DotButton onPress={() => setOpenDrawer(true)} /> right={
) : null, status === "draft" ? (
<DotButton onPress={() => setOpenDrawer(true)} />
) : null
}
/>
),
}} }}
/> />
<ViewWrapper> <OS_Wrapper>
<BaseBox> <BaseBox>
<StackCustom> <StackCustom>
<TextCustom bold align="center" size="xlarge"> <TextCustom bold align="center" size="xlarge">
@@ -112,7 +118,7 @@ export default function EventDetailStatus() {
status={status as string} status={status as string}
/> />
<Spacing /> <Spacing />
</ViewWrapper> </OS_Wrapper>
<DrawerCustom <DrawerCustom
isVisible={openDrawer} isVisible={openDrawer}

View File

@@ -5,10 +5,11 @@ import {
ButtonCustom, ButtonCustom,
CenterCustom, CenterCustom,
LoaderCustom, LoaderCustom,
OS_Wrapper,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
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 {
@@ -265,18 +266,22 @@ export default function UserEventConfirmation() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: "Konfirmasi Event", header: () => (
headerLeft: () => ( <AppHeader
<Ionicons title="Konfirmasi Event"
name="arrow-back" left={
size={20} <Ionicons
color={MainColor.yellow} name="arrow-back"
onPress={() => router.navigate("/")} size={20}
color={MainColor.yellow}
onPress={() => router.navigate("/")}
/>
}
/> />
), ),
}} }}
/> />
<ViewWrapper>{handlerReturn()}</ViewWrapper> <OS_Wrapper>{handlerReturn()}</OS_Wrapper>
</> </>
); );
} }

View File

@@ -4,9 +4,10 @@ import {
DrawerCustom, DrawerCustom,
LoaderCustom, LoaderCustom,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
OS_Wrapper,
Spacing, Spacing,
ViewWrapper,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { IMenuDrawerItem } from "@/components/_Interface/types"; import { IMenuDrawerItem } from "@/components/_Interface/types";
import LeftButtonCustom from "@/components/Button/BackButton"; import LeftButtonCustom from "@/components/Button/BackButton";
import Event_BoxDetailPublishSection from "@/screens/Event/BoxDetailPublishSection"; import Event_BoxDetailPublishSection from "@/screens/Event/BoxDetailPublishSection";
@@ -49,19 +50,23 @@ export default function EventDetailContribution() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: `Detail kontribusi`, header: () => (
headerLeft: () => <LeftButtonCustom />, <AppHeader
headerRight: () => <DotButton onPress={() => setOpenDrawer(true)} />, title="Detail kontribusi"
left={<LeftButtonCustom />}
right={<DotButton onPress={() => setOpenDrawer(true)} />}
/>
),
}} }}
/> />
<ViewWrapper> <OS_Wrapper>
{isLoadData ? ( {isLoadData ? (
<LoaderCustom /> <LoaderCustom />
) : ( ) : (
<Event_BoxDetailPublishSection data={data} /> <Event_BoxDetailPublishSection data={data} />
)} )}
<Spacing /> <Spacing />
</ViewWrapper> </OS_Wrapper>
<DrawerCustom <DrawerCustom
isVisible={openDrawer} isVisible={openDrawer}
closeDrawer={() => setOpenDrawer(false)} closeDrawer={() => setOpenDrawer(false)}

View File

@@ -3,14 +3,13 @@ import {
BoxButtonOnFooter, BoxButtonOnFooter,
ButtonCustom, ButtonCustom,
LoaderCustom, LoaderCustom,
NewWrapper, OS_Wrapper,
SelectCustom, SelectCustom,
Spacing, Spacing,
StackCustom, StackCustom,
TextAreaCustom, TextAreaCustom,
TextCustom, TextCustom,
TextInputCustom, TextInputCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import ListSkeletonComponent from "@/components/_ShareComponent/ListSkeletonComponent"; import ListSkeletonComponent from "@/components/_ShareComponent/ListSkeletonComponent";
import DateTimePickerCustom from "@/components/DateInput/DateTimePickerCustom"; import DateTimePickerCustom from "@/components/DateInput/DateTimePickerCustom";
@@ -186,7 +185,9 @@ export default function EventEdit() {
return ( return (
<> <>
<NewWrapper <OS_Wrapper
enableKeyboardHandling
contentPaddingBottom={250}
footerComponent={ footerComponent={
<BoxButtonOnFooter> <BoxButtonOnFooter>
<ButtonCustom <ButtonCustom
@@ -283,7 +284,7 @@ export default function EventEdit() {
/> />
</StackCustom> </StackCustom>
)} )}
</NewWrapper> </OS_Wrapper>
</> </>
); );
} }

View File

@@ -3,9 +3,10 @@ import {
DotButton, DotButton,
DrawerCustom, DrawerCustom,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
ViewWrapper, OS_Wrapper,
Spacing, Spacing,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { IMenuDrawerItem } from "@/components/_Interface/types"; import { IMenuDrawerItem } from "@/components/_Interface/types";
import LeftButtonCustom from "@/components/Button/BackButton"; import LeftButtonCustom from "@/components/Button/BackButton";
import Event_BoxDetailPublishSection from "@/screens/Event/BoxDetailPublishSection"; import Event_BoxDetailPublishSection from "@/screens/Event/BoxDetailPublishSection";
@@ -44,15 +45,19 @@ export default function EventDetailHistory() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: `Detail riwayat`, header: () => (
headerLeft: () => <LeftButtonCustom />, <AppHeader
headerRight: () => <DotButton onPress={() => setOpenDrawer(true)} />, title="Detail riwayat"
left={<LeftButtonCustom />}
right={<DotButton onPress={() => setOpenDrawer(true)} />}
/>
),
}} }}
/> />
<ViewWrapper> <OS_Wrapper>
<Event_BoxDetailPublishSection data={data} /> <Event_BoxDetailPublishSection data={data} />
<Spacing /> <Spacing />
</ViewWrapper> </OS_Wrapper>
<DrawerCustom <DrawerCustom
isVisible={openDrawer} isVisible={openDrawer}
closeDrawer={() => setOpenDrawer(false)} closeDrawer={() => setOpenDrawer(false)}

View File

@@ -6,8 +6,9 @@ import {
DotButton, DotButton,
DrawerCustom, DrawerCustom,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
ViewWrapper, OS_Wrapper,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { IMenuDrawerItem } from "@/components/_Interface/types"; import { IMenuDrawerItem } from "@/components/_Interface/types";
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom"; import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
import LeftButtonCustom from "@/components/Button/BackButton"; import LeftButtonCustom from "@/components/Button/BackButton";
@@ -121,9 +122,9 @@ export default function EventDetailPublish() {
if (isEventFinished) { if (isEventFinished) {
return ( return (
<ViewWrapper> <OS_Wrapper>
<CustomSkeleton /> <CustomSkeleton />
</ViewWrapper> </OS_Wrapper>
); );
} }
@@ -156,12 +157,16 @@ export default function EventDetailPublish() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: `Event Publish`, header: () => (
headerLeft: () => <BackButton onPress={() => router.back()} />, <AppHeader
headerRight: () => <DotButton onPress={() => setOpenDrawer(true)} />, title="Event Publish"
left={<BackButton onPress={() => router.back()} />}
right={<DotButton onPress={() => setOpenDrawer(true)} />}
/>
),
}} }}
/> />
<ViewWrapper> <OS_Wrapper>
{isLoadingData ? ( {isLoadingData ? (
<CustomSkeleton height={400} /> <CustomSkeleton height={400} />
) : ( ) : (
@@ -170,7 +175,7 @@ export default function EventDetailPublish() {
footerButton={FooterButton()} footerButton={FooterButton()}
/> />
)} )}
</ViewWrapper> </OS_Wrapper>
<DrawerCustom <DrawerCustom
isVisible={openDrawer} isVisible={openDrawer}

View File

@@ -1,7 +1,7 @@
import { import {
BoxButtonOnFooter, BoxButtonOnFooter,
ButtonCustom, ButtonCustom,
NewWrapper, OS_Wrapper,
SelectCustom, SelectCustom,
Spacing, Spacing,
StackCustom, StackCustom,
@@ -112,7 +112,9 @@ export default function EventCreate() {
return ( return (
<> <>
<NewWrapper <OS_Wrapper
enableKeyboardHandling
contentPaddingBottom={250}
footerComponent={<BoxButtonOnFooter>{buttonSubmit}</BoxButtonOnFooter>} footerComponent={<BoxButtonOnFooter>{buttonSubmit}</BoxButtonOnFooter>}
> >
<StackCustom gap={"xs"}> <StackCustom gap={"xs"}>
@@ -182,7 +184,7 @@ export default function EventCreate() {
/> />
</StackCustom> </StackCustom>
</StackCustom> </StackCustom>
</NewWrapper> </OS_Wrapper>
</> </>
); );
} }

View File

@@ -1,4 +1,4 @@
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper"; import { OS_Wrapper } from "@/components";
import { GStyles } from "@/styles/global-styles"; import { GStyles } from "@/styles/global-styles";
import { useLocalSearchParams } from "expo-router"; import { useLocalSearchParams } from "expo-router";
import { Text } from "react-native"; import { Text } from "react-native";
@@ -7,8 +7,8 @@ export default function DetailEvent() {
const { id } = useLocalSearchParams(); const { id } = useLocalSearchParams();
console.log("id event >", id); console.log("id event >", id);
return ( return (
<ViewWrapper> <OS_Wrapper>
<Text style={GStyles.textLabel}>Detail Event {id}</Text> <Text style={GStyles.textLabel}>Detail Event {id}</Text>
</ViewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -2,8 +2,8 @@ import {
BoxButtonOnFooter, BoxButtonOnFooter,
ButtonCustom, ButtonCustom,
LoaderCustom, LoaderCustom,
OS_Wrapper,
TextAreaCustom, TextAreaCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import AlertWarning from "@/components/Alert/AlertWarning"; import AlertWarning from "@/components/Alert/AlertWarning";
import { apiForumGetOne, apiForumUpdate } from "@/service/api-client/api-forum"; import { apiForumGetOne, apiForumUpdate } from "@/service/api-client/api-forum";
@@ -88,7 +88,11 @@ export default function ForumEdit() {
}; };
return ( return (
<ViewWrapper footerComponent={buttonFooter()}> <OS_Wrapper
enableKeyboardHandling
contentPaddingBottom={250}
footerComponent={buttonFooter()}
>
{!loadingGetData ? ( {!loadingGetData ? (
<TextAreaCustom <TextAreaCustom
placeholder="Ketik diskusi anda..." placeholder="Ketik diskusi anda..."
@@ -102,6 +106,6 @@ export default function ForumEdit() {
) : ( ) : (
<LoaderCustom /> <LoaderCustom />
)} )}
</ViewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -1,8 +1,8 @@
import { import {
BoxButtonOnFooter, BoxButtonOnFooter,
ButtonCustom, ButtonCustom,
OS_Wrapper,
TextAreaCustom, TextAreaCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
@@ -62,13 +62,17 @@ export default function ForumOtherReportCommentar() {
return ( return (
<> <>
<ViewWrapper footerComponent={handleSubmit}> <OS_Wrapper
enableKeyboardHandling
contentPaddingBottom={250}
footerComponent={handleSubmit}
>
<TextAreaCustom <TextAreaCustom
placeholder="Laporkan Komentar" placeholder="Laporkan Komentar"
value={value} value={value}
onChangeText={setValue} onChangeText={setValue}
/> />
</ViewWrapper> </OS_Wrapper>
</> </>
); );
} }

View File

@@ -1,8 +1,8 @@
import { import {
BoxButtonOnFooter, BoxButtonOnFooter,
ButtonCustom, ButtonCustom,
OS_Wrapper,
TextAreaCustom, TextAreaCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
@@ -61,13 +61,17 @@ export default function ForumOtherReportPosting() {
); );
return ( return (
<> <>
<ViewWrapper footerComponent={handleSubmit}> <OS_Wrapper
enableKeyboardHandling
contentPaddingBottom={250}
footerComponent={handleSubmit}
>
<TextAreaCustom <TextAreaCustom
placeholder="Laporkan Diskusi" placeholder="Laporkan Diskusi"
value={value} value={value}
onChangeText={setValue} onChangeText={setValue}
/> />
</ViewWrapper> </OS_Wrapper>
</> </>
); );
} }

View File

@@ -1,6 +1,6 @@
import { import {
BaseBox, BaseBox,
NewWrapper, OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
@@ -41,7 +41,7 @@ export default function ForumPreviewReportComment() {
return ( return (
<> <>
<NewWrapper> <OS_Wrapper>
<StackCustom> <StackCustom>
<TextCustom color="red" bold> <TextCustom color="red" bold>
Komentar anda telah melanggar aturan forum ! Admin mengambil Komentar anda telah melanggar aturan forum ! Admin mengambil
@@ -85,7 +85,7 @@ export default function ForumPreviewReportComment() {
</BaseBox> </BaseBox>
)) ))
)} )}
</NewWrapper> </OS_Wrapper>
</> </>
); );
} }

View File

@@ -1,6 +1,6 @@
import { import {
BaseBox, BaseBox,
NewWrapper, OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
@@ -41,7 +41,7 @@ export default function ForumPreviewReportPosting() {
return ( return (
<> <>
<NewWrapper> <OS_Wrapper>
<StackCustom> <StackCustom>
<TextCustom color="red" bold> <TextCustom color="red" bold>
Postingan anda telah melanggar aturan forum ! Admin mengambil Postingan anda telah melanggar aturan forum ! Admin mengambil
@@ -85,7 +85,7 @@ export default function ForumPreviewReportPosting() {
</BaseBox> </BaseBox>
)) ))
)} )}
</NewWrapper> </OS_Wrapper>
</> </>
); );
} }

View File

@@ -1,9 +1,9 @@
import { import {
ButtonCustom, ButtonCustom,
LoaderCustom, LoaderCustom,
OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import { AccentColor, MainColor } from "@/constants/color-palet"; import { AccentColor, MainColor } from "@/constants/color-palet";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
@@ -69,7 +69,7 @@ export default function ForumReportCommentar() {
return ( return (
<> <>
<ViewWrapper> <OS_Wrapper>
{isLoadingList ? ( {isLoadingList ? (
<LoaderCustom /> <LoaderCustom />
) : ( ) : (
@@ -101,7 +101,7 @@ export default function ForumReportCommentar() {
<Spacing /> <Spacing />
</StackCustom> </StackCustom>
)} )}
</ViewWrapper> </OS_Wrapper>
</> </>
); );
} }

View File

@@ -2,9 +2,9 @@ import {
AlertDefaultSystem, AlertDefaultSystem,
ButtonCustom, ButtonCustom,
LoaderCustom, LoaderCustom,
OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import { AccentColor, MainColor } from "@/constants/color-palet"; import { AccentColor, MainColor } from "@/constants/color-palet";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
@@ -73,7 +73,7 @@ export default function ForumReportPosting() {
return ( return (
<> <>
<ViewWrapper> <OS_Wrapper>
{isLoadingList ? ( {isLoadingList ? (
<LoaderCustom /> <LoaderCustom />
) : ( ) : (
@@ -114,7 +114,7 @@ export default function ForumReportPosting() {
<Spacing /> <Spacing />
</StackCustom> </StackCustom>
)} )}
</ViewWrapper> </OS_Wrapper>
</> </>
); );
} }

View File

@@ -1,8 +1,8 @@
import { import {
BoxButtonOnFooter, BoxButtonOnFooter,
ButtonCustom, ButtonCustom,
OS_Wrapper,
TextAreaCustom, TextAreaCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import AlertWarning from "@/components/Alert/AlertWarning"; import AlertWarning from "@/components/Alert/AlertWarning";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
@@ -67,7 +67,11 @@ export default function ForumCreate() {
); );
return ( return (
<ViewWrapper footerComponent={buttonFooter}> <OS_Wrapper
enableKeyboardHandling
contentPaddingBottom={250}
footerComponent={buttonFooter}
>
<TextAreaCustom <TextAreaCustom
placeholder="Ketik diskusi anda..." placeholder="Ketik diskusi anda..."
maxLength={1000} maxLength={1000}
@@ -75,6 +79,6 @@ export default function ForumCreate() {
value={text} value={text}
onChangeText={setText} onChangeText={setText}
/> />
</ViewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -2,7 +2,7 @@ import {
BaseBox, BaseBox,
ButtonCustom, ButtonCustom,
CheckboxCustom, CheckboxCustom,
NewWrapper, OS_Wrapper,
StackCustom, StackCustom,
TextCustom, TextCustom,
} from "@/components"; } from "@/components";
@@ -54,7 +54,7 @@ export default function ForumSplash() {
}; };
return ( return (
<NewWrapper> <OS_Wrapper>
{/* <TextCustom bold>HIPMI Badung Connect</TextCustom> . */} {/* <TextCustom bold>HIPMI Badung Connect</TextCustom> . */}
<BaseBox> <BaseBox>
@@ -162,7 +162,7 @@ export default function ForumSplash() {
</ButtonCustom> </ButtonCustom>
</StackCustom> </StackCustom>
</BaseBox> </BaseBox>
</NewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { BasicWrapper, StackCustom, ViewWrapper } from "@/components"; import { BasicWrapper, Spacing, StackCustom, ViewWrapper } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader"; import AppHeader from "@/components/_ShareComponent/AppHeader";
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom"; import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
@@ -8,19 +8,20 @@ import { useAuth } from "@/hooks/use-auth";
import { useNotificationStore } from "@/hooks/use-notification-store"; import { useNotificationStore } from "@/hooks/use-notification-store";
import Home_BottomFeatureSection from "@/screens/Home/bottomFeatureSection"; import Home_BottomFeatureSection from "@/screens/Home/bottomFeatureSection";
import HeaderBell from "@/screens/Home/HeaderBell"; import HeaderBell from "@/screens/Home/HeaderBell";
import HomeTabs from "@/screens/Home/HomeTabs";
import { stylesHome } from "@/screens/Home/homeViewStyle"; import { stylesHome } from "@/screens/Home/homeViewStyle";
import Home_ImageSection from "@/screens/Home/imageSection"; import Home_ImageSection from "@/screens/Home/imageSection";
import TabSection from "@/screens/Home/tabSection";
import { tabsHome } from "@/screens/Home/tabsList"; import { tabsHome } from "@/screens/Home/tabsList";
import Home_FeatureSection from "@/screens/Home/topFeatureSection"; import Home_FeatureSection from "@/screens/Home/topFeatureSection";
import { apiJobGetAll } from "@/service/api-client/api-job"; import { apiJobGetAll } from "@/service/api-client/api-job";
import { apiUser } from "@/service/api-client/api-user"; import { apiUser } from "@/service/api-client/api-user";
import { apiVersion } from "@/service/api-config"; import { apiVersion } from "@/service/api-config";
import { GStyles } from "@/styles/global-styles";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import { Redirect, router, Stack, useFocusEffect } from "expo-router"; import { Redirect, router, Stack, useFocusEffect } from "expo-router";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { RefreshControl, View } from "react-native"; import { RefreshControl, ScrollView, View } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { Platform } from "react-native";
export default function Application() { export default function Application() {
const { token, user, userData } = useAuth(); const { token, user, userData } = useAuth();
@@ -28,6 +29,8 @@ export default function Application() {
const [refreshing, setRefreshing] = useState(false); const [refreshing, setRefreshing] = useState(false);
const { syncUnreadCount } = useNotificationStore(); const { syncUnreadCount } = useNotificationStore();
const [listData, setListData] = useState<any[] | null>(null); const [listData, setListData] = useState<any[] | null>(null);
const insets = useSafeAreaInsets();
const paddingBottom = Platform.OS === "android" ? insets.bottom : 0;
useFocusEffect( useFocusEffect(
useCallback(() => { useCallback(() => {
@@ -105,15 +108,6 @@ export default function Application() {
); );
} }
// if (data && data?.masterUserRoleId !== "1") {
// console.log("User is not admin");
// return (
// <BasicWrapper>
// <Redirect href={`/admin/dashboard`} />
// </BasicWrapper>
// );
// }
return ( return (
<> <>
<Stack.Screen <Stack.Screen
@@ -148,63 +142,61 @@ export default function Application() {
}} }}
/> />
<ViewWrapper <View style={{ flex: 1, backgroundColor: MainColor.darkblue }}>
refreshControl={ <ScrollView
<RefreshControl style={{ flex: 1 }}
refreshing={refreshing} contentContainerStyle={{
onRefresh={onRefresh} flexGrow: 1,
tintColor={MainColor.yellow} paddingInline: 10,
colors={[MainColor.yellow]} paddingBottom: paddingBottom + 80, // Space for tabs + safe area
/> }}
} refreshControl={
footerComponent={ <RefreshControl
data && data ? ( refreshing={refreshing}
<TabSection onRefresh={onRefresh}
tabs={tabsHome({ tintColor={MainColor.yellow}
acceptedForumTermsAt: data?.acceptedForumTermsAt, colors={[MainColor.yellow]}
profileId: data?.Profile?.id,
})}
/> />
) : ( }
<View style={GStyles.tabBar}> keyboardShouldPersistTaps="handled"
<View style={[GStyles.tabContainer, { paddingTop: 10 }]}> >
{Array.from({ length: 4 }).map((e, index) => ( <StackCustom>
<Home_ImageSection />
{data && data ? (
<Home_FeatureSection />
) : (
<View style={stylesHome.gridContainer}>
{Array.from({ length: 4 }).map((_, index) => (
<CustomSkeleton <CustomSkeleton
key={index} key={index}
height={40} style={stylesHome.gridItem}
width={40} radius={50}
radius={100}
/> />
))} ))}
</View> </View>
</View> )}
)
}
>
<StackCustom>
<Home_ImageSection />
{data && data ? ( {data ? (
<Home_FeatureSection /> <Home_BottomFeatureSection listData={listData} />
) : ( ) : (
<View style={stylesHome.gridContainer}> <CustomSkeleton height={150} />
{Array.from({ length: 4 }).map((item, index) => ( )}
<CustomSkeleton </StackCustom>
key={index} </ScrollView>
style={stylesHome.gridItem}
radius={50}
/>
))}
</View>
)}
{data ? ( {/* Home Tabs di bawah */}
<Home_BottomFeatureSection listData={listData} /> {data && data ? (
) : ( <HomeTabs
<CustomSkeleton height={200} /> tabs={tabsHome({
)} acceptedForumTermsAt: data?.acceptedForumTermsAt,
</StackCustom> profileId: data?.Profile?.id,
</ViewWrapper> })}
/>
) : (
<View style={{ height: 80 + paddingBottom, backgroundColor: MainColor.darkblue }} />
)}
</View>
</> </>
); );
} }

View File

@@ -1,83 +1,108 @@
import BackButtonFromNotification from "@/components/Button/BackButtonFromNotification"; import BackButtonFromNotification from "@/components/Button/BackButtonFromNotification";
import { ICON_SIZE_SMALL } from "@/constants/constans-value"; import { ICON_SIZE_SMALL, OS_ANDROID_HEIGHT, OS_IOS_HEIGHT } from "@/constants/constans-value";
import { TabsStyles } from "@/styles/tabs-styles"; import { TabsStyles } from "@/styles/tabs-styles";
import { Feather, FontAwesome6, Ionicons } from "@expo/vector-icons"; import { Feather, FontAwesome6, Ionicons } from "@expo/vector-icons";
import { router, Tabs, useLocalSearchParams, useNavigation } from "expo-router"; import { router, Tabs, useLocalSearchParams, useNavigation } from "expo-router";
import { useLayoutEffect } from "react"; import { useLayoutEffect } from "react";
import { View } from "react-native";
import { MainColor } from "@/constants/color-palet";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { Platform } from "react-native";
export default function InvestmentTabsLayout() { function InvestmentTabsWrapper() {
// const navigation = useNavigation(); const insets = useSafeAreaInsets();
const paddingBottom = Platform.OS === "android" ? insets.bottom : 0;
const navigation = useNavigation();
// const { from, category } = useLocalSearchParams<{ const { from, category } = useLocalSearchParams<{
// from?: string; from?: string;
// category?: string; category?: string;
// }>(); }>();
// console.log("from", from); // Atur header secara dinamis
// console.log("category", category); useLayoutEffect(() => {
navigation.setOptions({
// // Atur header secara dinamis headerLeft: () => (
// useLayoutEffect(() => { <BackButtonFromNotification
// navigation.setOptions({ from={from || ""}
// headerLeft: () => ( category={category}
// <BackButtonFromNotification />
// from={from as string} ),
// category={category as string} });
// /> }, [from, category, router, navigation]);
// ),
// });
// }, [from, router, navigation]);
return ( return (
<Tabs screenOptions={TabsStyles}> <View style={{ flex: 1, backgroundColor: MainColor.darkblue }}>
<Tabs.Screen <Tabs
name="index" screenOptions={{
options={{ ...TabsStyles,
title: "Bursa", tabBarStyle: Platform.select({
tabBarIcon: ({ color }) => ( ios: {
<Ionicons borderTopWidth: 0,
name="bar-chart-outline" paddingTop: 12,
color={color} height: OS_IOS_HEIGHT,
size={ICON_SIZE_SMALL} },
/> android: {
), borderTopWidth: 0,
paddingTop: 5,
height: OS_ANDROID_HEIGHT + paddingBottom,
},
}),
}} }}
/> >
<Tabs.Screen <Tabs.Screen
name="portofolio" name="index"
options={{ options={{
title: "Portofolio", title: "Bursa",
tabBarIcon: ({ color }) => ( tabBarIcon: ({ color }) => (
<Feather name="pie-chart" color={color} size={ICON_SIZE_SMALL} /> <Ionicons
), name="bar-chart-outline"
}} color={color}
/> size={ICON_SIZE_SMALL}
<Tabs.Screen />
name="my-holding" ),
options={{ }}
title: "Saham Saya", />
tabBarIcon: ({ color }) => ( <Tabs.Screen
<FontAwesome6 name="portofolio"
name="hand-holding-dollar" options={{
color={color} title: "Portofolio",
size={ICON_SIZE_SMALL} tabBarIcon: ({ color }) => (
/> <Feather name="pie-chart" color={color} size={ICON_SIZE_SMALL} />
), ),
}} }}
/> />
<Tabs.Screen <Tabs.Screen
name="transaction" name="my-holding"
options={{ options={{
title: "Transaksi", title: "Saham Saya",
tabBarIcon: ({ color }) => ( tabBarIcon: ({ color }) => (
<FontAwesome6 <FontAwesome6
name="money-bill-transfer" name="hand-holding-dollar"
color={color} color={color}
size={ICON_SIZE_SMALL} size={ICON_SIZE_SMALL}
/> />
), ),
}} }}
/> />
</Tabs> <Tabs.Screen
name="transaction"
options={{
title: "Transaksi",
tabBarIcon: ({ color }) => (
<FontAwesome6
name="money-bill-transfer"
color={color}
size={ICON_SIZE_SMALL}
/>
),
}}
/>
</Tabs>
</View>
); );
} }
export default function InvestmentTabsLayout() {
return <InvestmentTabsWrapper />;
}

View File

@@ -5,11 +5,11 @@ import {
ButtonCustom, ButtonCustom,
CenterCustom, CenterCustom,
InformationBox, InformationBox,
OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
TextInputCustom, TextInputCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import DIRECTORY_ID from "@/constants/directory-id"; import DIRECTORY_ID from "@/constants/directory-id";
@@ -83,9 +83,12 @@ export default function InvestmentAddDocument() {
); );
return ( return (
<> <OS_Wrapper
<ViewWrapper footerComponent={buttonFooter}> enableKeyboardHandling
<StackCustom gap={"xs"}> contentPaddingBottom={250}
footerComponent={buttonFooter}
>
<StackCustom gap={"xs"}>
<InformationBox text="File dokumen bersifat opsional, jika memang ada file yang bisa membantu meyakinkan investor. Anda bisa mengupload nya." /> <InformationBox text="File dokumen bersifat opsional, jika memang ada file yang bisa membantu meyakinkan investor. Anda bisa mengupload nya." />
<Spacing /> <Spacing />
<TextInputCustom <TextInputCustom
@@ -124,7 +127,6 @@ export default function InvestmentAddDocument() {
Upload Upload
</ButtonCenteredOnly> </ButtonCenteredOnly>
</StackCustom> </StackCustom>
</ViewWrapper> </OS_Wrapper>
</>
); );
} }

View File

@@ -6,11 +6,11 @@ import {
ButtonCustom, ButtonCustom,
CenterCustom, CenterCustom,
InformationBox, InformationBox,
OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
TextInputCustom, TextInputCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import DIRECTORY_ID from "@/constants/directory-id"; import DIRECTORY_ID from "@/constants/directory-id";
import { import {
@@ -105,9 +105,12 @@ export default function InvestmentEditDocument() {
); );
return ( return (
<> <OS_Wrapper
<ViewWrapper footerComponent={buttonFooter}> enableKeyboardHandling
<StackCustom gap={"xs"}> contentPaddingBottom={250}
footerComponent={buttonFooter}
>
<StackCustom gap={"xs"}>
<InformationBox text="File dokumen bersifat opsional, jika memang ada file yang bisa membantu meyakinkan investor. Anda bisa mengupload nya." /> <InformationBox text="File dokumen bersifat opsional, jika memang ada file yang bisa membantu meyakinkan investor. Anda bisa mengupload nya." />
<Spacing /> <Spacing />
<TextInputCustom <TextInputCustom
@@ -142,7 +145,6 @@ export default function InvestmentEditDocument() {
Upload Upload
</ButtonCenteredOnly> </ButtonCenteredOnly>
</StackCustom> </StackCustom>
</ViewWrapper> </OS_Wrapper>
</>
); );
} }

View File

@@ -6,10 +6,11 @@ import {
DrawerCustom, DrawerCustom,
Grid, Grid,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
OS_Wrapper,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { IconDocument, IconEdit, IconNews } from "@/components/_Icon"; import { IconDocument, IconEdit, IconNews } from "@/components/_Icon";
import { IMenuDrawerItem } from "@/components/_Interface/types"; import { IMenuDrawerItem } from "@/components/_Interface/types";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
@@ -30,13 +31,13 @@ export default function InvestmentDetailHolding() {
const [openDrawerDraft, setOpenDrawerDraft] = useState(false); const [openDrawerDraft, setOpenDrawerDraft] = useState(false);
const [openDrawerPublish, setOpenDrawerPublish] = useState(false); const [openDrawerPublish, setOpenDrawerPublish] = useState(false);
const [data, setData] = useState<any>(null); const [data, setData] = useState<any>(null);
useFocusEffect( useFocusEffect(
useCallback(() => { useCallback(() => {
onLoadData(); onLoadData();
}, [id, status]) }, [id, status])
); );
const onLoadData = async () => { const onLoadData = async () => {
try { try {
const response = await apiInvestmentGetInvoice({ const response = await apiInvestmentGetInvoice({
@@ -44,7 +45,7 @@ export default function InvestmentDetailHolding() {
authorId: user?.id, authorId: user?.id,
category: "invoice", category: "invoice",
}); });
console.log("[DATA]", JSON.stringify(response.data, null, 2)); console.log("[DATA]", JSON.stringify(response.data, null, 2));
setData(response.data); setData(response.data);
} catch (error) { } catch (error) {
@@ -76,18 +77,23 @@ export default function InvestmentDetailHolding() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: `Detail ${_.startCase(status as string)}`, header: () => (
headerLeft: () => <BackButton />, <AppHeader
headerRight: () => title={`Detail ${_.startCase(status as string)}`}
status === "draft" ? ( left={<BackButton />}
<DotButton onPress={() => setOpenDrawerDraft(true)} /> right={
) : status === "publish" ? ( status === "draft" ? (
<DotButton onPress={() => setOpenDrawerPublish(true)} /> <DotButton onPress={() => setOpenDrawerDraft(true)} />
) : null, ) : status === "publish" ? (
<DotButton onPress={() => setOpenDrawerPublish(true)} />
) : null
}
/>
),
}} }}
/> />
<ViewWrapper> <OS_Wrapper>
<BaseBox> <BaseBox>
<StackCustom gap={"xs"}> <StackCustom gap={"xs"}>
<Grid> <Grid>
@@ -118,7 +124,7 @@ export default function InvestmentDetailHolding() {
status={"publish"} status={"publish"}
bottomSection={bottomSection} bottomSection={bottomSection}
/> />
</ViewWrapper> </OS_Wrapper>
{/* ========= Draft Drawer ========= */} {/* ========= Draft Drawer ========= */}
<DrawerCustom <DrawerCustom

View File

@@ -7,10 +7,11 @@ import {
DrawerCustom, DrawerCustom,
DummyLandscapeImage, DummyLandscapeImage,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
OS_Wrapper,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { IconTrash } from "@/components/_Icon/IconTrash"; import { IconTrash } from "@/components/_Icon/IconTrash";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
import { import {
@@ -56,15 +57,20 @@ export default function InvestmentNews() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: "Detail Berita", header: () => (
headerLeft: () => <BackButton />, <AppHeader
headerRight: () => title="Detail Berita"
user?.id === data?.authorId && ( left={<BackButton />}
<DotButton onPress={() => setOpenDrawer(true)} /> right={
), user?.id === data?.authorId && (
<DotButton onPress={() => setOpenDrawer(true)} />
)
}
/>
),
}} }}
/> />
<ViewWrapper> <OS_Wrapper>
<BaseBox> <BaseBox>
<StackCustom> <StackCustom>
{data && data?.imageId && ( {data && data?.imageId && (
@@ -76,7 +82,7 @@ export default function InvestmentNews() {
<TextCustom>{(data && data?.deskripsi) || "-"}</TextCustom> <TextCustom>{(data && data?.deskripsi) || "-"}</TextCustom>
</StackCustom> </StackCustom>
</BaseBox> </BaseBox>
</ViewWrapper> </OS_Wrapper>
<DrawerCustom <DrawerCustom
isVisible={openDrawer} isVisible={openDrawer}

View File

@@ -3,11 +3,11 @@ import {
ButtonCustom, ButtonCustom,
InformationBox, InformationBox,
LandscapeFrameUploaded, LandscapeFrameUploaded,
OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
TextAreaCustom, TextAreaCustom,
TextInputCustom, TextInputCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import DIRECTORY_ID from "@/constants/directory-id"; import DIRECTORY_ID from "@/constants/directory-id";
import { apiInvestmentCreateNews } from "@/service/api-client/api-investment"; import { apiInvestmentCreateNews } from "@/service/api-client/api-investment";
@@ -80,7 +80,10 @@ export default function InvestmentAddNews() {
}; };
return ( return (
<ViewWrapper> <OS_Wrapper
enableKeyboardHandling
contentPaddingBottom={250}
>
<StackCustom gap={"xs"}> <StackCustom gap={"xs"}>
<InformationBox text="Pengunggahan foto ke aplikasi bersifat opsional dan tidak diwajibkan, Anda dapat menyimpan berita tanpa mengunggah foto." /> <InformationBox text="Pengunggahan foto ke aplikasi bersifat opsional dan tidak diwajibkan, Anda dapat menyimpan berita tanpa mengunggah foto." />
<LandscapeFrameUploaded image={image?.uri} /> <LandscapeFrameUploaded image={image?.uri} />
@@ -123,7 +126,6 @@ export default function InvestmentAddNews() {
Simpan Simpan
</ButtonCustom> </ButtonCustom>
</StackCustom> </StackCustom>
<Spacing /> </OS_Wrapper>
</ViewWrapper>
); );
} }

View File

@@ -2,10 +2,10 @@
import { import {
BaseBox, BaseBox,
Grid, Grid,
OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { apiInvestmentGetInvoice } from "@/service/api-client/api-investment"; import { apiInvestmentGetInvoice } from "@/service/api-client/api-investment";
@@ -69,7 +69,7 @@ export default function InvestmentFailed() {
]; ];
return ( return (
<ViewWrapper> <OS_Wrapper>
<StackCustom> <StackCustom>
<BaseBox> <BaseBox>
<StackCustom> <StackCustom>
@@ -110,6 +110,6 @@ export default function InvestmentFailed() {
</StackCustom> </StackCustom>
</BaseBox> </BaseBox>
</StackCustom> </StackCustom>
</ViewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -5,10 +5,10 @@ import {
ButtonCustom, ButtonCustom,
Divider, Divider,
Grid, Grid,
OS_Wrapper,
StackCustom, StackCustom,
TextCustom, TextCustom,
TextInputCustom, TextInputCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import { LOCAL_STORAGE_KEY } from "@/constants/local-storage-key"; import { LOCAL_STORAGE_KEY } from "@/constants/local-storage-key";
import { apiInvestmentGetOne } from "@/service/api-client/api-investment"; import { apiInvestmentGetOne } from "@/service/api-client/api-investment";
@@ -99,9 +99,12 @@ export default function InvestmentInvest() {
}; };
return ( return (
<> <OS_Wrapper
<ViewWrapper footerComponent={buttonSubmit()}> enableKeyboardHandling
<BaseBox> contentPaddingBottom={250}
footerComponent={buttonSubmit()}
>
<BaseBox>
<StackCustom gap={"xs"}> <StackCustom gap={"xs"}>
<Grid> <Grid>
<Grid.Col span={6}> <Grid.Col span={6}>
@@ -165,7 +168,6 @@ export default function InvestmentInvest() {
</Grid> </Grid>
</StackCustom> </StackCustom>
</BaseBox> </BaseBox>
</ViewWrapper> </OS_Wrapper>
</>
); );
} }

View File

@@ -1,11 +1,11 @@
import { BaseBox, StackCustom, TextCustom, ViewWrapper } from "@/components"; import { BaseBox, OS_Wrapper, StackCustom, TextCustom } from "@/components";
import MoneyTransferAnimation from "@/components/_ShareComponent/MoneyTransferAnimation"; import MoneyTransferAnimation from "@/components/_ShareComponent/MoneyTransferAnimation";
import { View } from "react-native"; import { View } from "react-native";
export default function InvestmentProcess() { export default function InvestmentProcess() {
return ( return (
<> <>
<ViewWrapper> <OS_Wrapper>
<BaseBox> <BaseBox>
<StackCustom> <StackCustom>
<TextCustom align="center" bold> <TextCustom align="center" bold>
@@ -35,7 +35,7 @@ export default function InvestmentProcess() {
</Grid.Col> </Grid.Col>
</Grid> </Grid>
</BaseBox> */} </BaseBox> */}
</ViewWrapper> </OS_Wrapper>
</> </>
); );
} }

View File

@@ -2,7 +2,7 @@ import {
BaseBox, BaseBox,
BoxButtonOnFooter, BoxButtonOnFooter,
ButtonCustom, ButtonCustom,
ViewWrapper, OS_Wrapper,
} from "@/components"; } from "@/components";
import { RadioCustom, RadioGroup } from "@/components/Radio/RadioCustom"; import { RadioCustom, RadioGroup } from "@/components/Radio/RadioCustom";
import { LOCAL_STORAGE_KEY } from "@/constants/local-storage-key"; import { LOCAL_STORAGE_KEY } from "@/constants/local-storage-key";
@@ -86,7 +86,7 @@ export default function InvestmentSelectBank() {
}; };
return ( return (
<ViewWrapper footerComponent={buttonSubmit()}> <OS_Wrapper footerComponent={buttonSubmit()}>
<RadioGroup value={select} onChange={setSelect}> <RadioGroup value={select} onChange={setSelect}>
{_.isEmpty(listBank) {_.isEmpty(listBank)
? [] ? []
@@ -96,6 +96,6 @@ export default function InvestmentSelectBank() {
</BaseBox> </BaseBox>
))} ))}
</RadioGroup> </RadioGroup>
</ViewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -2,10 +2,10 @@
import { import {
BaseBox, BaseBox,
Grid, Grid,
OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { apiInvestmentGetInvoice } from "@/service/api-client/api-investment"; import { apiInvestmentGetInvoice } from "@/service/api-client/api-investment";
@@ -69,7 +69,7 @@ export default function InvestmentSuccess() {
]; ];
return ( return (
<ViewWrapper> <OS_Wrapper>
<StackCustom> <StackCustom>
<BaseBox> <BaseBox>
<StackCustom> <StackCustom>
@@ -110,6 +110,6 @@ export default function InvestmentSuccess() {
</StackCustom> </StackCustom>
</BaseBox> </BaseBox>
</StackCustom> </StackCustom>
</ViewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -4,8 +4,9 @@ import {
DotButton, DotButton,
DrawerCustom, DrawerCustom,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
ViewWrapper, OS_Wrapper,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { IconDocument, IconEdit, IconNews } from "@/components/_Icon"; import { IconDocument, IconEdit, IconNews } from "@/components/_Icon";
import { IMenuDrawerItem } from "@/components/_Interface/types"; import { IMenuDrawerItem } from "@/components/_Interface/types";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
@@ -106,25 +107,30 @@ export default function InvestmentDetailStatus() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: `Detail ${_.startCase(status as string)}`, header: () => (
headerLeft: () => <BackButton />, <AppHeader
headerRight: () => title={`Detail ${_.startCase(status as string)}`}
status === "draft" ? ( left={<BackButton />}
<DotButton onPress={() => setOpenDrawerDraft(true)} /> right={
) : status === "publish" ? ( status === "draft" ? (
<DotButton onPress={() => setOpenDrawerPublish(true)} /> <DotButton onPress={() => setOpenDrawerDraft(true)} />
) : null, ) : status === "publish" ? (
<DotButton onPress={() => setOpenDrawerPublish(true)} />
) : null
}
/>
),
}} }}
/> />
<ViewWrapper> <OS_Wrapper>
<Invesment_DetailDataPublishSection <Invesment_DetailDataPublishSection
status={status as string} status={status as string}
data={data} data={data}
bottomSection={bottomSection} bottomSection={bottomSection}
buttonSection={buttonSection} buttonSection={buttonSection}
/> />
</ViewWrapper> </OS_Wrapper>
{/* ========= Draft Drawer ========= */} {/* ========= Draft Drawer ========= */}
<DrawerCustom <DrawerCustom

View File

@@ -7,10 +7,10 @@ import {
CenterCustom, CenterCustom,
InformationBox, InformationBox,
LoaderCustom, LoaderCustom,
OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import DIRECTORY_ID from "@/constants/directory-id"; import DIRECTORY_ID from "@/constants/directory-id";
import { import {
@@ -116,7 +116,7 @@ export default function InvestmentEditProspectus() {
</BoxButtonOnFooter> </BoxButtonOnFooter>
); );
return ( return (
<ViewWrapper footerComponent={!loadingGet && buttonFooter}> <OS_Wrapper footerComponent={!loadingGet && buttonFooter}>
<StackCustom gap={"xs"}> <StackCustom gap={"xs"}>
<InformationBox text="File prospektus wajib untuk diupload, agar calon investor paham dengan prospek investasi yang akan anda jalankan kedepan." /> <InformationBox text="File prospektus wajib untuk diupload, agar calon investor paham dengan prospek investasi yang akan anda jalankan kedepan." />
<Spacing /> <Spacing />
@@ -153,6 +153,6 @@ export default function InvestmentEditProspectus() {
Upload Upload
</ButtonCenteredOnly> </ButtonCenteredOnly>
</StackCustom> </StackCustom>
</ViewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -6,7 +6,7 @@ import {
InformationBox, InformationBox,
LandscapeFrameUploaded, LandscapeFrameUploaded,
LoaderCustom, LoaderCustom,
NewWrapper, OS_Wrapper,
SelectCustom, SelectCustom,
Spacing, Spacing,
StackCustom, StackCustom,
@@ -199,7 +199,9 @@ export default function InvestmentEdit() {
}; };
return ( return (
<NewWrapper <OS_Wrapper
enableKeyboardHandling
contentPaddingBottom={250}
footerComponent={ footerComponent={
<BoxButtonOnFooter> <BoxButtonOnFooter>
<ButtonCustom isLoading={isLoading} onPress={handleSubmitUpdate}> <ButtonCustom isLoading={isLoading} onPress={handleSubmitUpdate}>
@@ -350,6 +352,6 @@ export default function InvestmentEdit() {
<Spacing /> <Spacing />
</StackCustom> </StackCustom>
</NewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -4,8 +4,9 @@ import {
DotButton, DotButton,
DrawerCustom, DrawerCustom,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
ViewWrapper, OS_Wrapper,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { IconDocument, IconEdit, IconNews } from "@/components/_Icon"; import { IconDocument, IconEdit, IconNews } from "@/components/_Icon";
import { IMenuDrawerItem } from "@/components/_Interface/types"; import { IMenuDrawerItem } from "@/components/_Interface/types";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
@@ -105,25 +106,30 @@ export default function InvestmentDetail() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: `Detail ${_.startCase(status as string)}`, header: () => (
headerLeft: () => <BackButton />, <AppHeader
headerRight: () => title={`Detail ${_.startCase(status as string)}`}
status === "draft" ? ( left={<BackButton />}
<DotButton onPress={() => setOpenDrawerDraft(true)} /> right={
) : status === "publish" ? ( status === "draft" ? (
<DotButton onPress={() => setOpenDrawerPublish(true)} /> <DotButton onPress={() => setOpenDrawerDraft(true)} />
) : null, ) : status === "publish" ? (
<DotButton onPress={() => setOpenDrawerPublish(true)} />
) : null
}
/>
),
}} }}
/> />
<ViewWrapper> <OS_Wrapper>
<Invesment_DetailDataPublishSection <Invesment_DetailDataPublishSection
status={"publish"} status={"publish"}
data={data} data={data}
bottomSection={bottomSection} bottomSection={bottomSection}
buttonSection={buttonSection} buttonSection={buttonSection}
/> />
</ViewWrapper> </OS_Wrapper>
{/* ========= Draft Drawer ========= */} {/* ========= Draft Drawer ========= */}
<DrawerCustom <DrawerCustom

View File

@@ -6,7 +6,7 @@ import {
CenterCustom, CenterCustom,
InformationBox, InformationBox,
LandscapeFrameUploaded, LandscapeFrameUploaded,
NewWrapper, OS_Wrapper,
SelectCustom, SelectCustom,
Spacing, Spacing,
StackCustom, StackCustom,
@@ -118,20 +118,7 @@ export default function InvestmentCreate() {
try { try {
setIsLoading(true); setIsLoading(true);
const responseUploadImage = await uploadFileService({
imageUri: image,
dirId: DIRECTORY_ID.investasi_image,
});
if (!responseUploadImage.success) {
Toast.show({
type: "error",
text1: "Gagal mengunggah gambar",
});
return;
}
const imageId = responseUploadImage.data.id;
const responseUploadPdf = await uploadFileService({ const responseUploadPdf = await uploadFileService({
imageUri: pdf.uri, imageUri: pdf.uri,
dirId: DIRECTORY_ID.investasi_prospektus, dirId: DIRECTORY_ID.investasi_prospektus,
@@ -144,8 +131,22 @@ export default function InvestmentCreate() {
}); });
return; return;
} }
const pdfId = responseUploadPdf.data.id; const pdfId = responseUploadPdf.data.id;
const responseUploadImage = await uploadFileService({
imageUri: image,
dirId: DIRECTORY_ID.investasi_image,
});
if (!responseUploadImage.success) {
Toast.show({
type: "error",
text1: "Gagal mengunggah gambar",
});
return;
}
const imageId = responseUploadImage.data.id;
const newData = { const newData = {
title: data.title, title: data.title,
targetDana: data.targetDana, targetDana: data.targetDana,
@@ -185,7 +186,9 @@ export default function InvestmentCreate() {
// const [coba, setCoba] = useState(""); // const [coba, setCoba] = useState("");
return ( return (
<NewWrapper <OS_Wrapper
enableKeyboardHandling
contentPaddingBottom={250}
footerComponent={ footerComponent={
<BoxButtonOnFooter> <BoxButtonOnFooter>
<ButtonCustom <ButtonCustom
@@ -373,7 +376,6 @@ export default function InvestmentCreate() {
<Spacing /> <Spacing />
</StackCustom> </StackCustom>
{/* <Spacing height={50} /> */} </OS_Wrapper>
</NewWrapper>
); );
} }

View File

@@ -1,37 +1,60 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { BackButton } from "@/components"; import { BackButton } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { IconHome, IconStatus } from "@/components/_Icon"; import { IconHome, IconStatus } from "@/components/_Icon";
import BackButtonFromNotification from "@/components/Button/BackButtonFromNotification"; import BackButtonFromNotification from "@/components/Button/BackButtonFromNotification";
import { TabsStyles } from "@/styles/tabs-styles"; import { TabsStyles } from "@/styles/tabs-styles";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import { router, Tabs, useLocalSearchParams } from "expo-router";
import { View } from "react-native";
import { MainColor } from "@/constants/color-palet";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { Platform } from "react-native";
import { import {
router, OS_ANDROID_HEIGHT,
Tabs, OS_ANDROID_PADDING_TOP,
useLocalSearchParams, OS_IOS_HEIGHT,
useNavigation OS_IOS_PADDING_TOP,
} from "expo-router"; } from "@/constants/constans-value";
import { useLayoutEffect } from "react";
export default function JobTabsLayout() {
const navigation = useNavigation();
function JobTabsWrapper() {
const insets = useSafeAreaInsets();
const paddingBottom = Platform.OS === "android" ? insets.bottom : 0;
const { from, category } = useLocalSearchParams<{ const { from, category } = useLocalSearchParams<{
from?: string; from?: string;
category?: string; category?: string;
}>(); }>();
// Atur header secara dinamis
useLayoutEffect(() => {
navigation.setOptions({
headerLeft: () => (
<BackButtonFromNotification from={from as string} category={category as string} />
),
});
}, [from, router, navigation]);
return ( return (
<> <View style={{ flex: 1, backgroundColor: MainColor.darkblue }}>
<Tabs screenOptions={TabsStyles}> <Tabs
screenOptions={{
...TabsStyles,
tabBarStyle: Platform.select({
ios: {
borderTopWidth: 0,
paddingTop: OS_IOS_PADDING_TOP,
height: OS_IOS_HEIGHT,
},
android: {
borderTopWidth: 0,
paddingTop: OS_ANDROID_PADDING_TOP,
height: OS_ANDROID_HEIGHT + paddingBottom,
},
}),
header: () => (
<AppHeader
title="Job Vacancy"
left={
<BackButtonFromNotification
from={from || ""}
category={category}
/>
}
/>
),
}}
>
<Tabs.Screen <Tabs.Screen
name="index" name="index"
options={{ options={{
@@ -56,6 +79,10 @@ export default function JobTabsLayout() {
}} }}
/> />
</Tabs> </Tabs>
</> </View>
); );
} }
export default function JobTabsLayout() {
return <JobTabsWrapper />;
}

View File

@@ -5,10 +5,11 @@ import {
DrawerCustom, DrawerCustom,
LoaderCustom, LoaderCustom,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { IconEdit } from "@/components/_Icon"; import { IconEdit } from "@/components/_Icon";
import { IMenuDrawerItem } from "@/components/_Interface/types"; import { IMenuDrawerItem } from "@/components/_Interface/types";
import ReportBox from "@/components/Box/ReportBox"; import ReportBox from "@/components/Box/ReportBox";
@@ -22,6 +23,7 @@ import {
useLocalSearchParams, useLocalSearchParams,
} from "expo-router"; } from "expo-router";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { PADDING_INLINE } from "@/constants/constans-value";
export default function JobDetailStatus() { export default function JobDetailStatus() {
const { id, status } = useLocalSearchParams(); const { id, status } = useLocalSearchParams();
@@ -58,15 +60,20 @@ export default function JobDetailStatus() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: `Detail`, header: () => (
headerLeft: () => <BackButton />, <AppHeader
headerRight: () => title="Detail"
status === "draft" ? ( left={<BackButton />}
<DotButton onPress={() => setOpenDrawer(true)} /> right={
) : null, status === "draft" ? (
<DotButton onPress={() => setOpenDrawer(true)} />
) : null
}
/>
),
}} }}
/> />
<ViewWrapper> <OS_Wrapper >
{isLoadData ? ( {isLoadData ? (
<LoaderCustom /> <LoaderCustom />
) : ( ) : (
@@ -77,7 +84,7 @@ export default function JobDetailStatus() {
(status === "draft" || status === "reject") && ( (status === "draft" || status === "reject") && (
<ReportBox text={data?.catatan} /> <ReportBox text={data?.catatan} />
)} )}
<Job_BoxDetailSection data={data} /> <Job_BoxDetailSection data={data} />
<Job_ButtonStatusSection <Job_ButtonStatusSection
id={id as string} id={id as string}
@@ -90,7 +97,7 @@ export default function JobDetailStatus() {
<Spacing /> <Spacing />
</> </>
)} )}
</ViewWrapper> </OS_Wrapper>
<DrawerCustom <DrawerCustom
isVisible={openDrawer} isVisible={openDrawer}

View File

@@ -1,198 +1,5 @@
/* eslint-disable react-hooks/exhaustive-deps */ import { Job_ScreenEdit } from "@/screens/Job/ScreenJobEdit";
import {
BaseBox,
ButtonCenteredOnly,
ButtonCustom,
DummyLandscapeImage,
InformationBox,
LandscapeFrameUploaded,
LoaderCustom,
Spacing,
StackCustom,
TextAreaCustom,
TextInputCustom,
ViewWrapper,
} from "@/components";
import DIRECTORY_ID from "@/constants/directory-id";
import { apiJobGetOne, apiJobUpdateData } from "@/service/api-client/api-job";
import {
deleteFileService,
uploadFileService,
} from "@/service/upload-service";
import pickImage from "@/utils/pickImage";
import { router, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
import Toast from "react-native-toast-message";
export default function JobEdit() { export default function JobEdit() {
const { id } = useLocalSearchParams(); return <Job_ScreenEdit />;
const [data, setData] = useState<any>({
title: "",
content: "",
deskripsi: "",
});
const [isLoadData, setIsLoadData] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [imageUri, setImageUri] = useState<string | null>(null);
useEffect(() => {
onLoadData();
}, [id]);
const onLoadData = async () => {
try {
setIsLoadData(true);
const response = await apiJobGetOne({ id: id as string });
if (response.success) {
setData(response.data);
}
} catch (error) {
console.log("[ERROR]", error);
} finally {
setIsLoadData(false);
}
};
const handlerOnUpdate = async () => {
if (!data.title || !data.content || !data.deskripsi) {
Toast.show({
type: "info",
text1: "Info",
text2: "Harap isi semua data",
});
return;
}
try {
setIsLoading(true);
let newImageId = "";
if (imageUri) {
const responseUploadImage = await uploadFileService({
imageUri: imageUri,
dirId: DIRECTORY_ID.job_image,
});
if (responseUploadImage.success) {
newImageId = responseUploadImage.data.id;
}
}
if (data?.imageId) {
const responseDeleteImage = await deleteFileService({
id: data.imageId,
});
if (!responseDeleteImage.success) {
console.log("[ERROR DELETE IMAGE]", responseDeleteImage.message);
}
}
const newData = {
title: data.title,
content: data.content,
deskripsi: data.deskripsi,
imageId: newImageId,
};
const response = await apiJobUpdateData({
id: id as string,
data: newData,
category: "edit",
});
if (response.success) {
Toast.show({
type: "success",
text1: response.message,
});
router.back();
} else {
Toast.show({
type: "info",
text1: "Info",
text2: response.message,
});
}
} catch (error) {
console.log("[ERROR]", error);
} finally {
setIsLoading(false);
}
};
const buttonSubmit = () => {
return (
<>
<ButtonCustom isLoading={isLoading} onPress={() => handlerOnUpdate()}>
Update
</ButtonCustom>
<Spacing />
</>
);
};
return (
<ViewWrapper>
{isLoadData ? (
<LoaderCustom />
) : (
<StackCustom gap={"xs"}>
<InformationBox text="Poster atau gambar lowongan kerja bersifat opsional, tidak wajib untuk dimasukkan dan upload lah gambar yang sesuai dengan deskripsi lowongan kerja." />
{imageUri ? (
<LandscapeFrameUploaded image={imageUri as any} />
) : (
<BaseBox>
<DummyLandscapeImage imageId={data?.imageId} />
</BaseBox>
)}
<ButtonCenteredOnly
onPress={() => {
pickImage({
setImageUri,
});
}}
icon="upload"
>
Upload
</ButtonCenteredOnly>
<Spacing />
<TextInputCustom
label="Judul Lowongan"
placeholder="Masukan Judul Lowongan Kerja"
required
value={data.title}
onChangeText={(value) => setData({ ...data, title: value })}
/>
<TextAreaCustom
label="Syarat & Kualifikasi"
placeholder="Masukan Syarat & Kualifikasi Lowongan Kerja"
required
showCount
maxLength={1000}
value={data.content}
onChangeText={(value) => setData({ ...data, content: value })}
/>
<TextAreaCustom
label="Deskripsi Lowongan"
placeholder="Masukan Deskripsi Lowongan Kerja"
required
showCount
maxLength={1000}
value={data.deskripsi}
onChangeText={(value) => setData({ ...data, deskripsi: value })}
/>
{buttonSubmit()}
</StackCustom>
)}
</ViewWrapper>
);
} }

View File

@@ -1,168 +1,5 @@
import { import { Job_ScreenCreate } from "@/screens/Job/ScreenJobCreate";
BoxButtonOnFooter,
ButtonCenteredOnly,
ButtonCustom,
InformationBox,
LandscapeFrameUploaded,
NewWrapper,
Spacing,
StackCustom,
TextAreaCustom,
TextInputCustom
} from "@/components";
import DIRECTORY_ID from "@/constants/directory-id";
import { useAuth } from "@/hooks/use-auth";
import { apiJobCreate } from "@/service/api-client/api-job";
import { uploadFileService } from "@/service/upload-service";
import pickImage from "@/utils/pickImage";
import { router } from "expo-router";
import { useState } from "react";
import Toast from "react-native-toast-message";
export default function JobCreate() { export default function JobCreate() {
const nextUrl = "/(application)/(user)/job/(tabs)/status?status=review"; return <Job_ScreenCreate />;
const { user } = useAuth();
const [isLoading, setIsLoading] = useState(false);
const [image, setImage] = useState<string | null>(null);
const [data, setData] = useState({
title: "",
content: "",
deskripsi: "",
authorId: "",
});
const handlerOnSubmit = async () => {
let imageId = "";
const newData = {
title: data.title,
content: data.content,
deskripsi: data.deskripsi,
authorId: user?.id,
imageId: "",
};
if (!data.title || !data.content || !data.deskripsi || !user?.id) {
Toast.show({
type: "info",
text1: "Info",
text2: "Harap isi semua data",
});
return;
}
try {
setIsLoading(true);
if (image === null || !image) {
const response = await apiJobCreate(newData);
if (response.success) {
Toast.show({
type: "success",
text1: "Berhasil",
text2: "Lowongan berhasil dibuat",
});
router.replace(nextUrl);
}
return;
}
const responseUploadImage = await uploadFileService({
imageUri: image,
dirId: DIRECTORY_ID.job_image,
});
if (responseUploadImage.success) {
imageId = responseUploadImage.data.id;
}
const fixData = {
...newData,
imageId: imageId,
};
const response = await apiJobCreate(fixData);
if (response.success) {
Toast.show({
type: "success",
text1: "Berhasil",
text2: "Lowongan berhasil dibuat",
});
router.replace(nextUrl);
}
} catch (error) {
console.log("[ERROR]", error);
} finally {
setIsLoading(false);
}
};
const buttonSubmit = () => {
return (
<>
<BoxButtonOnFooter>
<ButtonCustom isLoading={isLoading} onPress={() => handlerOnSubmit()}>
Simpan
</ButtonCustom>
</BoxButtonOnFooter>
</>
);
};
return (
<NewWrapper footerComponent={buttonSubmit()}>
<StackCustom gap={"xs"}>
<InformationBox text="Poster atau gambar lowongan kerja bersifat opsional, tidak wajib untuk dimasukkan dan upload lah gambar yang sesuai dengan deskripsi lowongan kerja." />
{/* <BaseBox>
<Image
source={image ? { uri: image } : DUMMY_IMAGE.dummy_image}
style={{ width: "100%", height: 200 }}
/>
</BaseBox> */}
<LandscapeFrameUploaded image={image as string} />
<ButtonCenteredOnly
onPress={() => {
// router.push("/(application)/(image)/take-picture/123");
pickImage({
setImageUri: setImage,
});
}}
icon="upload"
>
Upload
</ButtonCenteredOnly>
<Spacing />
<TextInputCustom
label="Judul Lowongan"
placeholder="Masukan Judul Lowongan Kerja"
required
value={data.title}
onChangeText={(value) => setData({ ...data, title: value })}
/>
<TextAreaCustom
label="Syarat & Kualifikasi"
placeholder="Masukan Syarat & Kualifikasi Lowongan Kerja"
required
showCount
maxLength={1000}
value={data.content}
onChangeText={(value) => setData({ ...data, content: value })}
/>
<TextAreaCustom
label="Deskripsi Lowongan"
placeholder="Masukan Deskripsi Lowongan Kerja"
required
showCount
maxLength={1000}
value={data.deskripsi}
onChangeText={(value) => setData({ ...data, deskripsi: value })}
/>
</StackCustom>
</NewWrapper>
);
} }

View File

@@ -1,5 +1,5 @@
import { Admin_ScreenPortofolioCreate } from "@/screens/Portofolio/ScreenPortofolioCreate"; import { ScreenPortofolioCreate } from "@/screens/Portofolio/ScreenPortofolioCreate";
export default function PortofolioCreate() { export default function PortofolioCreate() {
return <Admin_ScreenPortofolioCreate />; return <ScreenPortofolioCreate />;
} }

View File

@@ -3,7 +3,7 @@ import {
BoxButtonOnFooter, BoxButtonOnFooter,
ButtonCenteredOnly, ButtonCenteredOnly,
ButtonCustom, ButtonCustom,
ViewWrapper OS_Wrapper
} from "@/components"; } from "@/components";
import API_STRORAGE from "@/constants/base-url-api-strorage"; import API_STRORAGE from "@/constants/base-url-api-strorage";
import DIRECTORY_ID from "@/constants/directory-id"; import DIRECTORY_ID from "@/constants/directory-id";
@@ -126,7 +126,7 @@ export default function PortofolioEditLogo() {
return ( return (
<> <>
<ViewWrapper footerComponent={buttonFooter}> <OS_Wrapper footerComponent={buttonFooter}>
<BaseBox <BaseBox
style={{ style={{
alignItems: "center", alignItems: "center",
@@ -146,7 +146,7 @@ export default function PortofolioEditLogo() {
> >
Upload Upload
</ButtonCenteredOnly> </ButtonCenteredOnly>
</ViewWrapper> </OS_Wrapper>
</> </>
); );
} }

View File

@@ -1,8 +1,8 @@
import { import {
BoxButtonOnFooter, BoxButtonOnFooter,
ButtonCustom, ButtonCustom,
OS_Wrapper,
TextInputCustom, TextInputCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import { import {
apiGetOnePortofolio, apiGetOnePortofolio,
@@ -91,7 +91,11 @@ export default function PortofolioEditSocialMedia() {
return ( return (
<> <>
<ViewWrapper footerComponent={buttonFooter}> <OS_Wrapper
enableKeyboardHandling
contentPaddingBottom={250}
footerComponent={buttonFooter}
>
<TextInputCustom <TextInputCustom
value={data.tiktok} value={data.tiktok}
onChangeText={(value) => setData({ ...data, tiktok: value })} onChangeText={(value) => setData({ ...data, tiktok: value })}
@@ -122,7 +126,7 @@ export default function PortofolioEditSocialMedia() {
label="Youtube" label="Youtube"
placeholder="Masukkan youtube" placeholder="Masukkan youtube"
/> />
</ViewWrapper> </OS_Wrapper>
</> </>
); );
} }

View File

@@ -4,7 +4,8 @@ import {
BoxButtonOnFooter, BoxButtonOnFooter,
ButtonCustom, ButtonCustom,
CenterCustom, CenterCustom,
NewWrapper, OS_Wrapper,
PhoneInputCustom,
SelectCustom, SelectCustom,
Spacing, Spacing,
StackCustom, StackCustom,
@@ -15,6 +16,11 @@ import {
import ListSkeletonComponent from "@/components/_ShareComponent/ListSkeletonComponent"; import ListSkeletonComponent from "@/components/_ShareComponent/ListSkeletonComponent";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_XLARGE } from "@/constants/constans-value"; import { ICON_SIZE_XLARGE } from "@/constants/constans-value";
import {
DEFAULT_COUNTRY,
type CountryData,
COUNTRIES,
} from "@/constants/countries";
import { import {
apiMasterBidangBisnis, apiMasterBidangBisnis,
apiMasterSubBidangBisnis, apiMasterSubBidangBisnis,
@@ -32,7 +38,6 @@ import { router, useLocalSearchParams } from "expo-router";
import _ from "lodash"; import _ from "lodash";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Text, View } from "react-native"; import { Text, View } from "react-native";
import PhoneInput, { ICountry } from "react-native-international-phone-number";
import { ActivityIndicator } from "react-native-paper"; import { ActivityIndicator } from "react-native-paper";
import Toast from "react-native-toast-message"; import Toast from "react-native-toast-message";
@@ -59,8 +64,9 @@ export default function PortofolioEdit() {
const { id } = useLocalSearchParams(); const { id } = useLocalSearchParams();
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [data, setData] = useState<any>({}); const [data, setData] = useState<any>({});
const [phoneNumber, setPhoneNumber] = useState<string>("");
const [selectedCountry, setSelectedCountry] = useState<null | ICountry>(null); const [selectedCountry, setSelectedCountry] =
useState<CountryData>(DEFAULT_COUNTRY);
const [bidangBisnis, setBidangBisnis] = useState< const [bidangBisnis, setBidangBisnis] = useState<
IMasterBidangBisnis[] | null IMasterBidangBisnis[] | null
>(null); >(null);
@@ -72,12 +78,42 @@ export default function PortofolioEdit() {
IListSubBidangSelected[] IListSubBidangSelected[]
>([]); >([]);
function handleInputValue(phoneNumber: string) { function handlePhoneChange(phone: string) {
setData({ ...data, tlpn: phoneNumber }); setPhoneNumber(phone);
// Format phone number for API
const callingCode = selectedCountry.callingCode;
let fixNumber = phone.replace(/\s+/g, "").replace(/^0+/, "");
// Remove country code if already present
if (fixNumber.startsWith(callingCode)) {
fixNumber = fixNumber.substring(callingCode.length);
}
// Remove leading zero
fixNumber = fixNumber.replace(/^0+/, "");
const realNumber = callingCode + fixNumber;
setData({ ...data, tlpn: realNumber });
} }
function handleSelectedCountry(country: ICountry) { function handleCountryChange(country: CountryData) {
setSelectedCountry(country); setSelectedCountry(country);
// Re-format with new country code
const callingCode = country.callingCode;
let fixNumber = phoneNumber.replace(/\s+/g, "").replace(/^0+/, "");
// Remove country code if already present
if (fixNumber.startsWith(callingCode)) {
fixNumber = fixNumber.substring(callingCode.length);
}
// Remove leading zero
fixNumber = fixNumber.replace(/^0+/, "");
const realNumber = callingCode + fixNumber;
setData({ ...data, tlpn: realNumber });
} }
const onLoadMasterBidang = async () => { const onLoadMasterBidang = async () => {
@@ -122,8 +158,27 @@ export default function PortofolioEdit() {
const response = await apiGetOnePortofolio({ id: id }); const response = await apiGetOnePortofolio({ id: id });
if (response.success) { if (response.success) {
const fixNumber = response.data.tlpn.replace("62", ""); // Extract phone number without country code for display
setData({ ...response.data, tlpn: fixNumber }); const fullNumber = response.data.tlpn;
let displayNumber = fullNumber;
let detectedCountry = DEFAULT_COUNTRY;
// Try to detect country from calling code
for (const country of COUNTRIES) {
if (fullNumber.startsWith(country.callingCode)) {
detectedCountry = country;
displayNumber = fullNumber.substring(country.callingCode.length);
break;
}
}
setSelectedCountry(detectedCountry);
// Remove leading zero if present
displayNumber = displayNumber.replace(/^0+/, "");
setPhoneNumber(displayNumber);
setData({ ...response.data, tlpn: displayNumber });
// Cek apakah ada sub bidang bisnis yang terpilih // Cek apakah ada sub bidang bisnis yang terpilih
const prevSubBidang = response.data.Portofolio_BidangDanSubBidangBisnis; const prevSubBidang = response.data.Portofolio_BidangDanSubBidangBisnis;
@@ -244,15 +299,11 @@ export default function PortofolioEdit() {
} }
const handleSubmitUpdate = async () => { const handleSubmitUpdate = async () => {
const callingCode = selectedCountry?.callingCode.replace(/^\+/, "") || "";
let fixNumber = data.tlpn.replace(/\s+/g, "").replace(/^0+/, "");
const realNumber = callingCode + fixNumber;
const newData: IFormData = { const newData: IFormData = {
id_Portofolio: data.id_Portofolio, id_Portofolio: data.id_Portofolio,
namaBisnis: data.namaBisnis, namaBisnis: data.namaBisnis,
alamatKantor: data.alamatKantor, alamatKantor: data.alamatKantor,
tlpn: realNumber, tlpn: data.tlpn, // Already formatted by PhoneInputCustom
deskripsi: data.deskripsi, deskripsi: data.deskripsi,
masterBidangBisnisId: data.masterBidangBisnisId, masterBidangBisnisId: data.masterBidangBisnisId,
subBidang: listSubBidangSelected, subBidang: listSubBidangSelected,
@@ -317,162 +368,159 @@ export default function PortofolioEdit() {
</BoxButtonOnFooter> </BoxButtonOnFooter>
); );
if (!bidangBisnis || !subBidangBisnis) {
return (
<>
<NewWrapper>
<ListSkeletonComponent height={80} />
</NewWrapper>
</>
);
}
return ( return (
<> <>
<NewWrapper footerComponent={buttonUpdate}> <OS_Wrapper
<StackCustom gap={"xs"}> enableKeyboardHandling
<TextInputCustom contentPaddingBottom={250}
required footerComponent={buttonUpdate}
label="Nama Bisnis" >
placeholder="Masukkan nama bisnis" {!bidangBisnis || !subBidangBisnis ? (
value={data.namaBisnis} <ListSkeletonComponent height={80} />
onChangeText={(value: any) => ) : (
setData({ ...data, namaBisnis: value }) <StackCustom gap={"xs"}>
} <TextInputCustom
/> required
label="Nama Bisnis"
<SelectCustom placeholder="Masukkan nama bisnis"
label="Bidang Usaha" value={data.namaBisnis}
required onChangeText={(value: any) =>
data={bidangBisnis?.map((item) => ({ setData({ ...data, namaBisnis: value })
label: item.name, }
value: item.id,
}))}
value={data.masterBidangBisnisId}
onChange={(value: any) => {
handleBidangBisnisChange(value);
}}
/>
{listSubBidangSelected.map((item, index) => {
// Filter data untuk select sub bidang, menghilangkan yang sudah dipilih kecuali untuk item ini sendiri
const selectedIds = listSubBidangSelected
.filter((_, i) => i !== index)
.map((s) => s.MasterSubBidangBisnis?.id)
.filter((id) => id); // Filter hanya yang memiliki id (tidak kosong)
const availableSubBidangOptions = (selectedSubBidang || [])
.filter((sub: any) => {
// Tampilkan jika ini adalah opsi yang dipilih saat ini atau belum dipilih di sub bidang lainnya
return (
sub.id === item.MasterSubBidangBisnis?.id ||
!selectedIds.includes(sub.id)
);
})
.map((sub: any) => ({
value: sub.id,
label: sub.name,
}));
return (
<SelectCustom
key={index}
label="Sub Bidang Usaha"
required
data={availableSubBidangOptions}
value={item.MasterSubBidangBisnis?.id || null}
onChange={(value: any) => {
handleSubBidangChange(value, index);
}}
/>
);
})}
<CenterCustom>
<View
style={{ flexDirection: "row", alignItems: "center", gap: 10 }}
>
<ActionIcon
disabled={
selectedSubBidang.length === listSubBidangSelected.length
}
onPress={() => {
handleAddSubBidang();
}}
icon={
<Ionicons
name="add-circle-outline"
size={ICON_SIZE_XLARGE}
color={MainColor.black}
/>
}
size="xl"
/>
<ActionIcon
disabled={listSubBidangSelected.length <= 1}
onPress={() => {
handleRemoveSubBidang(listSubBidangSelected.length - 1);
}}
icon={
<Ionicons
name="remove-circle-outline"
size={ICON_SIZE_XLARGE}
color={MainColor.black}
/>
}
size="xl"
/>
</View>
</CenterCustom>
<Spacing />
<View>
<View style={{ flexDirection: "row", alignItems: "center" }}>
<TextCustom semiBold style={{ color: MainColor.white_gray }}>
Nomor Telepon
</TextCustom>
<Text style={{ color: "red" }}> *</Text>
</View>
<Spacing height={5} />
<PhoneInput
value={data.tlpn}
onChangePhoneNumber={handleInputValue}
selectedCountry={selectedCountry}
onChangeSelectedCountry={handleSelectedCountry}
defaultCountry="ID"
placeholder="xxx-xxx-xxx"
/> />
</View>
<Spacing />
<TextInputCustom <SelectCustom
required label="Bidang Usaha"
label="Alamat Bisnis" required
placeholder="Masukkan alamat bisnis" data={bidangBisnis?.map((item) => ({
value={data.alamatKantor} label: item.name,
onChangeText={(value: any) => value: item.id,
setData({ ...data, alamatKantor: value }) }))}
} value={data.masterBidangBisnisId}
/> onChange={(value: any) => {
handleBidangBisnisChange(value);
}}
/>
<TextAreaCustom {listSubBidangSelected.map((item, index) => {
label="Deskripsi Bisnis" // Filter data untuk select sub bidang, menghilangkan yang sudah dipilih kecuali untuk item ini sendiri
placeholder="Masukkan deskripsi bisnis" const selectedIds = listSubBidangSelected
value={data.deskripsi} .filter((_, i) => i !== index)
onChangeText={(value: any) => .map((s) => s.MasterSubBidangBisnis?.id)
setData({ ...data, deskripsi: value }) .filter((id) => id); // Filter hanya yang memiliki id (tidak kosong)
}
autosize const availableSubBidangOptions = (selectedSubBidang || [])
minRows={2} .filter((sub: any) => {
maxRows={5} // Tampilkan jika ini adalah opsi yang dipilih saat ini atau belum dipilih di sub bidang lainnya
required
showCount return (
maxLength={1000} sub.id === item.MasterSubBidangBisnis?.id ||
/> !selectedIds.includes(sub.id)
<Spacing /> );
</StackCustom> })
</NewWrapper> .map((sub: any) => ({
value: sub.id,
label: sub.name,
}));
return (
<SelectCustom
key={index}
label="Sub Bidang Usaha"
required
data={availableSubBidangOptions}
value={item.MasterSubBidangBisnis?.id || null}
onChange={(value: any) => {
handleSubBidangChange(value, index);
}}
/>
);
})}
<CenterCustom>
<View
style={{ flexDirection: "row", alignItems: "center", gap: 10 }}
>
<ActionIcon
disabled={
selectedSubBidang.length === listSubBidangSelected.length
}
onPress={() => {
handleAddSubBidang();
}}
icon={
<Ionicons
name="add-circle-outline"
size={ICON_SIZE_XLARGE}
color={MainColor.black}
/>
}
size="xl"
/>
<ActionIcon
disabled={listSubBidangSelected.length <= 1}
onPress={() => {
handleRemoveSubBidang(listSubBidangSelected.length - 1);
}}
icon={
<Ionicons
name="remove-circle-outline"
size={ICON_SIZE_XLARGE}
color={MainColor.black}
/>
}
size="xl"
/>
</View>
</CenterCustom>
<Spacing />
<View>
<View style={{ flexDirection: "row", alignItems: "center" }}>
<TextCustom semiBold style={{ color: MainColor.white_gray }}>
Nomor Telepon
</TextCustom>
<Text style={{ color: "red" }}> *</Text>
</View>
<Spacing height={5} />
<PhoneInputCustom
value={phoneNumber}
onChangePhoneNumber={handlePhoneChange}
selectedCountry={selectedCountry}
onChangeCountry={handleCountryChange}
placeholder="xxx-xxx-xxx"
/>
</View>
<Spacing />
<TextInputCustom
required
label="Alamat Bisnis"
placeholder="Masukkan alamat bisnis"
value={data.alamatKantor}
onChangeText={(value: any) =>
setData({ ...data, alamatKantor: value })
}
/>
<TextAreaCustom
label="Deskripsi Bisnis"
placeholder="Masukkan deskripsi bisnis"
value={data.deskripsi}
onChangeText={(value: any) =>
setData({ ...data, deskripsi: value })
}
autosize
minRows={2}
maxRows={5}
required
showCount
maxLength={1000}
/>
<Spacing />
</StackCustom>
)}
</OS_Wrapper>
</> </>
); );
} }

View File

@@ -4,14 +4,15 @@ import {
DrawerCustom, DrawerCustom,
DummyLandscapeImage, DummyLandscapeImage,
LoaderCustom, LoaderCustom,
OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import LeftButtonCustom from "@/components/Button/BackButton"; import LeftButtonCustom from "@/components/Button/BackButton";
import GridTwoView from "@/components/_ShareComponent/GridTwoView"; import GridTwoView from "@/components/_ShareComponent/GridTwoView";
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom"; import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_SMALL } from "@/constants/constans-value"; import { ICON_SIZE_SMALL } from "@/constants/constans-value";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
@@ -72,23 +73,26 @@ export default function Portofolio() {
{/* Header */} {/* Header */}
<Stack.Screen <Stack.Screen
options={{ options={{
title: "Portofolio", header: () => (
headerLeft: () => <LeftButtonCustom />, <AppHeader
headerRight: () => title="Portofolio"
data?.Profile?.id !== profileId ? null : ( left={<LeftButtonCustom />}
<TouchableOpacity onPress={openDrawer}> right={
<Ionicons data?.Profile?.id !== profileId ? null : (
name="ellipsis-vertical" <TouchableOpacity onPress={openDrawer}>
size={20} <Ionicons
color={MainColor.yellow} name="ellipsis-vertical"
/> size={20}
</TouchableOpacity> color={MainColor.yellow}
), />
headerStyle: GStyles.headerStyle, </TouchableOpacity>
headerTitleStyle: GStyles.headerTitleStyle, )
}
/>
),
}} }}
/> />
<ViewWrapper> <OS_Wrapper>
{!data || !profileId ? ( {!data || !profileId ? (
<StackCustom> <StackCustom>
<CustomSkeleton height={400} /> <CustomSkeleton height={400} />
@@ -121,7 +125,7 @@ export default function Portofolio() {
<Spacing /> <Spacing />
</StackCustom> </StackCustom>
)} )}
</ViewWrapper> </OS_Wrapper>
{/* Drawer Komponen Eksternal */} {/* Drawer Komponen Eksternal */}
<DrawerCustom <DrawerCustom

View File

@@ -1,5 +1,5 @@
import AppHeader from "@/components/_ShareComponent/AppHeader";
import LeftButtonCustom from "@/components/Button/BackButton"; import LeftButtonCustom from "@/components/Button/BackButton";
import { HeaderStyles } from "@/styles/header-styles";
import { Stack } from "expo-router"; import { Stack } from "expo-router";
export default function PortofolioLayout() { export default function PortofolioLayout() {
@@ -7,8 +7,9 @@ export default function PortofolioLayout() {
<> <>
<Stack <Stack
screenOptions={{ screenOptions={{
...HeaderStyles, header: () => (
headerLeft: () => <LeftButtonCustom />, <AppHeader title="Portofolio" left={<LeftButtonCustom />} />
),
}} }}
> >
{/* <Stack.Screen name="[id]/index" options={{ title: "Portofolio" }} /> */} {/* <Stack.Screen name="[id]/index" options={{ title: "Portofolio" }} /> */}

View File

@@ -3,13 +3,13 @@ import {
BadgeCustom, BadgeCustom,
ClickableCustom, ClickableCustom,
Divider, Divider,
OS_Wrapper,
SelectCustom, SelectCustom,
TextCustom, TextCustom,
} from "@/components"; } from "@/components";
import ListEmptyComponent from "@/components/_ShareComponent/ListEmptyComponent"; import ListEmptyComponent from "@/components/_ShareComponent/ListEmptyComponent";
import ListLoaderFooterComponent from "@/components/_ShareComponent/ListLoaderFooterComponent"; import ListLoaderFooterComponent from "@/components/_ShareComponent/ListLoaderFooterComponent";
import ListSkeletonComponent from "@/components/_ShareComponent/ListSkeletonComponent"; import ListSkeletonComponent from "@/components/_ShareComponent/ListSkeletonComponent";
import NewWrapper from "@/components/_ShareComponent/NewWrapper";
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 { usePaginatedApi } from "@/hooks/use-paginated-api"; import { usePaginatedApi } from "@/hooks/use-paginated-api";
@@ -120,7 +120,7 @@ export default function ProfileBlockedList() {
return ( return (
<> <>
<NewWrapper <OS_Wrapper
// headerComponent={renderHeader()} // headerComponent={renderHeader()}
listData={listData} listData={listData}
renderItem={renderItem} renderItem={renderItem}

View File

@@ -5,7 +5,7 @@ import {
BoxButtonOnFooter, BoxButtonOnFooter,
BoxWithHeaderSection, BoxWithHeaderSection,
ButtonCustom, ButtonCustom,
NewWrapper, OS_Wrapper,
StackCustom, StackCustom,
TextCustom, TextCustom,
} from "@/components"; } from "@/components";
@@ -46,7 +46,7 @@ export default function ProfileDetailBlocked() {
return ( return (
<> <>
<NewWrapper <OS_Wrapper
footerComponent={ footerComponent={
<BoxButtonOnFooter> <BoxButtonOnFooter>
<ButtonCustom <ButtonCustom
@@ -86,7 +86,7 @@ export default function ProfileDetailBlocked() {
</TextCustom> </TextCustom>
</StackCustom> </StackCustom>
</BoxWithHeaderSection> </BoxWithHeaderSection>
</NewWrapper> </OS_Wrapper>
</> </>
); );
} }

View File

@@ -1,11 +1,12 @@
import { import {
ButtonCustom, ButtonCustom,
OS_Wrapper,
SelectCustom, SelectCustom,
StackCustom, StackCustom,
TextInputCustom, TextInputCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import BoxButtonOnFooter from "@/components/Box/BoxButtonOnFooter"; import BoxButtonOnFooter from "@/components/Box/BoxButtonOnFooter";
import { PADDING_INLINE } from "@/constants/constans-value";
import { apiProfile, apiUpdateProfile } from "@/service/api-client/api-profile"; import { apiProfile, apiUpdateProfile } from "@/service/api-client/api-profile";
import { IProfile } from "@/types/Type-Profile"; import { IProfile } from "@/types/Type-Profile";
import { router, useLocalSearchParams } from "expo-router"; import { router, useLocalSearchParams } from "expo-router";
@@ -70,7 +71,9 @@ export default function ProfileEdit() {
}; };
return ( return (
<ViewWrapper <OS_Wrapper
enableKeyboardHandling
contentPaddingBottom={250}
footerComponent={ footerComponent={
<BoxButtonOnFooter> <BoxButtonOnFooter>
<ButtonCustom isLoading={isLoading} onPress={handleUpdate}> <ButtonCustom isLoading={isLoading} onPress={handleUpdate}>
@@ -119,6 +122,6 @@ export default function ProfileEdit() {
}} }}
/> />
</StackCustom> </StackCustom>
</ViewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -1,5 +1,6 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { NewWrapper, StackCustom } from "@/components"; import { OS_Wrapper, StackCustom } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom"; import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
import LeftButtonCustom from "@/components/Button/BackButton"; import LeftButtonCustom from "@/components/Button/BackButton";
import DrawerCustom from "@/components/Drawer/DrawerCustom"; import DrawerCustom from "@/components/Drawer/DrawerCustom";
@@ -101,22 +102,24 @@ export default function Profile() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: `Profile`, header: () => (
headerLeft: () => <LeftButtonCustom />, <AppHeader
headerRight: () => ( title="Profile"
<ButtonnDot left={<LeftButtonCustom />}
id={id as string} right={
openDrawer={openDrawer} <ButtonnDot
isUserCheck={isUserCheck()} id={id as string}
logout={logout} openDrawer={openDrawer}
isUserCheck={isUserCheck()}
logout={logout}
/>
}
/> />
), ),
headerStyle: GStyles.headerStyle,
headerTitleStyle: GStyles.headerTitleStyle,
}} }}
/> />
{/* Main View */} {/* Main View */}
<NewWrapper <OS_Wrapper
refreshControl={ refreshControl={
<RefreshControl <RefreshControl
refreshing={refreshing} refreshing={refreshing}
@@ -141,7 +144,7 @@ export default function Profile() {
/> />
</> </>
)} )}
</NewWrapper> </OS_Wrapper>
{/* Drawer Komponen Eksternal */} {/* Drawer Komponen Eksternal */}
<DrawerCustom <DrawerCustom

View File

@@ -3,8 +3,8 @@ import {
BoxButtonOnFooter, BoxButtonOnFooter,
ButtonCenteredOnly, ButtonCenteredOnly,
ButtonCustom, ButtonCustom,
OS_Wrapper,
} from "@/components"; } from "@/components";
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
import API_STRORAGE from "@/constants/base-url-api-strorage"; import API_STRORAGE from "@/constants/base-url-api-strorage";
import DIRECTORY_ID from "@/constants/directory-id"; import DIRECTORY_ID from "@/constants/directory-id";
import DUMMY_IMAGE from "@/constants/dummy-image-value"; import DUMMY_IMAGE from "@/constants/dummy-image-value";
@@ -127,7 +127,7 @@ export default function UpdateBackgroundProfile() {
); );
return ( return (
<ViewWrapper footerComponent={buttonFooter}> <OS_Wrapper footerComponent={buttonFooter}>
<BaseBox <BaseBox
style={{ alignItems: "center", justifyContent: "center", height: 250 }} style={{ alignItems: "center", justifyContent: "center", height: 250 }}
> >
@@ -144,6 +144,6 @@ export default function UpdateBackgroundProfile() {
> >
Update Update
</ButtonCenteredOnly> </ButtonCenteredOnly>
</ViewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -3,8 +3,8 @@ import {
BoxButtonOnFooter, BoxButtonOnFooter,
ButtonCenteredOnly, ButtonCenteredOnly,
ButtonCustom, ButtonCustom,
OS_Wrapper,
} from "@/components"; } from "@/components";
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
import API_STRORAGE from "@/constants/base-url-api-strorage"; import API_STRORAGE from "@/constants/base-url-api-strorage";
import DIRECTORY_ID from "@/constants/directory-id"; import DIRECTORY_ID from "@/constants/directory-id";
import DUMMY_IMAGE from "@/constants/dummy-image-value"; import DUMMY_IMAGE from "@/constants/dummy-image-value";
@@ -125,7 +125,7 @@ export default function UpdatePhotoProfile() {
); );
return ( return (
<ViewWrapper footerComponent={buttonFooter}> <OS_Wrapper footerComponent={buttonFooter}>
<BaseBox <BaseBox
style={{ alignItems: "center", justifyContent: "center", height: 250 }} style={{ alignItems: "center", justifyContent: "center", height: 250 }}
> >
@@ -143,6 +143,6 @@ export default function UpdatePhotoProfile() {
> >
Upload Upload
</ButtonCenteredOnly> </ButtonCenteredOnly>
</ViewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -1,47 +1,43 @@
import { BackButton } from "@/components"; import { BackButton } from "@/components";
import { GStyles } from "@/styles/global-styles"; import AppHeader from "@/components/_ShareComponent/AppHeader";
import { Stack } from "expo-router"; import { Stack } from "expo-router";
export default function ProfileLayout() { export default function ProfileLayout() {
return ( return (
<> <>
<Stack <Stack>
screenOptions={{
headerStyle: GStyles.headerStyle,
headerTitleStyle: GStyles.headerTitleStyle,
headerTitleAlign: "center",
headerBackButtonDisplayMode: "minimal",
}}
>
{/* <Stack.Screen name="[id]/index" options={{ headerShown: false }} /> */} {/* <Stack.Screen name="[id]/index" options={{ headerShown: false }} /> */}
<Stack.Screen <Stack.Screen
name="[id]/edit" name="[id]/edit"
options={{ title: "Edit Profile", headerLeft: () => <BackButton /> }} options={{ header: () => <AppHeader title="Edit Profile" /> }}
/> />
<Stack.Screen <Stack.Screen
name="[id]/update-photo" name="[id]/update-photo"
options={{ title: "Update Foto", headerLeft: () => <BackButton /> }} options={{ header: () => <AppHeader title="Update Foto" /> }}
/> />
<Stack.Screen <Stack.Screen
name="[id]/update-background" name="[id]/update-background"
options={{ options={{
title: "Update Latar Belakang", header: () => <AppHeader title="Update Latar Belakang" />,
headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen <Stack.Screen
name="create" name="create"
options={{ title: "Buat Profile", headerBackVisible: false }} options={{
header: () => (
<AppHeader title="Tambah Profil" showBack={false} />
),
}}
/> />
<Stack.Screen <Stack.Screen
name="[id]/blocked-list" name="[id]/blocked-list"
options={{ title: "Daftar Blokir", headerLeft: () => <BackButton /> }} options={{ header: () => <AppHeader title="Daftar Blokir" /> }}
/> />
<Stack.Screen <Stack.Screen
name="[id]/detail-blocked" name="[id]/detail-blocked"
options={{ title: "Detail Blokir", headerLeft: () => <BackButton /> }} options={{ header: () => <AppHeader title="Detail Blokir" /> }}
/> />
</Stack> </Stack>
</> </>

View File

@@ -2,16 +2,17 @@ import {
BaseBox, BaseBox,
ButtonCenteredOnly, ButtonCenteredOnly,
ButtonCustom, ButtonCustom,
OS_Wrapper,
SelectCustom, SelectCustom,
Spacing, Spacing,
StackCustom, StackCustom,
TextInputCustom, TextInputCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import BoxButtonOnFooter from "@/components/Box/BoxButtonOnFooter"; import BoxButtonOnFooter from "@/components/Box/BoxButtonOnFooter";
import InformationBox from "@/components/Box/InformationBox"; import InformationBox from "@/components/Box/InformationBox";
import DIRECTORY_ID from "@/constants/directory-id"; import DIRECTORY_ID from "@/constants/directory-id";
import DUMMY_IMAGE from "@/constants/dummy-image-value"; import DUMMY_IMAGE from "@/constants/dummy-image-value";
import { PADDING_INLINE } from "@/constants/constans-value";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
import { apiCreateProfile } from "@/service/api-client/api-profile"; import { apiCreateProfile } from "@/service/api-client/api-profile";
import { apiValidationEmail } from "@/service/api-client/api-validation"; import { apiValidationEmail } from "@/service/api-client/api-validation";
@@ -155,7 +156,11 @@ export default function CreateProfile() {
); );
return ( return (
<ViewWrapper footerComponent={footerComponent}> <OS_Wrapper
enableKeyboardHandling
contentPaddingBottom={250}
footerComponent={footerComponent}
>
<StackCustom> <StackCustom>
<InformationBox text="Upload foto profile anda." /> <InformationBox text="Upload foto profile anda." />
<View style={{ alignItems: "center" }}> <View style={{ alignItems: "center" }}>
@@ -241,6 +246,6 @@ export default function CreateProfile() {
/> />
<Spacing /> <Spacing />
</StackCustom> </StackCustom>
</ViewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -4,64 +4,87 @@ import {
IconHome, IconHome,
IconStatus, IconStatus,
} from "@/components/_Icon"; } from "@/components/_Icon";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import BackButtonFromNotification from "@/components/Button/BackButtonFromNotification"; import BackButtonFromNotification from "@/components/Button/BackButtonFromNotification";
import { OS_ANDROID_HEIGHT, OS_IOS_HEIGHT } from "@/constants/constans-value";
import { TabsStyles } from "@/styles/tabs-styles"; import { TabsStyles } from "@/styles/tabs-styles";
import { Tabs, useLocalSearchParams, useNavigation, router } from "expo-router"; import { router, Tabs, useLocalSearchParams } from "expo-router";
import { useLayoutEffect } from "react"; import { View } from "react-native";
import { MainColor } from "@/constants/color-palet";
export default function VotingTabsLayout() { import { useSafeAreaInsets } from "react-native-safe-area-context";
const navigation = useNavigation(); import { Platform } from "react-native";
function VotingTabsWrapper() {
const insets = useSafeAreaInsets();
const paddingBottom = Platform.OS === "android" ? insets.bottom : 0;
const { from, category } = useLocalSearchParams<{ const { from, category } = useLocalSearchParams<{
from?: string; from?: string;
category?: string; category?: string;
}>(); }>();
console.log("from", from);
console.log("category", category);
// Atur header secara dinamis
useLayoutEffect(() => {
navigation.setOptions({
headerLeft: () => (
<BackButtonFromNotification
from={from as string}
category={category as string}
/>
),
});
}, [from, router, navigation]);
return ( return (
<Tabs screenOptions={TabsStyles}> <View style={{ flex: 1, backgroundColor: MainColor.darkblue }}>
<Tabs.Screen <Tabs
name="index" screenOptions={{
options={{ ...TabsStyles,
title: "Beranda", tabBarStyle: Platform.select({
tabBarIcon: ({ color }) => <IconHome color={color} />, ios: {
borderTopWidth: 0,
paddingTop: 12,
height: OS_IOS_HEIGHT,
},
android: {
borderTopWidth: 0,
paddingTop: 5,
height: OS_ANDROID_HEIGHT + paddingBottom,
},
}),
header: () => (
<AppHeader
title="Voting"
left={
<BackButtonFromNotification
from={from || ""}
category={category}
/>
}
/>
),
}} }}
/> >
<Tabs.Screen <Tabs.Screen
name="status" name="index"
options={{ options={{
title: "Status", title: "Beranda",
tabBarIcon: ({ color }) => <IconStatus color={color} />, tabBarIcon: ({ color }) => <IconHome color={color} />,
}} }}
/> />
<Tabs.Screen <Tabs.Screen
name="contribution" name="status"
options={{ options={{
title: "Kontribusi", title: "Status",
tabBarIcon: ({ color }) => <IconContribution color={color} />, tabBarIcon: ({ color }) => <IconStatus color={color} />,
}} }}
/> />
<Tabs.Screen <Tabs.Screen
name="history" name="contribution"
options={{ options={{
title: "Riwayat", title: "Kontribusi",
tabBarIcon: ({ color }) => <IconHistory color={color} />, tabBarIcon: ({ color }) => <IconContribution color={color} />,
}} }}
/> />
</Tabs> <Tabs.Screen
name="history"
options={{
title: "Riwayat",
tabBarIcon: ({ color }) => <IconHistory color={color} />,
}}
/>
</Tabs>
</View>
); );
} }
export default function VotingTabsLayout() {
return <VotingTabsWrapper />;
}

View File

@@ -7,11 +7,12 @@ import {
DrawerCustom, DrawerCustom,
LoaderCustom, LoaderCustom,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { IconArchive, IconContribution, IconEdit } from "@/components/_Icon"; import { IconArchive, IconContribution, IconEdit } from "@/components/_Icon";
import { IMenuDrawerItem } from "@/components/_Interface/types"; import { IMenuDrawerItem } from "@/components/_Interface/types";
import ReportBox from "@/components/Box/ReportBox"; import ReportBox from "@/components/Box/ReportBox";
@@ -103,17 +104,22 @@ export default function VotingDetailStatus() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: `Detail`, header: () => (
headerLeft: () => <BackButton />, <AppHeader
headerRight: () => title="Detail"
status === "draft" ? ( left={<BackButton />}
<DotButton onPress={() => setOpenDrawerDraft(true)} /> right={
) : status === "publish" ? ( status === "draft" ? (
<DotButton onPress={() => setOpenDrawerPublish(true)} /> <DotButton onPress={() => setOpenDrawerDraft(true)} />
) : null, ) : status === "publish" ? (
<DotButton onPress={() => setOpenDrawerPublish(true)} />
) : null
}
/>
),
}} }}
/> />
<ViewWrapper> <OS_Wrapper>
{loadingGetData ? ( {loadingGetData ? (
<LoaderCustom /> <LoaderCustom />
) : ( ) : (
@@ -152,7 +158,7 @@ export default function VotingDetailStatus() {
<Spacing /> <Spacing />
</> </>
)} )}
</ViewWrapper> </OS_Wrapper>
{/* ========= Draft Drawer ========= */} {/* ========= Draft Drawer ========= */}
<DrawerCustom <DrawerCustom

View File

@@ -6,9 +6,10 @@ import {
DrawerCustom, DrawerCustom,
LoaderCustom, LoaderCustom,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
OS_Wrapper,
Spacing, Spacing,
ViewWrapper,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { IconContribution } from "@/components/_Icon"; import { IconContribution } from "@/components/_Icon";
import { IMenuDrawerItem } from "@/components/_Interface/types"; import { IMenuDrawerItem } from "@/components/_Interface/types";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
@@ -81,15 +82,19 @@ export default function VotingDetailContribution() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: "Detail Kontribusi", header: () => (
headerLeft: () => <BackButton />, <AppHeader
headerRight: () => ( title="Detail Kontribusi"
<DotButton onPress={() => setOpenDrawerPublish(true)} /> left={<BackButton />}
right={
<DotButton onPress={() => setOpenDrawerPublish(true)} />
}
/>
), ),
}} }}
/> />
<ViewWrapper> <OS_Wrapper>
{loadingGetData ? ( {loadingGetData ? (
<LoaderCustom /> <LoaderCustom />
) : ( ) : (
@@ -111,7 +116,7 @@ export default function VotingDetailContribution() {
<Spacing /> <Spacing />
</> </>
)} )}
</ViewWrapper> </OS_Wrapper>
{/* ========= Publish Drawer ========= */} {/* ========= Publish Drawer ========= */}
<DrawerCustom <DrawerCustom

View File

@@ -5,7 +5,7 @@ import {
ButtonCustom, ButtonCustom,
CenterCustom, CenterCustom,
LoaderCustom, LoaderCustom,
NewWrapper, OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
TextAreaCustom, TextAreaCustom,
@@ -189,7 +189,11 @@ export default function VotingEdit() {
}; };
return ( return (
<NewWrapper footerComponent={buttonSubmit()}> <OS_Wrapper
enableKeyboardHandling
contentPaddingBottom={250}
footerComponent={buttonSubmit()}
>
{loadingGetData ? ( {loadingGetData ? (
<ListSkeletonComponent /> <ListSkeletonComponent />
) : ( ) : (
@@ -328,6 +332,6 @@ export default function VotingEdit() {
<Spacing /> <Spacing />
</StackCustom> </StackCustom>
)} )}
</NewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -6,9 +6,10 @@ import {
DrawerCustom, DrawerCustom,
LoaderCustom, LoaderCustom,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
OS_Wrapper,
Spacing, Spacing,
ViewWrapper,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { IconContribution } from "@/components/_Icon"; import { IconContribution } from "@/components/_Icon";
import { IMenuDrawerItem } from "@/components/_Interface/types"; import { IMenuDrawerItem } from "@/components/_Interface/types";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
@@ -82,14 +83,18 @@ export default function VotingDetailHistory() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: "Riwayat Voting", header: () => (
headerLeft: () => <BackButton />, <AppHeader
headerRight: () => ( title="Riwayat Voting"
<DotButton onPress={() => setOpenDrawerPublish(true)} /> left={<BackButton />}
right={
<DotButton onPress={() => setOpenDrawerPublish(true)} />
}
/>
), ),
}} }}
/> />
<ViewWrapper> <OS_Wrapper>
{loadingGetData ? ( {loadingGetData ? (
<LoaderCustom /> <LoaderCustom />
) : ( ) : (
@@ -111,7 +116,7 @@ export default function VotingDetailHistory() {
<Spacing /> <Spacing />
</> </>
)} )}
</ViewWrapper> </OS_Wrapper>
{/* ========= Publish Drawer ========= */} {/* ========= Publish Drawer ========= */}
<DrawerCustom <DrawerCustom

View File

@@ -8,9 +8,10 @@ import {
InformationBox, InformationBox,
LoaderCustom, LoaderCustom,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
OS_Wrapper,
StackCustom, StackCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import { IconArchive, IconContribution } from "@/components/_Icon"; import { IconArchive, IconContribution } from "@/components/_Icon";
import { IMenuDrawerItem } from "@/components/_Interface/types"; import { IMenuDrawerItem } from "@/components/_Interface/types";
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom"; import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
@@ -31,6 +32,7 @@ import {
useLocalSearchParams, useLocalSearchParams,
} from "expo-router"; } from "expo-router";
import React, { useCallback, useEffect, useState } from "react"; import React, { useCallback, useEffect, useState } from "react";
import { RefreshControl } from "react-native";
import Toast from "react-native-toast-message"; import Toast from "react-native-toast-message";
export default function VotingDetail() { export default function VotingDetail() {
@@ -132,9 +134,9 @@ export default function VotingDetail() {
if (isEventFinished) { if (isEventFinished) {
return ( return (
<ViewWrapper> <OS_Wrapper>
<CustomSkeleton /> <CustomSkeleton />
</ViewWrapper> </OS_Wrapper>
); );
} }
@@ -142,15 +144,26 @@ export default function VotingDetail() {
<> <>
<Stack.Screen <Stack.Screen
options={{ options={{
title: `Detail Voting`, header: () => (
headerLeft: () => <BackButton />, <AppHeader
headerRight: () => ( title="Detail Voting"
<DotButton onPress={() => setOpenDrawerPublish(true)} /> left={<BackButton />}
right={
<DotButton onPress={() => setOpenDrawerPublish(true)} />
}
/>
), ),
}} }}
/> />
<ViewWrapper> <OS_Wrapper
refreshControl={
<RefreshControl
refreshing={loadingGetData}
onRefresh={handlerLoadData}
/>
}
>
{loadingGetData ? ( {loadingGetData ? (
<LoaderCustom /> <LoaderCustom />
) : ( ) : (
@@ -177,7 +190,7 @@ export default function VotingDetail() {
/> />
</StackCustom> </StackCustom>
)} )}
</ViewWrapper> </OS_Wrapper>
{/* ========= Publish Drawer ========= */} {/* ========= Publish Drawer ========= */}
<DrawerCustom <DrawerCustom

View File

@@ -3,12 +3,11 @@ import {
BoxButtonOnFooter, BoxButtonOnFooter,
ButtonCustom, ButtonCustom,
CenterCustom, CenterCustom,
NewWrapper, OS_Wrapper,
Spacing, Spacing,
StackCustom, StackCustom,
TextAreaCustom, TextAreaCustom,
TextInputCustom, TextInputCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import DateTimePickerCustom from "@/components/DateInput/DateTimePickerCustom"; import DateTimePickerCustom from "@/components/DateInput/DateTimePickerCustom";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
@@ -107,7 +106,11 @@ export default function VotingCreate() {
}; };
return ( return (
<NewWrapper footerComponent={buttonSubmit()}> <OS_Wrapper
enableKeyboardHandling
contentPaddingBottom={250}
footerComponent={buttonSubmit()}
>
<StackCustom gap={"xs"}> <StackCustom gap={"xs"}>
<TextInputCustom <TextInputCustom
label="Judul Voting" label="Judul Voting"
@@ -198,6 +201,6 @@ export default function VotingCreate() {
<Spacing /> <Spacing />
</StackCustom> </StackCustom>
</NewWrapper> </OS_Wrapper>
); );
} }

View File

@@ -3,7 +3,7 @@ import {
BoxButtonOnFooter, BoxButtonOnFooter,
ButtonCustom, ButtonCustom,
InformationBox, InformationBox,
NewWrapper, OS_Wrapper,
StackCustom StackCustom
} from "@/components"; } from "@/components";
import { ICON_SIZE_BUTTON } from "@/constants/constans-value"; import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
@@ -82,7 +82,7 @@ export default function WaitingRoom() {
return ( return (
<> <>
<NewWrapper <OS_Wrapper
footerComponent={logoutButton()} footerComponent={logoutButton()}
refreshControl={ refreshControl={
<RefreshControl refreshing={isLoading} onRefresh={handleCheck} /> <RefreshControl refreshing={isLoading} onRefresh={handleCheck} />
@@ -103,7 +103,7 @@ Silakan tunggu beberapa saat. Untuk memperbarui status, tarik layar ke bawah."
Check Check
</ButtonCenteredOnly> */} </ButtonCenteredOnly> */}
</StackCustom> </StackCustom>
</NewWrapper> </OS_Wrapper>
</> </>
); );
} }

View File

@@ -1,8 +1,8 @@
import { BackButton } from "@/components"; import { BackButton } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import BackgroundNotificationHandler from "@/components/Notification/BackgroundNotificationHandler"; import BackgroundNotificationHandler from "@/components/Notification/BackgroundNotificationHandler";
import NotificationInitializer from "@/components/Notification/NotificationInitializer"; import NotificationInitializer from "@/components/Notification/NotificationInitializer";
import { NotificationProvider } from "@/hooks/use-notification-store"; import { NotificationProvider } from "@/hooks/use-notification-store";
import { HeaderStyles } from "@/styles/header-styles";
import { Stack } from "expo-router"; import { Stack } from "expo-router";
export default function ApplicationLayout() { export default function ApplicationLayout() {
@@ -20,7 +20,7 @@ export default function ApplicationLayout() {
function ApplicationStack() { function ApplicationStack() {
return ( return (
<> <>
<Stack screenOptions={HeaderStyles}> <Stack>
<Stack.Screen name="(user)" options={{ headerShown: false }} /> <Stack.Screen name="(user)" options={{ headerShown: false }} />
<Stack.Screen name="admin" options={{ headerShown: false }} /> <Stack.Screen name="admin" options={{ headerShown: false }} />
@@ -28,8 +28,7 @@ function ApplicationStack() {
<Stack.Screen <Stack.Screen
name="(image)/take-picture/[id]/index" name="(image)/take-picture/[id]/index"
options={{ options={{
title: "Ambil Gambar", header: () => <AppHeader title="Ambil Gambar" />,
headerLeft: () => <BackButton />,
}} }}
/> />
@@ -37,8 +36,7 @@ function ApplicationStack() {
<Stack.Screen <Stack.Screen
name="(image)/preview-image/[id]/index" name="(image)/preview-image/[id]/index"
options={{ options={{
title: "Preview Gambar", header: () => <AppHeader title="Preview Gambar" />,
headerLeft: () => <BackButton />,
}} }}
/> />
</Stack> </Stack>

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