Compare commits
18 Commits
api-admin/
...
api-admin/
| Author | SHA1 | Date | |
|---|---|---|---|
| b3209dc7ee | |||
| 1e1b18f860 | |||
| 5d4328a139 | |||
| 125bf16605 | |||
| 73a803f2e8 | |||
| 1bcd1a044f | |||
| 1e0b72de22 | |||
| 36dbfa3296 | |||
| 966e55597c | |||
| 4da55a5a8a | |||
| faf0f36e53 | |||
| 57285e5697 | |||
| 1fd9694ebf | |||
| d31df8c390 | |||
| 90cfb042d8 | |||
| b9f93ff46a | |||
| 0770237fe5 | |||
| 6f4dd79568 |
42
.gitignore
vendored
42
.gitignore
vendored
@@ -40,3 +40,45 @@ app-example
|
||||
.qodo
|
||||
|
||||
.env
|
||||
|
||||
# @generated expo-cli sync-8d4afeec25ea8a192358fae2f8e2fc766bdce4ec
|
||||
# The following patterns were generated by expo-cli
|
||||
|
||||
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
# Expo
|
||||
.expo/
|
||||
dist/
|
||||
web-build/
|
||||
expo-env.d.ts
|
||||
|
||||
# Native
|
||||
*.orig.*
|
||||
*.jks
|
||||
*.p8
|
||||
*.p12
|
||||
*.key
|
||||
*.mobileprovision
|
||||
|
||||
# Metro
|
||||
.metro-health-check*
|
||||
|
||||
# debug
|
||||
npm-debug.*
|
||||
yarn-debug.*
|
||||
yarn-error.*
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
|
||||
# @end expo-cli
|
||||
@@ -64,9 +64,9 @@ react {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to true to Run Proguard on Release builds to minify the Java bytecode.
|
||||
* Set this to true in release builds to optimize the app using [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization).
|
||||
*/
|
||||
def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInReleaseBuilds') ?: false).toBoolean()
|
||||
def enableMinifyInReleaseBuilds = (findProperty('android.enableMinifyInReleaseBuilds') ?: false).toBoolean()
|
||||
|
||||
/**
|
||||
* The preferred build flavor of JavaScriptCore (JSC)
|
||||
@@ -94,6 +94,8 @@ android {
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 1
|
||||
versionName "1.0.0"
|
||||
|
||||
buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\""
|
||||
}
|
||||
signingConfigs {
|
||||
debug {
|
||||
@@ -111,15 +113,18 @@ android {
|
||||
// Caution! In production, you need to generate your own keystore file.
|
||||
// see https://reactnative.dev/docs/signed-apk-android.
|
||||
signingConfig signingConfigs.debug
|
||||
shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
|
||||
minifyEnabled enableProguardInReleaseBuilds
|
||||
def enableShrinkResources = findProperty('android.enableShrinkResourcesInReleaseBuilds') ?: 'false'
|
||||
shrinkResources enableShrinkResources.toBoolean()
|
||||
minifyEnabled enableMinifyInReleaseBuilds
|
||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||
crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true)
|
||||
def enablePngCrunchInRelease = findProperty('android.enablePngCrunchInReleaseBuilds') ?: 'true'
|
||||
crunchPngs enablePngCrunchInRelease.toBoolean()
|
||||
}
|
||||
}
|
||||
packagingOptions {
|
||||
jniLibs {
|
||||
useLegacyPackaging (findProperty('expo.useLegacyPackaging')?.toBoolean() ?: false)
|
||||
def enableLegacyPackaging = findProperty('expo.useLegacyPackaging') ?: 'false'
|
||||
useLegacyPackaging enableLegacyPackaging.toBoolean()
|
||||
}
|
||||
}
|
||||
androidResources {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<data android:scheme="https"/>
|
||||
</intent>
|
||||
</queries>
|
||||
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true">
|
||||
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true" android:enableOnBackInvokedCallback="false">
|
||||
<meta-data android:name="expo.modules.updates.ENABLED" android:value="false"/>
|
||||
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
|
||||
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
|
||||
|
||||
@@ -5,13 +5,13 @@ import android.content.res.Configuration
|
||||
|
||||
import com.facebook.react.PackageList
|
||||
import com.facebook.react.ReactApplication
|
||||
import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
|
||||
import com.facebook.react.ReactNativeHost
|
||||
import com.facebook.react.ReactPackage
|
||||
import com.facebook.react.ReactHost
|
||||
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
|
||||
import com.facebook.react.common.ReleaseLevel
|
||||
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint
|
||||
import com.facebook.react.defaults.DefaultReactNativeHost
|
||||
import com.facebook.react.soloader.OpenSourceMergedSoMapping
|
||||
import com.facebook.soloader.SoLoader
|
||||
|
||||
import expo.modules.ApplicationLifecycleDispatcher
|
||||
import expo.modules.ReactNativeHostWrapper
|
||||
@@ -19,21 +19,19 @@ import expo.modules.ReactNativeHostWrapper
|
||||
class MainApplication : Application(), ReactApplication {
|
||||
|
||||
override val reactNativeHost: ReactNativeHost = ReactNativeHostWrapper(
|
||||
this,
|
||||
object : DefaultReactNativeHost(this) {
|
||||
override fun getPackages(): List<ReactPackage> {
|
||||
val packages = PackageList(this).packages
|
||||
// Packages that cannot be autolinked yet can be added manually here, for example:
|
||||
// packages.add(MyReactNativePackage())
|
||||
return packages
|
||||
}
|
||||
this,
|
||||
object : DefaultReactNativeHost(this) {
|
||||
override fun getPackages(): List<ReactPackage> =
|
||||
PackageList(this).packages.apply {
|
||||
// Packages that cannot be autolinked yet can be added manually here, for example:
|
||||
// add(MyReactNativePackage())
|
||||
}
|
||||
|
||||
override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry"
|
||||
|
||||
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
|
||||
|
||||
override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
|
||||
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
|
||||
}
|
||||
)
|
||||
|
||||
@@ -42,11 +40,12 @@ class MainApplication : Application(), ReactApplication {
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
SoLoader.init(this, OpenSourceMergedSoMapping)
|
||||
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
||||
// If you opted-in for the New Architecture, we load the native entry point for this app.
|
||||
load()
|
||||
DefaultNewArchitectureEntryPoint.releaseLevel = try {
|
||||
ReleaseLevel.valueOf(BuildConfig.REACT_NATIVE_RELEASE_LEVEL.uppercase())
|
||||
} catch (e: IllegalArgumentException) {
|
||||
ReleaseLevel.STABLE
|
||||
}
|
||||
loadReactNative(this)
|
||||
ApplicationLifecycleDispatcher.onApplicationCreate(this)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<style name="AppTheme" parent="Theme.EdgeToEdge">
|
||||
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
|
||||
<item name="android:enforceNavigationBarContrast" tools:targetApi="29">true</item>
|
||||
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="android:statusBarColor">#ffffff</item>
|
||||
@@ -8,5 +9,6 @@
|
||||
<item name="windowSplashScreenBackground">@color/splashscreen_background</item>
|
||||
<item name="windowSplashScreenAnimatedIcon">@drawable/splashscreen_logo</item>
|
||||
<item name="postSplashScreenTheme">@style/AppTheme</item>
|
||||
<item name="android:windowSplashScreenBehavior">icon_preferred</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -12,21 +12,8 @@ buildscript {
|
||||
}
|
||||
}
|
||||
|
||||
def reactNativeAndroidDir = new File(
|
||||
providers.exec {
|
||||
workingDir(rootDir)
|
||||
commandLine("node", "--print", "require.resolve('react-native/package.json')")
|
||||
}.standardOutput.asText.get().trim(),
|
||||
"../android"
|
||||
)
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
maven {
|
||||
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
||||
url(reactNativeAndroidDir)
|
||||
}
|
||||
|
||||
google()
|
||||
mavenCentral()
|
||||
maven { url 'https://www.jitpack.io' }
|
||||
|
||||
@@ -15,7 +15,7 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
org.gradle.parallel=true
|
||||
|
||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||
# Android operating system, and which are packaged with your app's APK
|
||||
@@ -41,6 +41,11 @@ newArchEnabled=true
|
||||
# If set to false, you will be using JSC instead.
|
||||
hermesEnabled=true
|
||||
|
||||
# Use this property to enable edge-to-edge display support.
|
||||
# This allows your app to draw behind system bars for an immersive UI.
|
||||
# Note: Only works with ReactActivity and should not be used with custom Activity.
|
||||
edgeToEdgeEnabled=true
|
||||
|
||||
# Enable GIF support in React Native images (~200 B increase)
|
||||
expo.gif.enabled=true
|
||||
# Enable webp support in React Native images (~85 KB increase)
|
||||
@@ -55,5 +60,6 @@ EX_DEV_CLIENT_NETWORK_INSPECTOR=true
|
||||
# Use legacy packaging to compress native libraries in the resulting APK.
|
||||
expo.useLegacyPackaging=false
|
||||
|
||||
# Whether the app is configured to use edge-to-edge via the app config or `react-native-edge-to-edge` plugin
|
||||
expo.edgeToEdgeEnabled=true
|
||||
# Specifies whether the app is configured to use edge-to-edge via the app config or plugin
|
||||
# WARNING: This property has been deprecated and will be removed in Expo SDK 55. Use `edgeToEdgeEnabled` or `react.edgeToEdgeEnabled` to determine whether the project is using edge-to-edge.
|
||||
expo.edgeToEdgeEnabled=true
|
||||
|
||||
BIN
android/gradle/wrapper/gradle-wrapper.jar
vendored
BIN
android/gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
4
android/gradlew
vendored
4
android/gradlew
vendored
@@ -114,7 +114,7 @@ case "$( uname )" in #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
CLASSPATH="\\\"\\\""
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
@@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
|
||||
4
android/gradlew.bat
vendored
4
android/gradlew.bat
vendored
@@ -70,11 +70,11 @@ goto fail
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
set CLASSPATH=
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
||||
@@ -70,5 +70,6 @@ export default {
|
||||
// Tambahkan environment variables ke sini
|
||||
API_BASE_URL: process.env.API_BASE_URL,
|
||||
BASE_URL: process.env.BASE_URL,
|
||||
DEEP_LINK_URL: process.env.DEEP_LINK_URL,
|
||||
},
|
||||
};
|
||||
@@ -19,7 +19,6 @@ import Toast from "react-native-toast-message";
|
||||
|
||||
export default function CollaborationEdit() {
|
||||
const { id } = useLocalSearchParams();
|
||||
console.log("id :", id);
|
||||
const [data, setData] = useState<any>();
|
||||
const [listMaster, setListMaster] = useState<any[]>([]);
|
||||
const [loadingData, setLoadingData] = useState(false);
|
||||
|
||||
@@ -122,7 +122,7 @@ export default function DonationInvoice() {
|
||||
}}
|
||||
>
|
||||
<TextCustom size="xlarge" bold color="yellow">
|
||||
{data?.DonasiMaster_Bank?.norek}
|
||||
{data?.MasterBank?.norek}
|
||||
</TextCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col
|
||||
@@ -131,7 +131,7 @@ export default function DonationInvoice() {
|
||||
alignItems: "flex-end",
|
||||
}}
|
||||
>
|
||||
<CopyButton textToCopy={data?.DonasiMaster_Bank?.norek} />
|
||||
<CopyButton textToCopy={data?.MasterBank?.norek} />
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</BaseBox>
|
||||
|
||||
@@ -1,17 +1,71 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
BaseBox,
|
||||
ButtonCenteredOnly,
|
||||
Grid,
|
||||
InformationBox,
|
||||
LoaderCustom,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import {
|
||||
apiDonationDisbursementOfFundsListById,
|
||||
apiDonationGetOne,
|
||||
} from "@/service/api-client/api-donation";
|
||||
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
|
||||
import dayjs from "dayjs";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import React, { useState } from "react";
|
||||
|
||||
export default function DonationFundDisbursement() {
|
||||
const { id } = useLocalSearchParams();
|
||||
|
||||
const [data, setData] = useState({
|
||||
totalPencairan: 0,
|
||||
akumulasiPencairan: 0,
|
||||
});
|
||||
|
||||
const [listData, setListData] = React.useState<any[] | null>(null);
|
||||
const [loadData, setLoadData] = React.useState(false);
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadData(true);
|
||||
|
||||
const responseData = await apiDonationGetOne({
|
||||
id: id as string,
|
||||
category: "permanent",
|
||||
});
|
||||
|
||||
if (responseData.success) {
|
||||
setData({
|
||||
totalPencairan: responseData.data.totalPencairan,
|
||||
akumulasiPencairan: responseData.data.akumulasiPencairan,
|
||||
});
|
||||
}
|
||||
|
||||
const responseList = await apiDonationDisbursementOfFundsListById({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
if (responseList.success) {
|
||||
setListData(responseList.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadData(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper>
|
||||
@@ -20,47 +74,50 @@ export default function DonationFundDisbursement() {
|
||||
<Grid>
|
||||
<Grid.Col span={6}>
|
||||
<TextCustom bold color="yellow">
|
||||
Rp. 0
|
||||
Rp. {formatCurrencyDisplay(data?.totalPencairan)}
|
||||
</TextCustom>
|
||||
<TextCustom size="small">Total Pencairan Dana</TextCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={6}>
|
||||
<TextCustom bold color="yellow">
|
||||
0 kali
|
||||
{data?.akumulasiPencairan} kali
|
||||
</TextCustom>
|
||||
<TextCustom size="small">Akumulasi Pencairan</TextCustom>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</BaseBox>
|
||||
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<BaseBox key={index}>
|
||||
<StackCustom>
|
||||
<Grid>
|
||||
<Grid.Col span={8}>
|
||||
<TextCustom bold>Pencairan ke - {index + 1}</TextCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={4} style={{ alignItems: "flex-end" }}>
|
||||
<TextCustom>{dayjs().format("DD MMM YYYY")}</TextCustom>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<TextCustom>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
Nesciunt dolor ad sit? Eaque rem nihil natus, id, esse possimus
|
||||
perferendis provident velit illo consectetur distinctio ab
|
||||
accusantium quis earum omnis!
|
||||
</TextCustom>
|
||||
<ButtonCenteredOnly
|
||||
onPress={() => {
|
||||
router.navigate(`/(application)/(file)/${id}`);
|
||||
}}
|
||||
icon="file-text"
|
||||
>
|
||||
Bukti Transaksi
|
||||
</ButtonCenteredOnly>
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
))}
|
||||
{loadData ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(listData) ? (
|
||||
<TextCustom align="center" color="gray">
|
||||
Belum ada data
|
||||
</TextCustom>
|
||||
) : (
|
||||
listData?.map((item, index) => (
|
||||
<BaseBox key={index}>
|
||||
<StackCustom>
|
||||
<Grid>
|
||||
<Grid.Col span={8}>
|
||||
<TextCustom bold>{item?.title}</TextCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={4} style={{ alignItems: "flex-end" }}>
|
||||
<TextCustom>{dayjs(item?.createdAt).format("DD MMM YYYY")}</TextCustom>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<TextCustom>{item?.deskripsi}</TextCustom>
|
||||
<ButtonCenteredOnly
|
||||
onPress={() => {
|
||||
router.navigate(`/(application)/(image)/preview-image/${item?.imageId}`);
|
||||
}}
|
||||
icon="file-text"
|
||||
>
|
||||
Bukti Transaksi
|
||||
</ButtonCenteredOnly>
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
))
|
||||
)}
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -16,20 +16,19 @@ import Donation_ComponentInfoFundrising from "@/screens/Donation/ComponentInfoFu
|
||||
import Donation_ComponentStoryFunrising from "@/screens/Donation/ComponentStoryFunrising";
|
||||
import Donation_ProgressSection from "@/screens/Donation/ProgressSection";
|
||||
import { apiDonationGetOne } from "@/service/api-client/api-donation";
|
||||
import { countDownAndCondition } from "@/utils/countDownAndCondition";
|
||||
import {
|
||||
router,
|
||||
Stack,
|
||||
useFocusEffect,
|
||||
useLocalSearchParams,
|
||||
} from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
export default function DonasiDetailBeranda() {
|
||||
const { user } = useAuth();
|
||||
const { id } = useLocalSearchParams();
|
||||
console.log("ID ", id);
|
||||
const [openDrawer, setOpenDrawer] = useState(false);
|
||||
|
||||
const [data, setData] = useState<any>();
|
||||
|
||||
useFocusEffect(
|
||||
@@ -45,21 +44,41 @@ export default function DonasiDetailBeranda() {
|
||||
category: "permanent",
|
||||
});
|
||||
|
||||
console.log("[RES GET ONE]", JSON.stringify(response.data, null, 2));
|
||||
|
||||
setData(response.data);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const [value, setValue] = useState({
|
||||
sisa: 0,
|
||||
reminder: false,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
updateCountDown();
|
||||
}, [data]);
|
||||
|
||||
const updateCountDown = () => {
|
||||
const countDown = countDownAndCondition({
|
||||
duration: data?.DonasiMaster_Durasi?.name,
|
||||
publishTime: data?.publishTime,
|
||||
});
|
||||
|
||||
setValue({
|
||||
sisa: countDown.durationDay,
|
||||
reminder: countDown.reminder,
|
||||
});
|
||||
};
|
||||
|
||||
const buttonSection = (
|
||||
<>
|
||||
<BoxButtonOnFooter>
|
||||
<ButtonCustom
|
||||
disabled={value?.reminder}
|
||||
onPress={() => router.navigate(`/donation/${id}/(transaction-flow)`)}
|
||||
>
|
||||
Donasi
|
||||
{value?.reminder ? "Waktu berakhir" : "Donasi"}
|
||||
</ButtonCustom>
|
||||
</BoxButtonOnFooter>
|
||||
</>
|
||||
@@ -80,8 +99,10 @@ export default function DonasiDetailBeranda() {
|
||||
<ViewWrapper footerComponent={buttonSection}>
|
||||
<StackCustom>
|
||||
<Donation_ComponentBoxDetailData
|
||||
sisaHari={value.sisa}
|
||||
reminder={value.reminder}
|
||||
data={data}
|
||||
bottomSection={<Donation_ProgressSection id={id as string} />}
|
||||
bottomSection={<Donation_ProgressSection id={id as string} progres={Number(data?.progres) || 0} />}
|
||||
/>
|
||||
<Donation_ComponentInfoFundrising dataAuthor={data?.Author} />
|
||||
<Donation_ComponentStoryFunrising
|
||||
|
||||
@@ -1,46 +1,93 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
BaseBox,
|
||||
Grid,
|
||||
LoaderCustom,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { apiAdminDonationListOfDonaturById } from "@/service/api-admin/api-admin-donation";
|
||||
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
|
||||
import { FontAwesome6 } from "@expo/vector-icons";
|
||||
import dayjs from "dayjs";
|
||||
import { useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export default function Donation_ListOfDonatur() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [listData, setListData] = useState<any[] | null>(null);
|
||||
const [loadData, setLoadData] = useState(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadData(true);
|
||||
const response = await apiAdminDonationListOfDonaturById({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
|
||||
if (response.success) {
|
||||
setListData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadData(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper>
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<BaseBox key={index}>
|
||||
<Grid>
|
||||
<Grid.Col
|
||||
span={3}
|
||||
style={{ alignItems: "center", justifyContent: "center" }}
|
||||
>
|
||||
<FontAwesome6
|
||||
name="face-smile-wink"
|
||||
size={50}
|
||||
style={{ color: MainColor.yellow }}
|
||||
/>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={9}>
|
||||
<StackCustom gap={"xs"}>
|
||||
{loadData ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(listData) ? (
|
||||
<TextCustom bold align="center">
|
||||
Belum ada donatur
|
||||
</TextCustom>
|
||||
) : (
|
||||
listData?.map((item: any, index: number) => (
|
||||
<BaseBox key={index}>
|
||||
<Grid>
|
||||
<Grid.Col
|
||||
span={3}
|
||||
style={{ alignItems: "center", justifyContent: "center" }}
|
||||
>
|
||||
<FontAwesome6
|
||||
name="face-smile-wink"
|
||||
size={50}
|
||||
style={{ color: MainColor.yellow }}
|
||||
/>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={9}>
|
||||
<TextCustom bold size="large">
|
||||
Username
|
||||
{item?.Author?.username || "-"}
|
||||
</TextCustom>
|
||||
<TextCustom>Berdonas sebesar </TextCustom>
|
||||
<TextCustom bold size="large" color="yellow">
|
||||
Rp. 100.000
|
||||
</TextCustom>
|
||||
<TextCustom>{dayjs().format("DD MMM YYYY")}</TextCustom>
|
||||
</StackCustom>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</BaseBox>
|
||||
))}
|
||||
<Spacing/>
|
||||
<StackCustom gap={"xs"}>
|
||||
<TextCustom size={"small"}>Berdonas sebesar </TextCustom>
|
||||
<TextCustom bold size="large" color="yellow">
|
||||
Rp. {formatCurrencyDisplay(item?.nominal)}
|
||||
</TextCustom>
|
||||
<TextCustom>
|
||||
{dayjs(item?.createdAt).format("DD MMM YYYY, HH:mm")}
|
||||
</TextCustom>
|
||||
</StackCustom>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</BaseBox>
|
||||
))
|
||||
)}
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -44,6 +44,8 @@ export default function EventBeranda() {
|
||||
<TextCustom align="center">Belum ada event</TextCustom>
|
||||
) : (
|
||||
listData.map((item: any, index) => (
|
||||
|
||||
|
||||
<Event_BoxPublishSection
|
||||
key={index}
|
||||
href={`/event/${item.id}/publish`}
|
||||
|
||||
554
app/(application)/(user)/event/[id]/confirmation.tsx
Normal file
554
app/(application)/(user)/event/[id]/confirmation.tsx
Normal file
@@ -0,0 +1,554 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
BaseBox,
|
||||
ButtonCustom,
|
||||
CenterCustom,
|
||||
LoaderCustom,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import { AccentColor, MainColor } from "@/constants/color-palet";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import {
|
||||
apiEventConfirmationAction,
|
||||
apiEventGetConfirmation,
|
||||
apiEventJoin,
|
||||
} from "@/service/api-client/api-event";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import dayjs from "dayjs";
|
||||
import isBetween from "dayjs/plugin/isBetween";
|
||||
import {
|
||||
Redirect,
|
||||
router,
|
||||
Stack,
|
||||
useFocusEffect,
|
||||
useLocalSearchParams,
|
||||
} from "expo-router";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
// Extend Day.js dengan plugin isBetween
|
||||
dayjs.extend(isBetween);
|
||||
|
||||
interface DataEvent {
|
||||
id: string;
|
||||
title: string;
|
||||
tanggal: Date;
|
||||
tanggalSelesai: Date;
|
||||
lokasi: string;
|
||||
Author: {
|
||||
id: string;
|
||||
username: string;
|
||||
Profile: {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export default function UserEventConfirmation() {
|
||||
const { token } = useAuth();
|
||||
const { id, userId: authorId } = useLocalSearchParams();
|
||||
const { user } = useAuth();
|
||||
const [data, setData] = useState<DataEvent | null>(null);
|
||||
const [peserta, setPeserta] = useState<boolean | null>(null);
|
||||
const [konfirmasi, setKonfirmasi] = useState<boolean | null>(null);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
checkTokenAndDataParticipants() || console.log("Token is null");
|
||||
}, [token, id, user?.id])
|
||||
);
|
||||
|
||||
const checkTokenAndDataParticipants = async () => {
|
||||
if (!token) {
|
||||
return <Redirect href={`/`} />;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await apiEventGetConfirmation({
|
||||
id: id as string,
|
||||
userId: user?.id as string,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data?.dataEvent);
|
||||
setPeserta(response.data?.peserta);
|
||||
setKonfirmasi(response.data?.kehadiran);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR CONFIRMATION]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handlerReturn = () => {
|
||||
const now = dayjs(); // asumsi: UTC, sesuai dengan API
|
||||
|
||||
// --- [1] Loading & Data tidak ditemukan ---
|
||||
if (data === undefined || data === null) {
|
||||
if (peserta === null && konfirmasi === null) {
|
||||
return <LoaderCustom />;
|
||||
}
|
||||
return (
|
||||
<BaseBox>
|
||||
<TextCustom bold align="center" size={"large"}>
|
||||
Data Tidak Ditemukan
|
||||
</TextCustom>
|
||||
<BackToOtherPath path="home" />
|
||||
</BaseBox>
|
||||
);
|
||||
}
|
||||
|
||||
// --- [2] Ambil waktu event dari `data` ---
|
||||
const eventStart = dayjs(data.tanggal);
|
||||
const eventEnd = dayjs(data.tanggalSelesai);
|
||||
|
||||
// --- [3] Definisikan jendela konfirmasi: 1 jam sebelum mulai → 1 jam setelah selesai ---
|
||||
const confirmationStart = eventStart.subtract(1, "hour");
|
||||
const confirmationEnd = eventEnd.add(1, "hour");
|
||||
const isWithinConfirmationWindow = now.isBetween(
|
||||
confirmationStart,
|
||||
confirmationEnd,
|
||||
null,
|
||||
"[]"
|
||||
);
|
||||
|
||||
// --- [4] Status waktu event (untuk pesan UI) ---
|
||||
const isBeforeEvent = now.isBefore(eventStart);
|
||||
const isAfterEvent = now.isAfter(eventEnd);
|
||||
const isDuringEvent = !isBeforeEvent && !isAfterEvent;
|
||||
|
||||
// --- [5] Handle berdasarkan waktu dan status peserta/konfirmasi ---
|
||||
|
||||
// 🟢 Acara sudah selesai
|
||||
if (isAfterEvent) {
|
||||
if (peserta === false) {
|
||||
return (
|
||||
<TamplateBox data={data}>
|
||||
<TamplateText text="Event telah selesai, sehingga konfirmasi kehadiran sudah tidak dapat dilakukan. Terima kasih atas perhatian dan minat Anda. Kami berharap dapat bertemu di acara kami berikutnya." />
|
||||
<BackToOtherPath
|
||||
path="event"
|
||||
id={data.id}
|
||||
isAfterEvent={isAfterEvent}
|
||||
/>
|
||||
</TamplateBox>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<TamplateBox data={data}>
|
||||
<TamplateText
|
||||
text={`Event telah selesai, anda terdaftar sebagai peserta dan ${
|
||||
konfirmasi
|
||||
? "Anda telah mengonfirmasi kehadiran."
|
||||
: "Anda tidak mengonfirmasi kehadiran."
|
||||
} Terima kasih atas perhatian dan minat Anda. Kami berharap dapat bertemu di acara kami berikutnya.`}
|
||||
/>
|
||||
<BackToOtherPath
|
||||
path="event"
|
||||
id={data.id}
|
||||
isAfterEvent={isAfterEvent}
|
||||
/>
|
||||
</TamplateBox>
|
||||
);
|
||||
}
|
||||
|
||||
// 🔵 Acara belum mulai & belum terdaftar
|
||||
if (isBeforeEvent) {
|
||||
if (peserta === false) {
|
||||
return (
|
||||
<NotStarted_And_UserNotParticipan
|
||||
id={data.id}
|
||||
userId={user?.id as string}
|
||||
data={data}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Peserta sudah daftar → cek apakah sudah boleh konfirmasi
|
||||
if (isWithinConfirmationWindow && peserta === true) {
|
||||
if (konfirmasi === false) {
|
||||
return (
|
||||
<UserParticipan_And_DuringEvent
|
||||
id={data.id}
|
||||
userId={user?.id as string}
|
||||
data={data}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<TamplateBox data={data}>
|
||||
<TamplateText text="Terimakasih telah mengonfirmasi kehadiran. Silahkan lihat peserta lain pada halaman event atau kembali ke halaman home. Selamat menikmati acara dan selamat berpartisipasi." />
|
||||
<BackToOtherPath
|
||||
path="event"
|
||||
id={data.id}
|
||||
isAfterEvent={isAfterEvent}
|
||||
/>
|
||||
</TamplateBox>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<TamplateBox data={data}>
|
||||
<TamplateText text="Anda telah terdaftar sebagai peserta pada Event ini. Konfirmasi kehadiran dibuka 1 jam sebelum acara dimulai." />
|
||||
<BackToOtherPath
|
||||
path="event"
|
||||
id={data.id}
|
||||
isAfterEvent={isAfterEvent}
|
||||
/>
|
||||
</TamplateBox>
|
||||
);
|
||||
}
|
||||
|
||||
// 🟡 Acara sedang berlangsung & belum terdaftar
|
||||
if (isDuringEvent) {
|
||||
if (peserta === false) {
|
||||
return (
|
||||
<UserNotParticipan_And_DuringEvent
|
||||
id={data.id}
|
||||
userId={user?.id as string}
|
||||
data={data}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (peserta === true) {
|
||||
if (isWithinConfirmationWindow) {
|
||||
if (konfirmasi === false) {
|
||||
return (
|
||||
<TamplateBox data={data}>
|
||||
<TamplateText text="Konfirmasi Kehadiran" />
|
||||
</TamplateBox>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<TamplateBox data={data}>
|
||||
<TamplateText text="Anda telah mengonfirmasi kehadiran dalam event ini. Terima kasih dan selamat menikmati acara. Have fun!" />
|
||||
<BackToOtherPath
|
||||
path="event"
|
||||
id={data.id}
|
||||
isAfterEvent={isAfterEvent}
|
||||
/>
|
||||
</TamplateBox>
|
||||
);
|
||||
}
|
||||
|
||||
// Ini sangat jarang terjadi selama event berlangsung, tapi aman
|
||||
return (
|
||||
<TamplateBox data={data}>
|
||||
<TamplateText text="Konfirmasi kehadiran tidak tersedia saat ini." />
|
||||
<BackToOtherPath path="home" />
|
||||
</TamplateBox>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 🛑 Fallback aman
|
||||
return (
|
||||
<BaseBox>
|
||||
<StackCustom>
|
||||
<TamplateText text="Terjadi kesalahan tak terduga pada logika waktu." />
|
||||
<BackToOtherPath path="home" />
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
title: "Konfirmasi Event",
|
||||
headerLeft: () => (
|
||||
<Ionicons
|
||||
name="arrow-back"
|
||||
size={20}
|
||||
color={MainColor.yellow}
|
||||
onPress={() =>
|
||||
router.navigate("/(application)/(user)/event/create")
|
||||
}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<ViewWrapper>{handlerReturn()}</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const TamplateBox = ({
|
||||
data,
|
||||
children,
|
||||
}: {
|
||||
data: DataEvent;
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<CenterCustom>
|
||||
<BaseBox>
|
||||
<StackCustom gap={"lg"}>
|
||||
<StackCustom gap={"sm"}>
|
||||
<TextCustom bold align="center" size={"large"}>
|
||||
{data?.title}
|
||||
</TextCustom>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "center",
|
||||
// backgroundColor: AccentColor.blue,
|
||||
// borderColor: AccentColor.blue,
|
||||
// borderWidth: 1,
|
||||
// borderRadius: 4,
|
||||
// padding: 3
|
||||
}}
|
||||
>
|
||||
<TextCustom align="center" size="small" bold>
|
||||
{dayjs(data?.tanggal).format("DD MMM YYYY: HH:mm")}
|
||||
</TextCustom>
|
||||
<TextCustom align="center" size="small" bold>
|
||||
{" "}
|
||||
-{" "}
|
||||
</TextCustom>
|
||||
<TextCustom align="center" size="small" bold>
|
||||
{dayjs(data?.tanggalSelesai).format("DD MMM YYYY: HH:mm")}
|
||||
</TextCustom>
|
||||
</View>
|
||||
</StackCustom>
|
||||
|
||||
{children}
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
</CenterCustom>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const TamplateText = ({ text }: { text: React.ReactNode }) => {
|
||||
return (
|
||||
<>
|
||||
<TextCustom align="center">{text}</TextCustom>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
type BackToOtherPathProps =
|
||||
| { path: "home" | "beranda-event"; id?: never; isAfterEvent?: never }
|
||||
| { path: "event"; id: string; isAfterEvent: boolean };
|
||||
|
||||
const BackToOtherPath = ({ path, id, isAfterEvent }: BackToOtherPathProps) => {
|
||||
return (
|
||||
<>
|
||||
{path === "home" ? (
|
||||
<ButtonCustom
|
||||
onPress={() => {
|
||||
router.replace("/(application)/home");
|
||||
}}
|
||||
>
|
||||
Home
|
||||
</ButtonCustom>
|
||||
) : (
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
gap: 10,
|
||||
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<ButtonCustom
|
||||
onPress={() => {
|
||||
router.replace("/(application)/home");
|
||||
}}
|
||||
>
|
||||
Home
|
||||
</ButtonCustom>
|
||||
<ButtonCustom
|
||||
onPress={() => {
|
||||
if (path === "event") {
|
||||
if (isAfterEvent) {
|
||||
router.push(`/(application)/(user)/event/${id}/history`);
|
||||
} else {
|
||||
router.push(`/(application)/(user)/event/${id}/publish`);
|
||||
}
|
||||
} else if (path === "beranda-event") {
|
||||
router.push(`/(application)/(user)/event`);
|
||||
} else {
|
||||
console.log("[PATH]", path);
|
||||
}
|
||||
}}
|
||||
>
|
||||
Lihat {path === "event" ? "Event" : "Beranda Event"}
|
||||
</ButtonCustom>
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
// 🔵 Acara belum mulai & belum terdaftar
|
||||
const NotStarted_And_UserNotParticipan = ({
|
||||
id,
|
||||
userId,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
userId: string;
|
||||
data: DataEvent;
|
||||
}) => {
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
const handlerJoinEvent = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
const response = await apiEventJoin({
|
||||
id: id as string,
|
||||
userId: userId as string,
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Anda gagal join",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Anda berhasil join",
|
||||
});
|
||||
router.navigate(`/(application)/(user)/event/${id}/publish`);
|
||||
} catch (error) {
|
||||
console.log("[ERROR JOIN EVENT]", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<TamplateBox data={data}>
|
||||
<TamplateText text="Anda belum terdaftar sebagai peserta & Event belum dimulai. Silahkan daftarkan diri anda terlebih dahulu" />
|
||||
<ButtonCustom onPress={handlerJoinEvent} isLoading={isLoading}>
|
||||
Join
|
||||
</ButtonCustom>
|
||||
</TamplateBox>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
// 🟡 ZONA ACARA BERLANGSUNG
|
||||
// Acara sedang berlangsung & belum terdaftar & user harus join dan konfirmasi
|
||||
const UserNotParticipan_And_DuringEvent = ({
|
||||
id,
|
||||
userId,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
userId: string;
|
||||
data: DataEvent;
|
||||
}) => {
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
const handlerSubmit = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
const response = await apiEventConfirmationAction({
|
||||
id: id as string,
|
||||
userId: userId as string,
|
||||
category: "join_and_confirm",
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Anda gagal join & konfirmasi",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Anda berhasil join & konfirmasi",
|
||||
});
|
||||
router.navigate(`/(application)/(user)/event/${id}/publish`);
|
||||
} catch (error) {
|
||||
console.log("[ERROR JOIN & CONFIRMATION EVENT]", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<TamplateBox data={data}>
|
||||
<TamplateText text="Anda belum terdaftar sebagai peserta & Event sedang berlangsung. Silahkan daftarkan diri anda & Konfirmasi kehadiran" />
|
||||
|
||||
<ButtonCustom onPress={() => handlerSubmit()} isLoading={isLoading}>
|
||||
Join & Konfirmasi
|
||||
</ButtonCustom>
|
||||
</TamplateBox>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// 🟡 ZONA ACARA BERLANGSUN
|
||||
// User sudah terdaftar & Event sedang berlangsung & user harus konfirmasi
|
||||
const UserParticipan_And_DuringEvent = ({
|
||||
id,
|
||||
userId,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
userId: string;
|
||||
data: DataEvent;
|
||||
}) => {
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
const handlerSubmit = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
const response = await apiEventConfirmationAction({
|
||||
id: id as string,
|
||||
userId: userId as string,
|
||||
category: "confirmation",
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Anda gagal konfirmasi",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Anda berhasil konfirmasi",
|
||||
});
|
||||
router.navigate(`/(application)/(user)/event/${id}/publish`);
|
||||
} catch (error) {
|
||||
console.log("[ERROR JOIN & CONFIRMATION EVENT]", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<TamplateBox data={data}>
|
||||
<TamplateText text="Anda sudah terdaftar sebagai peserta & Event sedang berlangsung. Silahkan konfirmasi kehadiran" />
|
||||
|
||||
<ButtonCustom onPress={() => handlerSubmit()} isLoading={isLoading}>
|
||||
Konfirmasi
|
||||
</ButtonCustom>
|
||||
</TamplateBox>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -11,29 +11,30 @@ import {
|
||||
apiEventGetOne,
|
||||
apiEventListOfParticipants,
|
||||
} from "@/service/api-client/api-event";
|
||||
import { useLocalSearchParams } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import dayjs, { Dayjs } from "dayjs";
|
||||
import { useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
|
||||
export default function EventListOfParticipants() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [startDate, setStartDate] = useState();
|
||||
const [listData, setListData] = useState([]);
|
||||
const [isLoadData, setIsLoadData] = useState(false);
|
||||
const [startDate, setStartDate] = useState<Dayjs | undefined>();
|
||||
const [listData, setListData] = useState<any[] | null>(null);
|
||||
const [loadtData, setLoadData] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
handlerLoadData();
|
||||
}, [id]);
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
handlerLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const handlerLoadData = () => {
|
||||
try {
|
||||
setIsLoadData(true);
|
||||
onLoadData();
|
||||
onLoadList();
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setIsLoadData(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -41,7 +42,8 @@ export default function EventListOfParticipants() {
|
||||
try {
|
||||
const response = await apiEventGetOne({ id: id as string });
|
||||
if (response.success) {
|
||||
setStartDate(response.data.tanggal);
|
||||
const date = dayjs(response.data.tanggal);
|
||||
setStartDate(date);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
@@ -50,30 +52,36 @@ export default function EventListOfParticipants() {
|
||||
|
||||
const onLoadList = async () => {
|
||||
try {
|
||||
setLoadData(true);
|
||||
const response = await apiEventListOfParticipants({ id: id as string });
|
||||
|
||||
if (response.success) {
|
||||
setListData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadData(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ViewWrapper>
|
||||
{isLoadData ? (
|
||||
{loadtData && !listData ? (
|
||||
<LoaderCustom />
|
||||
) : listData.length === 0 ? (
|
||||
<TextCustom align="center">Belum ada peserta</TextCustom>
|
||||
) : _.isEmpty(listData) ? (
|
||||
<TextCustom align="center" color="gray">
|
||||
Belum ada peserta
|
||||
</TextCustom>
|
||||
) : (
|
||||
listData.map((item: any, index: number) => (
|
||||
listData?.map((item: any, index: number) => (
|
||||
<BaseBox key={index}>
|
||||
<AvatarUsernameAndOtherComponent
|
||||
avatar={item?.User?.Profile?.imageId}
|
||||
name={item?.User?.username}
|
||||
avatarHref={`/profile/${item?.User?.Profile?.id}`}
|
||||
rightComponent={
|
||||
new Date().getTime() > new Date(startDate as any).getTime() ? (
|
||||
startDate && startDate.subtract(1, "hour").diff(dayjs()) < 0 ? (
|
||||
<View
|
||||
style={{
|
||||
justifyContent: "flex-end",
|
||||
|
||||
@@ -55,6 +55,8 @@ export default function EventDetailPublish() {
|
||||
userId: user?.id as string,
|
||||
});
|
||||
|
||||
console.log("[RES CHECK PARTICIPANTS]", responseCheckParticipants);
|
||||
|
||||
if (
|
||||
responseCheckParticipants.success &&
|
||||
responseCheckParticipants.data
|
||||
@@ -69,6 +71,8 @@ export default function EventDetailPublish() {
|
||||
}
|
||||
}
|
||||
|
||||
console.log("[participans]", isParticipant);
|
||||
|
||||
const handlePress = (item: IMenuDrawerItem) => {
|
||||
console.log("PATH ", item.path);
|
||||
router.navigate(item.path as any);
|
||||
|
||||
@@ -191,7 +191,7 @@ export default function EventCreate() {
|
||||
placeholder="Masukkan deskripsi event"
|
||||
required
|
||||
showCount
|
||||
maxLength={100}
|
||||
maxLength={1000}
|
||||
onChangeText={(value: any) =>
|
||||
setData({ ...data, deskripsi: value })
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
} from "@/components";
|
||||
import { IconEdit } from "@/components/_Icon";
|
||||
import { IMenuDrawerItem } from "@/components/_Interface/types";
|
||||
import ReportBox from "@/components/Box/ReportBox";
|
||||
import Job_BoxDetailSection from "@/screens/Job/BoxDetailSection";
|
||||
import Job_ButtonStatusSection from "@/screens/Job/ButtonStatusSection";
|
||||
import { apiJobGetOne } from "@/service/api-client/api-job";
|
||||
@@ -70,7 +71,13 @@ export default function JobDetailStatus() {
|
||||
<LoaderCustom />
|
||||
) : (
|
||||
<>
|
||||
<StackCustom>
|
||||
<StackCustom gap={"xs"}>
|
||||
{data &&
|
||||
data?.catatan &&
|
||||
(status === "draft" || status === "rejected") && (
|
||||
<ReportBox text={data?.catatan} />
|
||||
)}
|
||||
|
||||
<Job_BoxDetailSection data={data} />
|
||||
<Job_ButtonStatusSection
|
||||
id={id as string}
|
||||
|
||||
@@ -8,11 +8,13 @@ import {
|
||||
LoaderCustom,
|
||||
MenuDrawerDynamicGrid,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import { IconArchive, IconContribution, IconEdit } from "@/components/_Icon";
|
||||
import { IMenuDrawerItem } from "@/components/_Interface/types";
|
||||
import ReportBox from "@/components/Box/ReportBox";
|
||||
import Voting_BoxDetailHasilVotingSection from "@/screens/Voting/BoxDetailHasilVotingSection";
|
||||
import { Voting_BoxDetailSection } from "@/screens/Voting/BoxDetailSection";
|
||||
import Voting_ButtonStatusSection from "@/screens/Voting/ButtonStatusSection";
|
||||
@@ -49,6 +51,8 @@ export default function VotingDetailStatus() {
|
||||
setLoadingGetData(true);
|
||||
const response = await apiVotingGetOne({ id: id as string });
|
||||
|
||||
console.log("[DATA BY ID]", JSON.stringify(response, null, 2));
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
@@ -127,6 +131,13 @@ export default function VotingDetailStatus() {
|
||||
</BaseBox>
|
||||
)}
|
||||
<Spacing height={0} />
|
||||
|
||||
{data &&
|
||||
data?.catatan &&
|
||||
(status === "draft" || status === "rejected") && (
|
||||
<ReportBox text={data?.catatan} />
|
||||
)}
|
||||
|
||||
<Voting_BoxDetailSection data={data as any} />
|
||||
{status === "publish" ? (
|
||||
<Voting_BoxDetailHasilVotingSection
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { apiAdminCollaborationGetById } from "@/service/api-admin/api-admin-collaboration";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
@@ -28,7 +29,7 @@ export default function AdminCollaborationPublish() {
|
||||
try {
|
||||
const response = await apiAdminCollaborationGetById({
|
||||
id: id as string,
|
||||
category: status as "publish" | "reject" | "group",
|
||||
category: status as any,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
@@ -39,7 +40,7 @@ export default function AdminCollaborationPublish() {
|
||||
}
|
||||
};
|
||||
|
||||
const bottomFooter = (
|
||||
const bottomFooter = status === "publish" && (
|
||||
<BoxButtonOnFooter>
|
||||
<ButtonCustom
|
||||
backgroundColor={MainColor.red}
|
||||
@@ -76,6 +77,17 @@ export default function AdminCollaborationPublish() {
|
||||
))}
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
|
||||
{data?.report && (
|
||||
<BaseBox>
|
||||
<GridTwoView
|
||||
spanLeft={4}
|
||||
spanRight={8}
|
||||
leftIcon={<TextCustom bold>Catatan report</TextCustom>}
|
||||
rightIcon={<TextCustom>{data?.report}</TextCustom>}
|
||||
/>
|
||||
</BaseBox>
|
||||
)}
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
BaseBox,
|
||||
Grid,
|
||||
@@ -6,23 +7,45 @@ import {
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import { useLocalSearchParams } from "expo-router";
|
||||
import { apiAdminCollaborationGetById } from "@/service/api-admin/api-admin-collaboration";
|
||||
import { useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export default function AdminCollaborationGroup() {
|
||||
const { id } = useLocalSearchParams();
|
||||
console.log("params:", id);
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiAdminCollaborationGetById({
|
||||
id: id as string,
|
||||
category: "group",
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper
|
||||
headerComponent={
|
||||
<AdminBackButtonAntTitle title={`Detail Group ${id}`} />
|
||||
}
|
||||
headerComponent={<AdminBackButtonAntTitle title={`Detail Group`} />}
|
||||
>
|
||||
<StackCustom gap={"xs"}>
|
||||
<BaseBox>
|
||||
<StackCustom>
|
||||
{listData.map((item, i) => (
|
||||
<Grid key={i}>
|
||||
{listData(data).map((item: any, index: number) => (
|
||||
<Grid key={index}>
|
||||
<Grid.Col
|
||||
span={4}
|
||||
style={{ justifyContent: "center", paddingRight: 10 }}
|
||||
@@ -40,21 +63,36 @@ export default function AdminCollaborationGroup() {
|
||||
<StackCustom>
|
||||
<TextCustom align="center">Anggota</TextCustom>
|
||||
|
||||
{Array.from({ length: 10 }).map((_, i) => (
|
||||
<Grid key={i}>
|
||||
<Grid.Col
|
||||
span={4}
|
||||
style={{ justifyContent: "center", paddingRight: 10 }}
|
||||
>
|
||||
<TextCustom bold>Username</TextCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={8} style={{ justifyContent: "center" }}>
|
||||
<TextCustom>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
</TextCustom>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
))}
|
||||
{data?.ProjectCollaboration_AnggotaRoomChat?.map(
|
||||
(item: any, index: number) => (
|
||||
<StackCustom key={index} gap={0}>
|
||||
<Grid>
|
||||
<Grid.Col
|
||||
span={4}
|
||||
style={{ justifyContent: "center", paddingRight: 10 }}
|
||||
>
|
||||
<TextCustom bold>Nama</TextCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={8} style={{ justifyContent: "center" }}>
|
||||
<TextCustom>
|
||||
{item?.User?.Profile?.name || "-"}
|
||||
</TextCustom>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.Col
|
||||
span={4}
|
||||
style={{ justifyContent: "center", paddingRight: 10 }}
|
||||
>
|
||||
<TextCustom bold>Username</TextCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={8} style={{ justifyContent: "center" }}>
|
||||
<TextCustom>{item?.User?.username || "-"}</TextCustom>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</StackCustom>
|
||||
)
|
||||
)}
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
</StackCustom>
|
||||
@@ -63,35 +101,35 @@ export default function AdminCollaborationGroup() {
|
||||
);
|
||||
}
|
||||
|
||||
const listData = [
|
||||
const listData = (data: any) => [
|
||||
{
|
||||
label: "Admin Group",
|
||||
value: "Bagas Banuna",
|
||||
value: data?.ProjectCollaboration?.Author?.username || "-",
|
||||
},
|
||||
{
|
||||
label: "Nama Group",
|
||||
value: "Lorem ipsum dolor sit amet consectetur adipisicing elit.",
|
||||
value: data?.name || "-",
|
||||
},
|
||||
{
|
||||
label: "Industri",
|
||||
value: "Kesehatan",
|
||||
value:
|
||||
data?.ProjectCollaboration?.ProjectCollaborationMaster_Industri?.name ||
|
||||
"-",
|
||||
},
|
||||
{
|
||||
label: "Jumlah Partisipan ",
|
||||
value: "0",
|
||||
value: data?.ProjectCollaboration_AnggotaRoomChat?.length || "-",
|
||||
},
|
||||
{
|
||||
label: "Lokasi",
|
||||
value: "Kuta Selatan, Bali",
|
||||
value: data?.ProjectCollaboration?.lokasi || "-",
|
||||
},
|
||||
{
|
||||
label: "Tujuan Proyek",
|
||||
value:
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||
value: data?.ProjectCollaboration?.purpose || "-",
|
||||
},
|
||||
{
|
||||
label: "Keuntungan",
|
||||
value:
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||
value: data?.ProjectCollaboration?.benefit || "-",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -6,12 +6,41 @@ import {
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
|
||||
import { apiAdminCollaborationReject } from "@/service/api-admin/api-admin-collaboration";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminCollaborationRejectInput() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [value, setValue] = useState(id as string);
|
||||
const [value, setValue] = useState("");
|
||||
|
||||
const handlerReject = async () => {
|
||||
console.log("value:", value);
|
||||
// router.replace(`/admin/job/reject/status`);
|
||||
try {
|
||||
const response = await apiAdminCollaborationReject({
|
||||
id: id as string,
|
||||
data: value,
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Report gagal",
|
||||
});
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Report berhasil",
|
||||
});
|
||||
|
||||
router.back();
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const buttonSubmit = (
|
||||
<BoxButtonOnFooter>
|
||||
@@ -23,12 +52,8 @@ export default function AdminCollaborationRejectInput() {
|
||||
message: "Apakah anda yakin ingin menolak data ini?",
|
||||
textLeft: "Batal",
|
||||
textRight: "Ya",
|
||||
onPressLeft: () => {
|
||||
router.back();
|
||||
},
|
||||
onPressRight: () => {
|
||||
console.log("value:", value);
|
||||
// router.replace(`/admin/job/reject/status`);
|
||||
handlerReject();
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -40,7 +65,9 @@ export default function AdminCollaborationRejectInput() {
|
||||
<>
|
||||
<ViewWrapper
|
||||
footerComponent={buttonSubmit}
|
||||
headerComponent={<AdminBackButtonAntTitle title="Penolakan Collaboration" />}
|
||||
headerComponent={
|
||||
<AdminBackButtonAntTitle title="Penolakan Collaboration" />
|
||||
}
|
||||
>
|
||||
<TextAreaCustom
|
||||
value={value}
|
||||
|
||||
@@ -1,67 +1,101 @@
|
||||
import {
|
||||
ActionIcon,
|
||||
BaseBox,
|
||||
Spacing,
|
||||
LoaderCustom,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
ViewWrapper
|
||||
} from "@/components";
|
||||
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
|
||||
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
|
||||
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
|
||||
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import { apiAdminCollaboration } from "@/service/api-admin/api-admin-collaboration";
|
||||
import { Octicons } from "@expo/vector-icons";
|
||||
import { router } from "expo-router";
|
||||
import { router, useFocusEffect } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import { Divider } from "react-native-paper";
|
||||
|
||||
export default function AdminCollaborationGroup() {
|
||||
const [list, setList] = useState<any[] | null>(null);
|
||||
const [loadList, setLoadList] = useState(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
handlerLoadList();
|
||||
}, [])
|
||||
);
|
||||
|
||||
const handlerLoadList = async () => {
|
||||
try {
|
||||
setLoadList(true);
|
||||
const response = await apiAdminCollaboration({
|
||||
category: "group",
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setList(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadList(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper headerComponent={<AdminTitlePage title="Collaboration" />}>
|
||||
<StackCustom gap={"xs"}>
|
||||
<StackCustom>
|
||||
<AdminComp_BoxTitle title="Group" />
|
||||
<BaseBox>
|
||||
<>
|
||||
<AdminTitleTable
|
||||
title1="Aksi"
|
||||
title2="Admin Group"
|
||||
title3="Nama Group"
|
||||
title2="Jumlah peserta"
|
||||
title3="Nama group"
|
||||
/>
|
||||
<Spacing height={10} />
|
||||
<Divider />
|
||||
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<Octicons
|
||||
name="eye"
|
||||
size={ICON_SIZE_BUTTON}
|
||||
color="black"
|
||||
{loadList ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(list) ? (
|
||||
<TextCustom align="center" color="gray">
|
||||
Belum ada data
|
||||
</TextCustom>
|
||||
) : (
|
||||
list?.map((item: any, index: number) => (
|
||||
<View key={index}>
|
||||
<AdminTableValue
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<Octicons
|
||||
name="eye"
|
||||
size={ICON_SIZE_BUTTON}
|
||||
color="black"
|
||||
/>
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(`/admin/collaboration/${item.id}/group`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(`/admin/collaboration/${index}/group`);
|
||||
}}
|
||||
value2={
|
||||
<TextCustom truncate={1}>
|
||||
{item?.ProjectCollaboration_AnggotaRoomChat?.length ||
|
||||
"-"}
|
||||
</TextCustom>
|
||||
}
|
||||
value3={
|
||||
<TextCustom truncate={2}>{item?.name || "-"}</TextCustom>
|
||||
}
|
||||
/>
|
||||
}
|
||||
value2={
|
||||
<TextCustom truncate={1}>Username username </TextCustom>
|
||||
}
|
||||
value3={
|
||||
<TextCustom truncate={2}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
Blanditiis asperiores quidem deleniti architecto eaque et
|
||||
nostrum, ad consequuntur eveniet quisquam quae voluptatum
|
||||
ducimus! Dolorem nobis modi officia debitis, beatae
|
||||
mollitia.
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</BaseBox>
|
||||
</View>
|
||||
))
|
||||
)}
|
||||
</>
|
||||
</StackCustom>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
|
||||
@@ -9,7 +9,6 @@ import { useCallback, useState } from "react";
|
||||
|
||||
export default function AdminCollaboration() {
|
||||
const [list, setList] = useState<any | null>(null);
|
||||
const [loadList, setLoadList] = useState(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
@@ -19,20 +18,15 @@ export default function AdminCollaboration() {
|
||||
|
||||
const handlerLoadList = async () => {
|
||||
try {
|
||||
setLoadList(true);
|
||||
const response = await apiAdminCollaboration({
|
||||
category: "dashboard",
|
||||
});
|
||||
|
||||
console.log("[RESPONSE]", JSON.stringify(response, null, 2));
|
||||
|
||||
if (response.success) {
|
||||
setList(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadList(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -50,7 +44,6 @@ export default function AdminCollaboration() {
|
||||
}
|
||||
|
||||
const listData = (list: any) => {
|
||||
console.log("[LIST masuk]", JSON.stringify(list, null, 2));
|
||||
return [
|
||||
{
|
||||
label: "Publish",
|
||||
|
||||
@@ -15,6 +15,7 @@ import { Octicons } from "@expo/vector-icons";
|
||||
import { router, useFocusEffect } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import { Divider } from "react-native-paper";
|
||||
|
||||
export default function AdminCollaborationPublish() {
|
||||
@@ -43,10 +44,11 @@ export default function AdminCollaborationPublish() {
|
||||
setLoadList(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper headerComponent={<AdminTitlePage title="Collaboration" />}>
|
||||
<StackCustom gap={"xs"}>
|
||||
<StackCustom>
|
||||
<AdminComp_BoxTitle title="Publish" />
|
||||
|
||||
<AdminTitleTable
|
||||
@@ -60,36 +62,39 @@ export default function AdminCollaborationPublish() {
|
||||
{loadList ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(list) ? (
|
||||
<TextCustom>Belum ada data</TextCustom>
|
||||
<TextCustom align="center" color="gray">
|
||||
Belum ada data
|
||||
</TextCustom>
|
||||
) : (
|
||||
list?.map((item: any, index: number) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<Octicons
|
||||
name="eye"
|
||||
size={ICON_SIZE_BUTTON}
|
||||
color="black"
|
||||
/>
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(`/admin/collaboration/${item?.id}/publish`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={
|
||||
<TextCustom align="center" truncate={1}>
|
||||
{item?.Author?.username || "-"}{" "}
|
||||
</TextCustom>
|
||||
}
|
||||
value3={
|
||||
<TextCustom align="center" truncate={2}>
|
||||
{item?.title || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
<View key={index}>
|
||||
<AdminTableValue
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<Octicons
|
||||
name="eye"
|
||||
size={ICON_SIZE_BUTTON}
|
||||
color="black"
|
||||
/>
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(`/admin/collaboration/${item?.id}/publish`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={
|
||||
<TextCustom align="center" truncate={1}>
|
||||
{item?.Author?.username || "-"}{" "}
|
||||
</TextCustom>
|
||||
}
|
||||
value3={
|
||||
<TextCustom align="center" truncate={2}>
|
||||
{item?.title || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
))
|
||||
)}
|
||||
</StackCustom>
|
||||
|
||||
@@ -1,67 +1,99 @@
|
||||
import {
|
||||
ActionIcon,
|
||||
BaseBox,
|
||||
Spacing,
|
||||
LoaderCustom,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
ViewWrapper
|
||||
} from "@/components";
|
||||
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
|
||||
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
|
||||
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
|
||||
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import { apiAdminCollaboration } from "@/service/api-admin/api-admin-collaboration";
|
||||
import { Octicons } from "@expo/vector-icons";
|
||||
import { router } from "expo-router";
|
||||
import { router, useFocusEffect } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import { Divider } from "react-native-paper";
|
||||
|
||||
export default function AdminCollaborationReject() {
|
||||
const [list, setList] = useState<any[] | null>(null);
|
||||
const [loadList, setLoadList] = useState(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
handlerLoadList();
|
||||
}, [])
|
||||
);
|
||||
|
||||
const handlerLoadList = async () => {
|
||||
try {
|
||||
setLoadList(true);
|
||||
const response = await apiAdminCollaboration({
|
||||
category: "reject",
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setList(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadList(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper headerComponent={<AdminTitlePage title="Collaboration" />}>
|
||||
<StackCustom gap={"xs"}>
|
||||
<StackCustom>
|
||||
<AdminComp_BoxTitle title="Reject" />
|
||||
<BaseBox>
|
||||
<AdminTitleTable
|
||||
title1="Aksi"
|
||||
title2="Username"
|
||||
title3="Judul Proyek"
|
||||
/>
|
||||
<Spacing height={10} />
|
||||
<Divider />
|
||||
<AdminTitleTable
|
||||
title1="Aksi"
|
||||
title2="Username"
|
||||
title3="Judul Proyek"
|
||||
/>
|
||||
<Divider />
|
||||
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<Octicons
|
||||
name="eye"
|
||||
size={ICON_SIZE_BUTTON}
|
||||
color="black"
|
||||
/>
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(`/admin/collaboration/${index}/reject`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={
|
||||
<TextCustom truncate={1}>Username username </TextCustom>
|
||||
}
|
||||
value3={
|
||||
<TextCustom truncate={2}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
Blanditiis asperiores quidem deleniti architecto eaque et
|
||||
nostrum, ad consequuntur eveniet quisquam quae voluptatum
|
||||
ducimus! Dolorem nobis modi officia debitis, beatae
|
||||
mollitia.
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</BaseBox>
|
||||
{loadList ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(list) ? (
|
||||
<TextCustom>Belum ada data</TextCustom>
|
||||
) : (
|
||||
list?.map((item: any) => (
|
||||
<View key={item.id}>
|
||||
<AdminTableValue
|
||||
key={item?.id}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<Octicons
|
||||
name="eye"
|
||||
size={ICON_SIZE_BUTTON}
|
||||
color="black"
|
||||
/>
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(`/admin/collaboration/${item?.id}/reject`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={
|
||||
<TextCustom align="center" truncate={1}>
|
||||
{item?.Author?.username || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
value3={
|
||||
<TextCustom align="center" truncate={2}>
|
||||
{item?.title || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
))
|
||||
)}
|
||||
</StackCustom>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
ActionIcon,
|
||||
AlertDefaultSystem,
|
||||
@@ -18,97 +19,153 @@ import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButt
|
||||
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
|
||||
import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview";
|
||||
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import ReportBox from "@/components/Box/ReportBox";
|
||||
import { ICON_SIZE_BUTTON, TEXT_SIZE_LARGE } from "@/constants/constans-value";
|
||||
import AdminDonation_BoxOfDonationStory from "@/screens/Admin/Donation/BoxOfDonationStory";
|
||||
import { funUpdateStatusDonation } from "@/screens/Admin/Donation/funDonationUpdateStatus";
|
||||
import { apiAdminDonationDetailById } from "@/service/api-admin/api-admin-donation";
|
||||
import { colorBadgeStatus } from "@/utils/colorBadge";
|
||||
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import React from "react";
|
||||
import { View } from "react-native";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminDonationDetail() {
|
||||
const { id, status } = useLocalSearchParams();
|
||||
const [openDrawer, setOpenDrawer] = React.useState(false);
|
||||
|
||||
const colorBadge = () => {
|
||||
if (status === "publish") {
|
||||
return MainColor.green;
|
||||
} else if (status === "review") {
|
||||
return MainColor.orange;
|
||||
} else if (status === "reject") {
|
||||
return MainColor.red;
|
||||
} else {
|
||||
return MainColor.placeholder;
|
||||
const [data, setData] = React.useState<any | null>(null);
|
||||
const [countDonatur, setCountDonatur] = React.useState(0);
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiAdminDonationDetailById({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data.donasi);
|
||||
setCountDonatur(response.data.donatur);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
setData(null);
|
||||
}
|
||||
};
|
||||
|
||||
const listData = [
|
||||
{
|
||||
label: "Penggalang Dana",
|
||||
value: `Bagas Banuna ${id}`,
|
||||
value: (data && data?.Author?.username) || "-",
|
||||
},
|
||||
{
|
||||
label: "Judul",
|
||||
value: `Donasi Lorem ipsum dolor sit amet, consectetur adipisicing elit.`,
|
||||
value: (data && data?.title) || "-",
|
||||
},
|
||||
{
|
||||
label: "Status",
|
||||
value: (
|
||||
<BadgeCustom color={colorBadge()}>
|
||||
{_.startCase(status as string)}
|
||||
</BadgeCustom>
|
||||
),
|
||||
value:
|
||||
data && data?.DonasiMaster_Status?.name ? (
|
||||
<BadgeCustom
|
||||
color={colorBadgeStatus({
|
||||
status: data?.DonasiMaster_Status?.name,
|
||||
})}
|
||||
>
|
||||
{_.startCase(data?.DonasiMaster_Status?.name)}
|
||||
</BadgeCustom>
|
||||
) : (
|
||||
"-"
|
||||
),
|
||||
},
|
||||
{
|
||||
label: "Durasi",
|
||||
value: "30 Hari",
|
||||
value: (data && data?.DonasiMaster_Durasi?.name) + " hari" || "-",
|
||||
},
|
||||
{
|
||||
label: "Target Dana",
|
||||
value: "Rp 10.000.000",
|
||||
value:
|
||||
data && data?.target
|
||||
? `Rp. ${formatCurrencyDisplay(data?.target)}`
|
||||
: "-",
|
||||
},
|
||||
{
|
||||
label: "Kategori",
|
||||
value: "Kategori Donasi",
|
||||
value: (data && data?.DonasiMaster_Ketegori?.name) || "-",
|
||||
},
|
||||
// {
|
||||
// label: "Total Donatur",
|
||||
// value: "-",
|
||||
// },
|
||||
// {
|
||||
// label: "Progress",
|
||||
// value: "0 %",
|
||||
// },
|
||||
// {
|
||||
// label: "Dana Terkumpul",
|
||||
// value: "Rp 0",
|
||||
// },
|
||||
];
|
||||
|
||||
const listPencarianDana = [
|
||||
{
|
||||
label: "Total Dana Dicairkan",
|
||||
value: "Rp 0",
|
||||
value: `Rp ${(data && formatCurrencyDisplay(data?.totalPencairan)) || 0}`,
|
||||
},
|
||||
{
|
||||
label: "Sisa Dana",
|
||||
value: "Rp 0",
|
||||
label: "Sisa Dana Masuk",
|
||||
value: `Rp ${
|
||||
(data &&
|
||||
formatCurrencyDisplay(data?.terkumpul - data?.totalPencairan)) ||
|
||||
0
|
||||
}`,
|
||||
},
|
||||
{
|
||||
label: "Akumulasi Pencairan",
|
||||
value: "0 kali",
|
||||
value: `${(data && data?.akumulasiPencairan) || 0} kali`,
|
||||
},
|
||||
{
|
||||
label: "Bank Tujuan",
|
||||
value: "BNI",
|
||||
value: (data && data?.namaBank) || "-",
|
||||
},
|
||||
{
|
||||
label: "Nomor Rekening",
|
||||
value: "123456789",
|
||||
value: (data && data?.rekening) || "-",
|
||||
},
|
||||
];
|
||||
|
||||
const handleReport = async ({
|
||||
changeStatus,
|
||||
}: {
|
||||
changeStatus: "publish" | "review" | "reject";
|
||||
}) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await funUpdateStatusDonation({
|
||||
id: id as string,
|
||||
changeStatus,
|
||||
data: data,
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Update status gagal",
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Update status berhasil",
|
||||
});
|
||||
|
||||
router.back();
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const rightComponent = (
|
||||
<ActionIcon
|
||||
icon={<IconDot size={ICON_SIZE_BUTTON} />}
|
||||
@@ -118,8 +175,6 @@ export default function AdminDonationDetail() {
|
||||
/>
|
||||
);
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper
|
||||
@@ -147,11 +202,20 @@ export default function AdminDonationDetail() {
|
||||
/>
|
||||
))}
|
||||
</StackCustom>
|
||||
|
||||
<ButtonCustom
|
||||
iconLeft={
|
||||
<Ionicons name="cash-outline" size={ICON_SIZE_BUTTON} />
|
||||
}
|
||||
disabled={data?.terkumpul - data?.totalPencairan <= 0}
|
||||
onPress={() => {
|
||||
if (data?.terkumpul - data?.totalPencairan <= 0) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Tidak ada dana yang tersisa",
|
||||
});
|
||||
return;
|
||||
}
|
||||
router.push(`/admin/donation/${id}/disbursement-of-funds`);
|
||||
}}
|
||||
>
|
||||
@@ -161,16 +225,32 @@ export default function AdminDonationDetail() {
|
||||
</BaseBox>
|
||||
|
||||
<BaseBox>
|
||||
<ProgressCustom size="lg" />
|
||||
<ProgressCustom
|
||||
size="lg"
|
||||
value={Number(data?.progres) || 0}
|
||||
showLabel={true}
|
||||
label={data?.progres + "%"}
|
||||
animated
|
||||
color="primary"
|
||||
/>
|
||||
<Spacing />
|
||||
|
||||
<StackCustom gap={"xs"}>
|
||||
<GridDetail_4_8
|
||||
label={<TextCustom bold>Jumlah Donatur</TextCustom>}
|
||||
value={<TextCustom>0 orang</TextCustom>}
|
||||
value={
|
||||
<TextCustom>
|
||||
{countDonatur ? countDonatur : 0} orang
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
<GridDetail_4_8
|
||||
label={<TextCustom bold>Dana Terkumpul</TextCustom>}
|
||||
value={<TextCustom>Rp 0</TextCustom>}
|
||||
value={
|
||||
<TextCustom>
|
||||
Rp {formatCurrencyDisplay(data?.terkumpul || 0)}
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
@@ -179,7 +259,7 @@ export default function AdminDonationDetail() {
|
||||
|
||||
<BaseBox>
|
||||
<StackCustom>
|
||||
<DummyLandscapeImage />
|
||||
<DummyLandscapeImage imageId={data?.imageId || ""} />
|
||||
{listData.map((item, i) => (
|
||||
<GridDetail_4_8
|
||||
key={i}
|
||||
@@ -190,27 +270,33 @@ export default function AdminDonationDetail() {
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
|
||||
<AdminDonation_BoxOfDonationStory data={data?.CeritaDonasi as any} />
|
||||
|
||||
{data &&
|
||||
data?.catatan &&
|
||||
(status === "review" || status === "reject") && (
|
||||
<ReportBox text={data?.catatan} />
|
||||
)}
|
||||
|
||||
{status === "review" && (
|
||||
<StackCustom>
|
||||
<AdminDonation_BoxOfDonationStory />
|
||||
|
||||
<AdminButtonReview
|
||||
isLoading={isLoading}
|
||||
onPublish={() => {
|
||||
AlertDefaultSystem({
|
||||
title: "Publish",
|
||||
message: "Apakah anda yakin ingin mempublikasikan data ini?",
|
||||
textLeft: "Batal",
|
||||
textRight: "Ya",
|
||||
onPressLeft: () => {
|
||||
router.back();
|
||||
},
|
||||
onPressRight: () => {
|
||||
router.back();
|
||||
handleReport({ changeStatus: "publish" });
|
||||
},
|
||||
});
|
||||
}}
|
||||
onReject={() => {
|
||||
router.push(`/admin/donation/${id}/reject-input`);
|
||||
router.push(
|
||||
`/admin/donation/${id}/reject-input?status=${status}`
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</StackCustom>
|
||||
@@ -218,12 +304,12 @@ export default function AdminDonationDetail() {
|
||||
|
||||
{status === "reject" && (
|
||||
<StackCustom>
|
||||
<AdminDonation_BoxOfDonationStory />
|
||||
|
||||
<AdminButtonReject
|
||||
title="Tambah Catatan"
|
||||
onReject={() => {
|
||||
router.push(`/admin/donation/${id}/reject-input`);
|
||||
router.push(
|
||||
`/admin/donation/${id}/reject-input?status=${status}`
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</StackCustom>
|
||||
|
||||
@@ -9,51 +9,162 @@ import {
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import dayjs from "dayjs";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import {
|
||||
apiAdminDonationInvoiceDetailById,
|
||||
apiAdminDonationInvoiceUpdateById,
|
||||
} from "@/service/api-admin/api-admin-donation";
|
||||
import { colorBadgeTransaction } from "@/utils/colorBadge";
|
||||
import { dateTimeView } from "@/utils/dateTimeView";
|
||||
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminDonasiTransactionDetail() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const { id, status } = useLocalSearchParams();
|
||||
console.log("[STATUS]", id, status);
|
||||
|
||||
const buttonAction = (
|
||||
<BoxButtonOnFooter>
|
||||
<ButtonCustom onPress={() => router.back()}>Terima</ButtonCustom>
|
||||
</BoxButtonOnFooter>
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
const [isLoading, setLoading] = useState(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiAdminDonationInvoiceDetailById({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
console.log("[GET INVOICE BY ID]", JSON.stringify(response, null, 2));
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handlerSubmit = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const newData = {
|
||||
donationId: data?.donasiId,
|
||||
nominal: data?.nominal,
|
||||
};
|
||||
|
||||
const response = await apiAdminDonationInvoiceUpdateById({
|
||||
id: id as string,
|
||||
data: newData,
|
||||
status: "berhasil",
|
||||
});
|
||||
|
||||
console.log("[UPDATE INVOICE]", JSON.stringify(response, null, 2));
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: response.message,
|
||||
});
|
||||
return;
|
||||
}
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: response.message,
|
||||
});
|
||||
router.back();
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const buttonAction = () => {
|
||||
if (data && data?.DonasiMaster_StatusInvoice?.name === "Menunggu") {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (data && data?.DonasiMaster_StatusInvoice?.name === "Proses") {
|
||||
return (
|
||||
<BoxButtonOnFooter>
|
||||
<ButtonCustom
|
||||
isLoading={isLoading}
|
||||
onPress={() => {
|
||||
handlerSubmit();
|
||||
}}
|
||||
>
|
||||
Terima donasi
|
||||
</ButtonCustom>
|
||||
</BoxButtonOnFooter>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<BoxButtonOnFooter>
|
||||
<ButtonCustom disabled>
|
||||
{data?.DonasiMaster_StatusInvoice?.name}
|
||||
</ButtonCustom>
|
||||
</BoxButtonOnFooter>
|
||||
);
|
||||
};
|
||||
|
||||
const listData = [
|
||||
{
|
||||
label: "Donatur",
|
||||
value: "Bagas Banuna",
|
||||
value: (data && data?.Author?.username) || "-",
|
||||
},
|
||||
{
|
||||
label: "Bank",
|
||||
value: "BCA",
|
||||
value: (data && data?.MasterBank?.namaBank) || "-",
|
||||
},
|
||||
{
|
||||
label: "Jumlah Donasi",
|
||||
value: "Rp. 1.000.000",
|
||||
value: `Rp. ${
|
||||
(data && data?.nominal && formatCurrencyDisplay(data?.nominal)) || "-"
|
||||
}`,
|
||||
},
|
||||
{
|
||||
label: "Status",
|
||||
value: <BadgeCustom color={MainColor.green}>Berhasil</BadgeCustom>,
|
||||
value:
|
||||
(data && data?.DonasiMaster_StatusInvoice?.name && (
|
||||
<BadgeCustom
|
||||
color={colorBadgeTransaction({
|
||||
status: data?.DonasiMaster_StatusInvoice?.name as any,
|
||||
})}
|
||||
>
|
||||
{_.startCase(
|
||||
(data?.DonasiMaster_StatusInvoice?.name as any) || "-"
|
||||
)}
|
||||
</BadgeCustom>
|
||||
)) ||
|
||||
"-",
|
||||
},
|
||||
{
|
||||
label: "Tanggal",
|
||||
value: dayjs().format("DD-MM-YYYY HH:mm:ss"),
|
||||
value: (data && dateTimeView({ date: data?.createdAt })) || "-",
|
||||
},
|
||||
{
|
||||
label: "Bukti Transfer",
|
||||
value: (
|
||||
<ButtonCustom
|
||||
onPress={() =>
|
||||
router.push(`/(application)/(image)/preview-image/${id}`)
|
||||
}
|
||||
>
|
||||
Cek
|
||||
</ButtonCustom>
|
||||
),
|
||||
value:
|
||||
(data && data?.imageId && (
|
||||
<ButtonCustom
|
||||
onPress={() =>
|
||||
router.push(
|
||||
`/(application)/(image)/preview-image/${data?.imageId}`
|
||||
)
|
||||
}
|
||||
>
|
||||
Cek
|
||||
</ButtonCustom>
|
||||
)) ||
|
||||
"-",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -61,7 +172,7 @@ export default function AdminDonasiTransactionDetail() {
|
||||
<>
|
||||
<ViewWrapper
|
||||
headerComponent={<AdminBackButtonAntTitle title="Detail Transaksi" />}
|
||||
footerComponent={buttonAction}
|
||||
footerComponent={buttonAction()}
|
||||
>
|
||||
<BaseBox>
|
||||
<StackCustom>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
BaseBox,
|
||||
ButtonCustom,
|
||||
@@ -7,27 +8,53 @@ import {
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
|
||||
import dayjs from "dayjs";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { apiAdminDonationDisbursementOfFundsListById } from "@/service/api-admin/api-admin-donation";
|
||||
import { dateTimeView } from "@/utils/dateTimeView";
|
||||
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import React, { useCallback } from "react";
|
||||
|
||||
export default function AdminDonationDetailDisbursementOfFunds() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [data, setData] = React.useState<any | null>(null);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiAdminDonationDisbursementOfFundsListById({
|
||||
id: id as string,
|
||||
category: "get-one",
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const listData = [
|
||||
{
|
||||
label: "Nominal",
|
||||
value: "Rp 1.000.000",
|
||||
value: `Rp ${(data && formatCurrencyDisplay(data?.nominalCair)) || 0}`,
|
||||
},
|
||||
{
|
||||
label: "Tanggal",
|
||||
value: dayjs().format("DD-MM-YYYY HH:mm"),
|
||||
value: dateTimeView({ date: data?.createdAt }),
|
||||
},
|
||||
{
|
||||
label: "Judul",
|
||||
value: `Judul Pencairan Dana ${id}`,
|
||||
value: (data && data?.title) || "-",
|
||||
},
|
||||
{
|
||||
label: "Deskripsi",
|
||||
value: `Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque velit eos facere a dicta nemo repellendus harum laboriosam quos, earum reprehenderit. Nisi sapiente, quo earum quis alias ullam temporibus quidem.`,
|
||||
value: (data && data?.deskripsi) || "-",
|
||||
},
|
||||
];
|
||||
return (
|
||||
@@ -39,7 +66,7 @@ export default function AdminDonationDetailDisbursementOfFunds() {
|
||||
>
|
||||
<BaseBox>
|
||||
<StackCustom>
|
||||
{listData.map((item, index) => (
|
||||
{listData?.map((item, index) => (
|
||||
<GridDetail_4_8
|
||||
key={index}
|
||||
label={<TextCustom bold>{item.label}</TextCustom>}
|
||||
@@ -51,7 +78,7 @@ export default function AdminDonationDetailDisbursementOfFunds() {
|
||||
|
||||
<ButtonCustom
|
||||
onPress={() =>
|
||||
router.push(`/(application)/(image)/preview-image/${id}`)
|
||||
router.push(`/(application)/(image)/preview-image/${data?.imageId}`)
|
||||
}
|
||||
>
|
||||
Cek Bukti Transaksi
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
BaseBox,
|
||||
BoxButtonOnFooter,
|
||||
@@ -12,15 +13,122 @@ import {
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import DIRECTORY_ID from "@/constants/directory-id";
|
||||
import { apiAdminDonationDetailById, apiAdminDonationDisbursementOfFundsCreated } from "@/service/api-admin/api-admin-donation";
|
||||
import { uploadFileService } from "@/service/upload-service";
|
||||
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
|
||||
import pickFile from "@/utils/pickFile";
|
||||
import { Image } from "expo-image";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import React from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminDonationDisbursementOfFunds() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const handleSubmit = (
|
||||
|
||||
const [data, setData] = React.useState<any | null>(null);
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
|
||||
const [value, setValue] = React.useState({
|
||||
nominalCair: "",
|
||||
title: "",
|
||||
deskripsi: "",
|
||||
});
|
||||
|
||||
const [image, setImage] = React.useState<any | null>(null);
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiAdminDonationDetailById({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data.donasi);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
setData(null);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!image) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Harap upload bukti transfer",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!value.nominalCair || !value.title || !value.deskripsi) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Harap isi semua data",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const uploadImage = await uploadFileService({
|
||||
dirId: DIRECTORY_ID.donasi_bukti_trf_pencairan_dana,
|
||||
imageUri: image.uri,
|
||||
});
|
||||
|
||||
if (!uploadFileService) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Gagal mengunggah gambar",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const imageId = uploadImage.data.id;
|
||||
|
||||
const newData = {
|
||||
...value,
|
||||
imageId: imageId,
|
||||
};
|
||||
|
||||
const response = await apiAdminDonationDisbursementOfFundsCreated({
|
||||
id: id as string,
|
||||
data: newData,
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: response.message,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Pencairan dana berhasil disimpan",
|
||||
});
|
||||
|
||||
router.back();
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const buttonSubmit = (
|
||||
<BoxButtonOnFooter>
|
||||
<ButtonCustom
|
||||
isLoading={isLoading}
|
||||
onPress={() => {
|
||||
router.back();
|
||||
handleSubmit();
|
||||
}}
|
||||
>
|
||||
Simpan
|
||||
@@ -31,7 +139,7 @@ export default function AdminDonationDisbursementOfFunds() {
|
||||
return (
|
||||
<ViewWrapper
|
||||
headerComponent={<AdminBackButtonAntTitle title="Pencairan Dana" />}
|
||||
footerComponent={handleSubmit}
|
||||
footerComponent={buttonSubmit}
|
||||
>
|
||||
<BaseBox>
|
||||
<StackCustom gap="md">
|
||||
@@ -39,7 +147,7 @@ export default function AdminDonationDisbursementOfFunds() {
|
||||
Dana Tersisa
|
||||
</TextCustom>
|
||||
<TextCustom align="center" bold size="large">
|
||||
Rp 1.000.000
|
||||
Rp {formatCurrencyDisplay(data?.terkumpul - data?.totalPencairan)}
|
||||
</TextCustom>
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
@@ -56,9 +164,27 @@ export default function AdminDonationDisbursementOfFunds() {
|
||||
label="Nominal"
|
||||
placeholder="0"
|
||||
iconLeft={"Rp"}
|
||||
value={value.nominalCair}
|
||||
onChangeText={(text) => {
|
||||
setValue({
|
||||
...value,
|
||||
nominalCair: text,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
<TextInputCustom required label="Judul" placeholder="Masukan judul" />
|
||||
<TextInputCustom
|
||||
required
|
||||
label="Judul"
|
||||
placeholder="Masukan judul"
|
||||
value={value.title}
|
||||
onChangeText={(text) => {
|
||||
setValue({
|
||||
...value,
|
||||
title: text,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
<TextAreaCustom
|
||||
required
|
||||
@@ -66,20 +192,37 @@ export default function AdminDonationDisbursementOfFunds() {
|
||||
placeholder="Masukan deskripsi"
|
||||
showCount
|
||||
maxLength={500}
|
||||
value={value.deskripsi}
|
||||
onChangeText={(text) => {
|
||||
setValue({
|
||||
...value,
|
||||
deskripsi: text,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
<InformationBox text="Wajib menyertakan bukti transfer" />
|
||||
|
||||
<Spacing />
|
||||
|
||||
<InformationBox text="Wajib menyertakan bukti transfer" />
|
||||
<ButtonCenteredOnly
|
||||
onPress={() => {
|
||||
router.push(`/(application)/(image)/take-picture/${id}`);
|
||||
pickFile({
|
||||
allowedType: "image",
|
||||
aspectRatio: [9, 16],
|
||||
setImageUri: (file) => {
|
||||
setImage(file);
|
||||
},
|
||||
});
|
||||
}}
|
||||
icon="upload"
|
||||
>
|
||||
Upload
|
||||
</ButtonCenteredOnly>
|
||||
<Spacing />
|
||||
<Image source={image?.uri} style={{ width: "100%", height: 300 }} />
|
||||
<Spacing />
|
||||
</ViewWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,21 +1,54 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
ActionIcon,
|
||||
CenterCustom,
|
||||
Divider,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper
|
||||
ActionIcon,
|
||||
CenterCustom,
|
||||
Divider,
|
||||
LoaderCustom,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import { IconView } from "@/components/_Icon/IconComponent";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import { GridViewCustomSpan } from "@/components/_ShareComponent/GridViewCustomSpan";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import { apiAdminDonationDisbursementOfFundsListById } from "@/service/api-admin/api-admin-donation";
|
||||
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
|
||||
import dayjs from "dayjs";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import React, { useCallback } from "react";
|
||||
import { View } from "react-native";
|
||||
|
||||
export default function AdminDonasiListOfDisbursementOfFunds() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [listData, setListData] = React.useState<any[] | null>(null);
|
||||
const [loadData, setLoadData] = React.useState(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadData(true);
|
||||
const response = await apiAdminDonationDisbursementOfFundsListById({
|
||||
id: id as string,
|
||||
category: "get-all",
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setListData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadData(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper
|
||||
@@ -45,36 +78,47 @@ export default function AdminDonasiListOfDisbursementOfFunds() {
|
||||
/>
|
||||
<Divider />
|
||||
<StackCustom>
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<View key={index}>
|
||||
<GridViewCustomSpan
|
||||
span1={3}
|
||||
span2={5}
|
||||
span3={4}
|
||||
component1={
|
||||
<CenterCustom>
|
||||
<ActionIcon
|
||||
icon={<IconView size={ICON_SIZE_BUTTON} color="black" />}
|
||||
onPress={() => {
|
||||
router.push(
|
||||
`/admin/donation/${id}/detail-disbursement-of-funds`
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</CenterCustom>
|
||||
}
|
||||
component2={
|
||||
<TextCustom bold align="center" truncate>
|
||||
{dayjs()
|
||||
.add(index + 1, "day")
|
||||
.format("DD-MM-YYYY HH:mm")}
|
||||
</TextCustom>
|
||||
}
|
||||
component3={<TextCustom>Rp. 1.000.000</TextCustom>}
|
||||
/>
|
||||
<Divider />
|
||||
</View>
|
||||
))}
|
||||
{loadData ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(listData) ? (
|
||||
<TextCustom align="center" color="gray">
|
||||
Belum ada data
|
||||
</TextCustom>
|
||||
) : (
|
||||
listData?.map((item, index) => (
|
||||
<View key={index}>
|
||||
<GridViewCustomSpan
|
||||
span1={3}
|
||||
span2={5}
|
||||
span3={4}
|
||||
component1={
|
||||
<CenterCustom>
|
||||
<ActionIcon
|
||||
icon={
|
||||
<IconView size={ICON_SIZE_BUTTON} color="black" />
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(
|
||||
`/admin/donation/${item?.id}/detail-disbursement-of-funds`
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</CenterCustom>
|
||||
}
|
||||
component2={
|
||||
<TextCustom align="center" truncate>
|
||||
{dayjs(item?.createdAt).format("DD-MM-YYYY")}
|
||||
</TextCustom>
|
||||
}
|
||||
component3={
|
||||
<TextCustom align="center" truncate>
|
||||
Rp. {formatCurrencyDisplay(item?.nominalCair)}
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
))
|
||||
)}
|
||||
</StackCustom>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
ActionIcon,
|
||||
BadgeCustom,
|
||||
CenterCustom,
|
||||
LoaderCustom,
|
||||
SelectCustom,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
@@ -10,23 +12,91 @@ import {
|
||||
import { IconView } from "@/components/_Icon/IconComponent";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import { GridViewCustomSpan } from "@/components/_ShareComponent/GridViewCustomSpan";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import { dummyMasterStatusTransaction } from "@/lib/dummy-data/_master/status-transaction";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import React from "react";
|
||||
import { apiAdminDonationListOfDonatur } from "@/service/api-admin/api-admin-donation";
|
||||
import { apiMasterTransaction } from "@/service/api-client/api-master";
|
||||
import { colorBadgeTransaction } from "@/utils/colorBadge";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import React, { useEffect } from "react";
|
||||
import { View } from "react-native";
|
||||
import { Divider } from "react-native-paper";
|
||||
|
||||
export default function AdminDonasiListOfDonatur() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [listData, setListData] = React.useState<any[] | null>(null);
|
||||
const [loadData, setLoadData] = React.useState(false);
|
||||
const [master, setMaster] = React.useState<any[]>([]);
|
||||
|
||||
const [selectValue, setSelectValue] = React.useState<string | null>(null);
|
||||
const [selectedStatus, setSelectedStatus] = React.useState<string | null>(
|
||||
null
|
||||
);
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id, selectValue])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadData(true);
|
||||
const response = await apiAdminDonationListOfDonatur({
|
||||
id: id as string,
|
||||
status: selectedStatus as any,
|
||||
});
|
||||
// console.log("[LIST OF DONATUR]", JSON.stringify(response, null, 2));
|
||||
|
||||
if (response.success) {
|
||||
setListData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
setListData([]);
|
||||
} finally {
|
||||
setLoadData(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
onLoadMaster();
|
||||
}, []);
|
||||
|
||||
const onLoadMaster = async () => {
|
||||
try {
|
||||
const response = await apiMasterTransaction();
|
||||
|
||||
if (response.success) {
|
||||
setMaster(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
setMaster([]);
|
||||
}
|
||||
};
|
||||
|
||||
const searchComponent = (
|
||||
<View style={{ flexDirection: "row", gap: 5 }}>
|
||||
<SelectCustom
|
||||
placeholder="Pilih status transaksi"
|
||||
data={dummyMasterStatusTransaction}
|
||||
onChange={(value) => console.log(value)}
|
||||
data={
|
||||
_.isEmpty(master)
|
||||
? []
|
||||
: master?.map((item: any) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
}))
|
||||
}
|
||||
value={selectValue}
|
||||
onChange={(value: any) => {
|
||||
setSelectValue(value);
|
||||
const nameSelected = master.find((item: any) => item.id === value);
|
||||
const statusChooses = _.lowerCase(nameSelected?.name);
|
||||
setSelectedStatus(statusChooses);
|
||||
}}
|
||||
styleContainer={{ width: "100%", marginBottom: 0 }}
|
||||
allowClear
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
@@ -37,63 +107,78 @@ export default function AdminDonasiListOfDonatur() {
|
||||
<AdminBackButtonAntTitle newComponent={searchComponent} />
|
||||
}
|
||||
>
|
||||
<GridViewCustomSpan
|
||||
span1={3}
|
||||
span2={5}
|
||||
span3={4}
|
||||
component1={
|
||||
<TextCustom bold align="center">
|
||||
Aksi
|
||||
</TextCustom>
|
||||
}
|
||||
component2={
|
||||
<TextCustom bold align="center">
|
||||
Donatur
|
||||
</TextCustom>
|
||||
}
|
||||
component3={
|
||||
<TextCustom bold align="center">
|
||||
Status
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
<Divider />
|
||||
<StackCustom>
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<View key={index}>
|
||||
<GridViewCustomSpan
|
||||
span1={3}
|
||||
span2={5}
|
||||
span3={4}
|
||||
component1={
|
||||
<CenterCustom>
|
||||
<ActionIcon
|
||||
icon={<IconView size={ICON_SIZE_BUTTON} color="black" />}
|
||||
onPress={() => {
|
||||
router.push(
|
||||
`/admin/donation/${id}/berhasil/transaction-detail`
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</CenterCustom>
|
||||
}
|
||||
component2={
|
||||
<TextCustom bold align="center" truncate>
|
||||
Bagas Banuna
|
||||
</TextCustom>
|
||||
}
|
||||
component3={
|
||||
<BadgeCustom
|
||||
style={{ alignSelf: "center" }}
|
||||
color={MainColor.green}
|
||||
>
|
||||
Berhasil
|
||||
</BadgeCustom>
|
||||
}
|
||||
/>
|
||||
<Divider />
|
||||
</View>
|
||||
))}
|
||||
<GridViewCustomSpan
|
||||
span1={3}
|
||||
span2={5}
|
||||
span3={4}
|
||||
component1={
|
||||
<TextCustom bold align="center">
|
||||
Aksi
|
||||
</TextCustom>
|
||||
}
|
||||
component2={
|
||||
<TextCustom bold align="center">
|
||||
Donatur
|
||||
</TextCustom>
|
||||
}
|
||||
component3={
|
||||
<TextCustom bold align="center">
|
||||
Status
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
<Divider />
|
||||
<StackCustom>
|
||||
{loadData ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(listData) ? (
|
||||
<TextCustom align="center" color="gray">
|
||||
Belum ada data
|
||||
</TextCustom>
|
||||
) : (
|
||||
listData?.map((item: any, index: number) => (
|
||||
<View key={index}>
|
||||
<GridViewCustomSpan
|
||||
span1={3}
|
||||
span2={5}
|
||||
span3={4}
|
||||
component1={
|
||||
<CenterCustom>
|
||||
<ActionIcon
|
||||
icon={
|
||||
<IconView size={ICON_SIZE_BUTTON} color="black" />
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(
|
||||
`/admin/donation/${item?.id}/${_.lowerCase(
|
||||
item?.DonasiMaster_StatusInvoice?.name
|
||||
)}/transaction-detail`
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</CenterCustom>
|
||||
}
|
||||
component2={
|
||||
<TextCustom bold align="center" truncate>
|
||||
{item?.Author?.username || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
component3={
|
||||
<BadgeCustom
|
||||
style={{ alignSelf: "center" }}
|
||||
color={colorBadgeTransaction({
|
||||
status: item?.DonasiMaster_StatusInvoice?.name,
|
||||
})}
|
||||
>
|
||||
{item?.DonasiMaster_StatusInvoice?.name}
|
||||
</BadgeCustom>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
))
|
||||
)}
|
||||
</StackCustom>
|
||||
</StackCustom>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
AlertDefaultSystem,
|
||||
BoxButtonOnFooter,
|
||||
@@ -6,15 +7,84 @@ import {
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import { funUpdateStatusDonation } from "@/screens/Admin/Donation/funDonationUpdateStatus";
|
||||
import {
|
||||
apiAdminDonationDetailById
|
||||
} from "@/service/api-admin/api-admin-donation";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import React from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminDonationRejectInput() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [value, setValue] = useState(id as string);
|
||||
const { id, status } = useLocalSearchParams();
|
||||
|
||||
const [data, setData] = React.useState<any | null>(null);
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiAdminDonationDetailById({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data.catatan);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
setData(null);
|
||||
}
|
||||
};
|
||||
|
||||
const handleReport = async ({
|
||||
changeStatus,
|
||||
}: {
|
||||
changeStatus: "publish" | "review" | "reject";
|
||||
}) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await funUpdateStatusDonation({
|
||||
id: id as string,
|
||||
changeStatus,
|
||||
data: data,
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Report gagal",
|
||||
});
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Report berhasil",
|
||||
});
|
||||
|
||||
if (status === "review") {
|
||||
router.replace(`/admin/donation/reject/status`);
|
||||
} else if (status === "reject") {
|
||||
router.back();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const buttonSubmit = (
|
||||
<BoxButtonOnFooter>
|
||||
<AdminButtonReject
|
||||
isLoading={isLoading}
|
||||
title="Reject"
|
||||
onReject={() =>
|
||||
AlertDefaultSystem({
|
||||
@@ -22,12 +92,9 @@ export default function AdminDonationRejectInput() {
|
||||
message: "Apakah anda yakin ingin menolak data ini?",
|
||||
textLeft: "Batal",
|
||||
textRight: "Ya",
|
||||
onPressLeft: () => {
|
||||
router.back();
|
||||
},
|
||||
|
||||
onPressRight: () => {
|
||||
console.log("value:", value);
|
||||
router.replace(`/admin/donation/reject/status`);
|
||||
handleReport({ changeStatus: "reject" });
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -42,8 +109,8 @@ export default function AdminDonationRejectInput() {
|
||||
headerComponent={<AdminBackButtonAntTitle title="Penolakan Donasi" />}
|
||||
>
|
||||
<TextAreaCustom
|
||||
value={value}
|
||||
onChangeText={setValue}
|
||||
value={data}
|
||||
onChangeText={setData}
|
||||
placeholder="Masukan alasan"
|
||||
required
|
||||
showCount
|
||||
|
||||
@@ -1,69 +1,116 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
ActionIcon,
|
||||
SearchInput,
|
||||
Spacing,
|
||||
TextCustom,
|
||||
ViewWrapper
|
||||
ActionIcon,
|
||||
LoaderCustom,
|
||||
SearchInput,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper
|
||||
} from "@/components";
|
||||
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
|
||||
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
|
||||
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
|
||||
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import { apiAdminDonation } from "@/service/api-admin/api-admin-donation";
|
||||
import { Octicons } from "@expo/vector-icons";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { Divider } from "react-native-paper";
|
||||
|
||||
export default function AdminDonationStatus() {
|
||||
const { status } = useLocalSearchParams();
|
||||
console.log("[STATUS]", status);
|
||||
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
const [search, setSearch] = useState<string>("");
|
||||
const [loadData, setLoadData] = useState<boolean>(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [status, search])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadData(true);
|
||||
const response = await apiAdminDonation({
|
||||
category: status as "publish" | "review" | "reject",
|
||||
search,
|
||||
});
|
||||
|
||||
console.log("[RES]", JSON.stringify(response, null, 2));
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
setData([]);
|
||||
} finally {
|
||||
setLoadData(false);
|
||||
}
|
||||
};
|
||||
|
||||
const rightComponent = (
|
||||
<SearchInput
|
||||
containerStyle={{ width: "100%", marginBottom: 0 }}
|
||||
placeholder="Cari"
|
||||
value={search}
|
||||
onChangeText={(value) => setSearch(value)}
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper
|
||||
headerComponent={
|
||||
<ViewWrapper headerComponent={<AdminTitlePage title="Donasi" />}>
|
||||
<StackCustom gap={"sm"}>
|
||||
<AdminComp_BoxTitle
|
||||
title={`Donasi ${_.startCase(status as string)}`}
|
||||
title={`${_.startCase(status as string)}`}
|
||||
rightComponent={rightComponent}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<AdminTitleTable
|
||||
title1="Aksi"
|
||||
title2="Username"
|
||||
title3="Judul Donasi"
|
||||
/>
|
||||
<Spacing />
|
||||
<Divider />
|
||||
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<Octicons name="eye" size={ICON_SIZE_BUTTON} color="black" />
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(`/admin/donation/${index}/${status}`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={<TextCustom truncate={1}>Username username</TextCustom>}
|
||||
value3={
|
||||
<TextCustom truncate={2}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
Blanditiis asperiores quidem deleniti architecto eaque et
|
||||
nostrum, ad consequuntur eveniet quisquam quae voluptatum
|
||||
ducimus! Dolorem nobis modi officia debitis, beatae mollitia.
|
||||
</TextCustom>
|
||||
}
|
||||
<AdminTitleTable
|
||||
title1="Aksi"
|
||||
title2="Username"
|
||||
title3="Judul Donasi"
|
||||
/>
|
||||
))}
|
||||
<Divider />
|
||||
|
||||
{loadData ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(data) ? (
|
||||
<TextCustom align="center" size="small" color="gray">
|
||||
Belum ada data
|
||||
</TextCustom>
|
||||
) : (
|
||||
data?.map((item: any, index: number) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<Octicons
|
||||
name="eye"
|
||||
size={ICON_SIZE_BUTTON}
|
||||
color="black"
|
||||
/>
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(`/admin/donation/${item.id}/${status}`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={<TextCustom truncate={1}>{item?.Author?.username || "-"}</TextCustom>}
|
||||
value3={
|
||||
<TextCustom truncate={2}>
|
||||
{item?.title || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</StackCustom>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,15 +1,67 @@
|
||||
import { Spacing, StackCustom, ViewWrapper } from "@/components";
|
||||
import {
|
||||
IconList,
|
||||
IconPublish,
|
||||
IconReject,
|
||||
IconReview,
|
||||
IconList,
|
||||
IconPublish,
|
||||
IconReject,
|
||||
IconReview,
|
||||
} from "@/components/_Icon/IconComponent";
|
||||
import AdminComp_BoxDashboard from "@/components/_ShareComponent/Admin/BoxDashboard";
|
||||
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { apiAdminDonation } from "@/service/api-admin/api-admin-donation";
|
||||
import { useFocusEffect } from "expo-router";
|
||||
import { useState, useCallback } from "react";
|
||||
|
||||
export default function AdminDonation() {
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
|
||||
const response = await apiAdminDonation({
|
||||
category: "dashboard",
|
||||
});
|
||||
|
||||
console.log("[RES]", JSON.stringify(response, null, 2));
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
setData([]);
|
||||
}
|
||||
};
|
||||
|
||||
const listData = [
|
||||
{
|
||||
label: "Publish",
|
||||
value: (data && data.publish) || 0,
|
||||
icon: <IconPublish size={25} color={MainColor.green} />,
|
||||
},
|
||||
{
|
||||
label: "Review",
|
||||
value: (data && data.review) || 0,
|
||||
icon: <IconReview size={25} color={MainColor.orange} />,
|
||||
},
|
||||
{
|
||||
label: "Reject",
|
||||
value: (data && data.reject) || 0,
|
||||
icon: <IconReject size={25} color={MainColor.red} />,
|
||||
},
|
||||
{
|
||||
label: "Kategori",
|
||||
value: (data && data.categoryDonation) || 0,
|
||||
icon: <IconList size={25} color={MainColor.white_gray} />,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper>
|
||||
@@ -24,26 +76,3 @@ export default function AdminDonation() {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const listData = [
|
||||
{
|
||||
label: "Publish",
|
||||
value: 4,
|
||||
icon: <IconPublish size={25} color={MainColor.green} />,
|
||||
},
|
||||
{
|
||||
label: "Review",
|
||||
value: 7,
|
||||
icon: <IconReview size={25} color={MainColor.orange} />,
|
||||
},
|
||||
{
|
||||
label: "Reject",
|
||||
value: 5,
|
||||
icon: <IconReject size={25} color={MainColor.red} />,
|
||||
},
|
||||
{
|
||||
label: "Kategori",
|
||||
value: 4,
|
||||
icon: <IconList size={25} color={MainColor.white_gray} />,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,112 +1,110 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
ActionIcon,
|
||||
AlertDefaultSystem,
|
||||
BadgeCustom,
|
||||
BaseBox,
|
||||
DrawerCustom,
|
||||
MenuDrawerDynamicGrid,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
ActionIcon,
|
||||
AlertDefaultSystem,
|
||||
BadgeCustom,
|
||||
BaseBox,
|
||||
DrawerCustom,
|
||||
LoaderCustom,
|
||||
MenuDrawerDynamicGrid,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import { IconDot, IconList } from "@/components/_Icon/IconComponent";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
|
||||
import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview";
|
||||
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import ReportBox from "@/components/Box/ReportBox";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import dayjs from "dayjs";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { funUpdateStatusEvent } from "@/screens/Admin/Event/funUpdateStatus";
|
||||
import { apiAdminEventById } from "@/service/api-admin/api-admin-event";
|
||||
import { DEEP_LINK_URL } from "@/service/api-config";
|
||||
import { colorBadgeStatus } from "@/utils/colorBadge";
|
||||
import { dateTimeView } from "@/utils/dateTimeView";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import React from "react";
|
||||
import React, { useCallback } from "react";
|
||||
import QRCode from "react-native-qrcode-svg";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminEventDetail() {
|
||||
const { user } = useAuth();
|
||||
const { id, status } = useLocalSearchParams();
|
||||
const [openDrawer, setOpenDrawer] = React.useState(false);
|
||||
|
||||
const colorBadge = () => {
|
||||
if (status === "publish") {
|
||||
return MainColor.green;
|
||||
} else if (status === "review") {
|
||||
return MainColor.orange;
|
||||
} else if (status === "reject") {
|
||||
return MainColor.red;
|
||||
} else {
|
||||
return MainColor.placeholder;
|
||||
const [data, setData] = React.useState<any | null>(null);
|
||||
const [loadData, setLoadData] = React.useState(false);
|
||||
const deepLinkURL = `${DEEP_LINK_URL}/--/event/${id}/confirmation?userId=${user?.id}`;
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadData(true);
|
||||
const response = await apiAdminEventById({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadData(false);
|
||||
}
|
||||
};
|
||||
|
||||
const listData = [
|
||||
{
|
||||
label: "Pembuat Event",
|
||||
value: `Bagas Banuna ${id}`,
|
||||
value: (data && data?.Author?.username) || "-",
|
||||
},
|
||||
{
|
||||
label: "Judul Event",
|
||||
value: `Event 123`,
|
||||
value: (data && data?.title) || "-",
|
||||
},
|
||||
{
|
||||
label: "Status",
|
||||
value: (
|
||||
<BadgeCustom color={colorBadge()}>
|
||||
{_.startCase(status as string)}
|
||||
</BadgeCustom>
|
||||
),
|
||||
value:
|
||||
(data && (
|
||||
<BadgeCustom color={colorBadgeStatus({ status: status as string })}>
|
||||
{_.startCase(status as string)}
|
||||
</BadgeCustom>
|
||||
)) ||
|
||||
"-",
|
||||
},
|
||||
{
|
||||
label: "Lokasi",
|
||||
value: "Lokasi Event",
|
||||
value: (data && data?.lokasi) || "-",
|
||||
},
|
||||
{
|
||||
label: "Tipe Acara",
|
||||
value: "Tipe Acara",
|
||||
value: (data && data?.EventMaster_TipeAcara?.name) || "-",
|
||||
},
|
||||
{
|
||||
label: "Mulai Event",
|
||||
value: dayjs().format("DD/MM/YYYY HH:mm:ss"),
|
||||
value:
|
||||
(data && data?.tanggal && dateTimeView({ date: data?.tanggal })) || "-",
|
||||
},
|
||||
{
|
||||
label: "Event Berakhir",
|
||||
value: dayjs().add(3, "day").format("DD/MM/YYYY HH:mm:ss"),
|
||||
value:
|
||||
(data &&
|
||||
data?.tanggalSelesai &&
|
||||
dateTimeView({ date: data?.tanggalSelesai })) ||
|
||||
"-",
|
||||
},
|
||||
{
|
||||
label: "Deskripsi",
|
||||
value: "Lorem ipsum dolor sit amet consectetur adipisicing elit.",
|
||||
value: (data && data?.deskripsi) || "-",
|
||||
},
|
||||
// {
|
||||
// label: "Daftar Tipe Acara",
|
||||
// value: (
|
||||
// <>
|
||||
// <List.Item
|
||||
// title={<TextCustom>Pilihan 1</TextCustom>}
|
||||
// left={(props) => (
|
||||
// <List.Icon {...props} icon="circle" color={MainColor.yellow} />
|
||||
// )}
|
||||
// />
|
||||
// <List.Item
|
||||
// title={<TextCustom>Pilihan 2</TextCustom>}
|
||||
// left={(props) => (
|
||||
// <List.Icon {...props} icon="circle" color={MainColor.yellow} />
|
||||
// )}
|
||||
// />
|
||||
// <List.Item
|
||||
// title={<TextCustom>Pilihan 3</TextCustom>}
|
||||
// left={(props) => (
|
||||
// <List.Icon {...props} icon="circle" color={MainColor.yellow} />
|
||||
// )}
|
||||
// />
|
||||
// <List.Item
|
||||
// title={<TextCustom>Pilihan 4</TextCustom>}
|
||||
// left={(props) => (
|
||||
// <List.Icon {...props} icon="circle" color={MainColor.yellow} />
|
||||
// )}
|
||||
// />
|
||||
// </>
|
||||
// ),
|
||||
// },
|
||||
];
|
||||
|
||||
const rightComponent = (
|
||||
@@ -118,6 +116,31 @@ export default function AdminEventDetail() {
|
||||
/>
|
||||
);
|
||||
|
||||
const handlerSubmit = async () => {
|
||||
try {
|
||||
const response = await funUpdateStatusEvent({
|
||||
id: id as string,
|
||||
changeStatus: "publish",
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Gagal mempublikasikan event",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Event berhasil dipublikasikan",
|
||||
});
|
||||
router.back();
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper
|
||||
@@ -125,7 +148,7 @@ export default function AdminEventDetail() {
|
||||
<AdminBackButtonAntTitle
|
||||
title={`Detail Data`}
|
||||
rightComponent={
|
||||
(status === "publish" || status === "riwayat") && rightComponent
|
||||
(status === "publish" || status === "history") && rightComponent
|
||||
}
|
||||
/>
|
||||
}
|
||||
@@ -143,19 +166,30 @@ export default function AdminEventDetail() {
|
||||
|
||||
<Spacing />
|
||||
</BaseBox>
|
||||
{(status === "publish" || status === "riwayat") && (
|
||||
|
||||
{data &&
|
||||
data?.catatan &&
|
||||
(status === "reject" || status === "review") && (
|
||||
<ReportBox text={data?.catatan} />
|
||||
)}
|
||||
|
||||
{(status === "publish" || status === "history") && (
|
||||
<BaseBox>
|
||||
<StackCustom style={{ alignItems: "center" }}>
|
||||
<TextCustom bold>QR Code Event</TextCustom>
|
||||
<QRCode
|
||||
value="https://google.com"
|
||||
size={200}
|
||||
// logo={require("@/assets/images/logo-hipmi.png")}
|
||||
// logoSize={70}
|
||||
// logoBackgroundColor="transparent"
|
||||
// logoBorderRadius={50}
|
||||
// color="black"
|
||||
/>
|
||||
{loadData ? (
|
||||
<LoaderCustom />
|
||||
) : (
|
||||
<QRCode
|
||||
value={deepLinkURL}
|
||||
size={200}
|
||||
// logo={require("@/assets/images/logo-hipmi.png")}
|
||||
// logoSize={70}
|
||||
// logoBackgroundColor="transparent"
|
||||
// logoBorderRadius={50}
|
||||
// color="black"
|
||||
/>
|
||||
)}
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
)}
|
||||
@@ -168,16 +202,11 @@ export default function AdminEventDetail() {
|
||||
message: "Apakah anda yakin ingin mempublikasikan data ini?",
|
||||
textLeft: "Batal",
|
||||
textRight: "Ya",
|
||||
onPressLeft: () => {
|
||||
router.back();
|
||||
},
|
||||
onPressRight: () => {
|
||||
router.back();
|
||||
},
|
||||
onPressRight: () => handlerSubmit(),
|
||||
});
|
||||
}}
|
||||
onReject={() => {
|
||||
router.push(`/admin/event/${id}/reject-input`);
|
||||
router.push(`/admin/event/${id}/reject-input?status=${status}`);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -186,7 +215,7 @@ export default function AdminEventDetail() {
|
||||
<AdminButtonReject
|
||||
title="Tambah Catatan"
|
||||
onReject={() => {
|
||||
router.push(`/admin/event/${id}/reject-input`);
|
||||
router.push(`/admin/event/${id}/reject-input?status=${status}`);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -1,41 +1,81 @@
|
||||
import { BadgeCustom, BaseBox, Grid, TextCustom, ViewWrapper } from "@/components";
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
BadgeCustom,
|
||||
BaseBox,
|
||||
Grid,
|
||||
LoaderCustom,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { apiAdminEventListOfParticipants } from "@/service/api-admin/api-admin-event";
|
||||
import { useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export default function AdminEventListOfParticipants() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [listData, setListData] = useState<any[] | null>(null);
|
||||
const [loadData, setLoadData] = useState(false);
|
||||
|
||||
const isPresent = ({id}: {id: number}) => {
|
||||
const check = id % 3 * 3;
|
||||
if (check === 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadData(true);
|
||||
const response = await apiAdminEventListOfParticipants({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setListData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadData(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper
|
||||
headerComponent={<AdminBackButtonAntTitle title="Daftar Peserta" />}
|
||||
>
|
||||
{Array.from({ length: 10 }).map((item, index) => (
|
||||
<BaseBox key={index}>
|
||||
<Grid>
|
||||
<Grid.Col span={6}>
|
||||
<TextCustom bold>Username {index + 1}</TextCustom>
|
||||
<TextCustom>+6282123456789</TextCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={6} style={{ justifyContent: "center" }}>
|
||||
<BadgeCustom
|
||||
style={{ alignSelf: "flex-end" }}
|
||||
color={isPresent({id: index}) ? MainColor.green : MainColor.red}
|
||||
>
|
||||
{isPresent({id: index}) ? "Hadir" : "Tidak Hadir"}
|
||||
</BadgeCustom>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</BaseBox>
|
||||
))}
|
||||
{loadData ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(listData) ? (
|
||||
<TextCustom align="center" color="gray">
|
||||
Belum ada peserta
|
||||
</TextCustom>
|
||||
) : (
|
||||
listData?.map((item: any, index: number) => (
|
||||
<BaseBox key={index}>
|
||||
<Grid>
|
||||
<Grid.Col span={6}>
|
||||
<StackCustom gap={"sm"}>
|
||||
<TextCustom bold truncate>{item?.User?.username}</TextCustom>
|
||||
<TextCustom>+{item?.User?.nomor}</TextCustom>
|
||||
</StackCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={6} style={{ justifyContent: "center" }}>
|
||||
<BadgeCustom
|
||||
style={{ alignSelf: "flex-end" }}
|
||||
color={item?.isPresent ? "green" : "red"}
|
||||
>
|
||||
{item?.isPresent ? "Hadir" : "Tidak Hadir"}
|
||||
</BadgeCustom>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</BaseBox>
|
||||
))
|
||||
)}
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
AlertDefaultSystem,
|
||||
BoxButtonOnFooter,
|
||||
@@ -6,15 +7,78 @@ import {
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import { funUpdateStatusEvent } from "@/screens/Admin/Event/funUpdateStatus";
|
||||
import { apiAdminEventById } from "@/service/api-admin/api-admin-event";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminEventRejectInput() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [value, setValue] = useState(id as string);
|
||||
const { id, status } = useLocalSearchParams();
|
||||
|
||||
const [data, setData] = useState<any>("");
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiAdminEventById({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data.catatan);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdate = async ({
|
||||
changeStatus,
|
||||
}: {
|
||||
changeStatus: "publish" | "review" | "reject";
|
||||
}) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await funUpdateStatusEvent({
|
||||
id: id as string,
|
||||
changeStatus,
|
||||
data: data,
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Report gagal",
|
||||
});
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Report berhasil",
|
||||
});
|
||||
|
||||
if (status === "review") {
|
||||
router.replace(`/admin/event/reject/status`);
|
||||
} else if (status === "reject") {
|
||||
router.back();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const buttonSubmit = (
|
||||
<BoxButtonOnFooter>
|
||||
<AdminButtonReject
|
||||
isLoading={isLoading}
|
||||
title="Reject"
|
||||
onReject={() =>
|
||||
AlertDefaultSystem({
|
||||
@@ -22,12 +86,8 @@ export default function AdminEventRejectInput() {
|
||||
message: "Apakah anda yakin ingin menolak data ini?",
|
||||
textLeft: "Batal",
|
||||
textRight: "Ya",
|
||||
onPressLeft: () => {
|
||||
router.back();
|
||||
},
|
||||
onPressRight: () => {
|
||||
console.log("value:", value);
|
||||
router.replace(`/admin/event/reject/status`);
|
||||
handleUpdate({ changeStatus: "reject" });
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -42,8 +102,8 @@ export default function AdminEventRejectInput() {
|
||||
headerComponent={<AdminBackButtonAntTitle title="Penolakan Event" />}
|
||||
>
|
||||
<TextAreaCustom
|
||||
value={value}
|
||||
onChangeText={setValue}
|
||||
value={data}
|
||||
onChangeText={setData}
|
||||
placeholder="Masukan alasan"
|
||||
required
|
||||
showCount
|
||||
|
||||
@@ -1,27 +1,67 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
ActionIcon,
|
||||
BaseBox,
|
||||
LoaderCustom,
|
||||
SearchInput,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
ViewWrapper
|
||||
} from "@/components";
|
||||
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
|
||||
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
|
||||
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
|
||||
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import { apiAdminEvent } from "@/service/api-admin/api-admin-event";
|
||||
import { Octicons } from "@expo/vector-icons";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { Divider } from "react-native-paper";
|
||||
|
||||
export default function AdminEventStatus() {
|
||||
const { status } = useLocalSearchParams();
|
||||
console.log("[STATUS EVENT]", status);
|
||||
|
||||
const [listData, setListData] = useState<any[] | null>(null);
|
||||
const [loadData, setLoadData] = useState(false);
|
||||
const [search, setSearch] = useState<string>("");
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [status, search])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadData(true);
|
||||
const response = await apiAdminEvent({
|
||||
category: status as "publish" | "review" | "reject" | "history" as any,
|
||||
search,
|
||||
});
|
||||
|
||||
console.log(
|
||||
`[RES LIST BY STATUS: ${status}]`,
|
||||
JSON.stringify(response, null, 2)
|
||||
);
|
||||
|
||||
if (response.success) {
|
||||
setListData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadData(false);
|
||||
}
|
||||
};
|
||||
|
||||
const rightComponent = (
|
||||
<SearchInput
|
||||
containerStyle={{ width: "100%", marginBottom: 0 }}
|
||||
placeholder="Cari"
|
||||
value={search}
|
||||
onChangeText={(value) => setSearch(value)}
|
||||
/>
|
||||
);
|
||||
return (
|
||||
@@ -32,44 +72,50 @@ export default function AdminEventStatus() {
|
||||
rightComponent={rightComponent}
|
||||
/>
|
||||
|
||||
<BaseBox>
|
||||
<StackCustom gap={"sm"}>
|
||||
<AdminTitleTable
|
||||
title1="Aksi"
|
||||
title2="Username"
|
||||
title3="Judul Event"
|
||||
/>
|
||||
<Spacing />
|
||||
<Divider />
|
||||
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<Octicons
|
||||
name="eye"
|
||||
size={ICON_SIZE_BUTTON}
|
||||
color="black"
|
||||
/>
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(`/admin/event/${index}/${status}`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={<TextCustom truncate={1}>Username username</TextCustom>}
|
||||
value3={
|
||||
<TextCustom truncate={2}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
Blanditiis asperiores quidem deleniti architecto eaque et
|
||||
nostrum, ad consequuntur eveniet quisquam quae voluptatum
|
||||
ducimus! Dolorem nobis modi officia debitis, beatae mollitia.
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</BaseBox>
|
||||
{loadData ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(listData) ? (
|
||||
<TextCustom align="center" size="small" color="gray">Belum ada data</TextCustom>
|
||||
) : (
|
||||
listData?.map((item, index) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<Octicons
|
||||
name="eye"
|
||||
size={ICON_SIZE_BUTTON}
|
||||
color="black"
|
||||
/>
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(`/admin/event/${item.id}/${status}`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={
|
||||
<TextCustom truncate={1}>
|
||||
{item?.Author?.username || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
value3={
|
||||
<TextCustom align="center" truncate={2}>
|
||||
{item?.title || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</StackCustom>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -9,13 +9,67 @@ import {
|
||||
import AdminComp_BoxDashboard from "@/components/_ShareComponent/Admin/BoxDashboard";
|
||||
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { apiAdminEvent } from "@/service/api-admin/api-admin-event";
|
||||
import { useFocusEffect } from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export default function AdminVoting() {
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiAdminEvent({
|
||||
category: "dashboard",
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const listData = [
|
||||
{
|
||||
label: "Publish",
|
||||
value: (data && data.publish) || 0,
|
||||
icon: <IconPublish size={25} color={MainColor.green} />,
|
||||
},
|
||||
{
|
||||
label: "Review",
|
||||
value: (data && data.review) || 0,
|
||||
icon: <IconReview size={25} color={MainColor.orange} />,
|
||||
},
|
||||
{
|
||||
label: "Reject",
|
||||
value: (data && data.reject) || 0,
|
||||
icon: <IconReject size={25} color={MainColor.red} />,
|
||||
},
|
||||
{
|
||||
label: "Riwayat",
|
||||
value: (data && data.history) || 0,
|
||||
icon: <IconArchive size={25} color={MainColor.placeholder} />,
|
||||
},
|
||||
{
|
||||
label: "Tipe Acara",
|
||||
value: (data && data.typeOfEvent) || 0,
|
||||
icon: <IconList size={25} color={MainColor.placeholder} />,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper>
|
||||
<AdminTitlePage title="Event" />
|
||||
<Spacing />
|
||||
|
||||
<StackCustom gap={"xs"}>
|
||||
{listData.map((item, i) => (
|
||||
<AdminComp_BoxDashboard key={i} item={item} />
|
||||
@@ -25,31 +79,3 @@ export default function AdminVoting() {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const listData = [
|
||||
{
|
||||
label: "Publish",
|
||||
value: 3,
|
||||
icon: <IconPublish size={25} color={MainColor.green} />,
|
||||
},
|
||||
{
|
||||
label: "Review",
|
||||
value: 8,
|
||||
icon: <IconReview size={25} color={MainColor.orange} />,
|
||||
},
|
||||
{
|
||||
label: "Reject",
|
||||
value: 4,
|
||||
icon: <IconReject size={25} color={MainColor.red} />,
|
||||
},
|
||||
{
|
||||
label: "Riwayat",
|
||||
value: 6,
|
||||
icon: <IconArchive size={25} color={MainColor.placeholder} />,
|
||||
},
|
||||
{
|
||||
label: "Tipe Acara",
|
||||
value: 7,
|
||||
icon: <IconList size={25} color={MainColor.placeholder} />,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -5,13 +5,48 @@ import {
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import { apiEventCreateTypeOfEvent } from "@/service/api-admin/api-master-admin";
|
||||
import { useRouter } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminEventTypeOfEventCreate() {
|
||||
const router = useRouter();
|
||||
const [value, setValue] = useState("");
|
||||
const [isLoading, setLoading] = useState<boolean>(false);
|
||||
|
||||
const handlerSubmit = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await apiEventCreateTypeOfEvent({
|
||||
data: value,
|
||||
});
|
||||
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Gagal menambahkan tipe acara",
|
||||
});
|
||||
return;
|
||||
}
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Berhasil menambahkan tipe acara",
|
||||
});
|
||||
router.back();
|
||||
} catch (error) {
|
||||
console.log("[ERROR CREATE TYPE EVENT]", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const buttonSubmit = (
|
||||
<BoxButtonOnFooter>
|
||||
<ButtonCustom onPress={() => router.back()}>Simpan</ButtonCustom>
|
||||
<ButtonCustom isLoading={isLoading} onPress={() => handlerSubmit()}>
|
||||
Simpan
|
||||
</ButtonCustom>
|
||||
</BoxButtonOnFooter>
|
||||
);
|
||||
return (
|
||||
@@ -20,7 +55,11 @@ export default function AdminEventTypeOfEventCreate() {
|
||||
headerComponent={<AdminBackButtonAntTitle title="Tambah Tipe Acara" />}
|
||||
footerComponent={buttonSubmit}
|
||||
>
|
||||
<TextInputCustom placeholder="Masukkan Tipe Acara" />
|
||||
<TextInputCustom
|
||||
placeholder="Masukkan Tipe Acara"
|
||||
value={value}
|
||||
onChangeText={setValue}
|
||||
/>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,23 +1,53 @@
|
||||
import {
|
||||
ActionIcon,
|
||||
BaseBox,
|
||||
BadgeCustom,
|
||||
CenterCustom,
|
||||
LoaderCustom,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
ViewWrapper
|
||||
} from "@/components";
|
||||
import { IconEdit } from "@/components/_Icon";
|
||||
import AdminActionIconPlus from "@/components/_ShareComponent/Admin/ActionIconPlus";
|
||||
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
|
||||
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
|
||||
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
|
||||
import { GridViewCustomSpan } from "@/components/_ShareComponent/GridViewCustomSpan";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import { router } from "expo-router";
|
||||
import { apiAdminMasterTypeOfEvent } from "@/service/api-admin/api-master-admin";
|
||||
import { colorActivationForBadge } from "@/utils/colorActivationForBadge";
|
||||
import { router, useFocusEffect } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import { Divider } from "react-native-paper";
|
||||
|
||||
export default function AdminEventTypeOfEvent() {
|
||||
const [listData, setListData] = useState<any[] | null>(null);
|
||||
const [loadData, setLoadData] = useState<boolean>(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadData(true);
|
||||
const response = await apiAdminMasterTypeOfEvent();
|
||||
|
||||
if (response.success) {
|
||||
setListData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]",error);
|
||||
setListData([]);
|
||||
} finally {
|
||||
setLoadData(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper headerComponent={<AdminTitlePage title="Event" />}>
|
||||
@@ -32,73 +62,68 @@ export default function AdminEventTypeOfEvent() {
|
||||
}
|
||||
/>
|
||||
|
||||
<BaseBox>
|
||||
<GridDetail_4_8
|
||||
label={
|
||||
<>
|
||||
<GridViewCustomSpan
|
||||
span1={2}
|
||||
span2={5}
|
||||
span3={5}
|
||||
component1={
|
||||
<TextCustom bold align="center">
|
||||
Aksi
|
||||
</TextCustom>
|
||||
}
|
||||
value={<TextCustom bold>Tipe Acara</TextCustom>}
|
||||
component2={<TextCustom bold align="center">Status</TextCustom>}
|
||||
component3={<TextCustom bold>Tipe Acara</TextCustom>}
|
||||
/>
|
||||
<Divider />
|
||||
<Spacing />
|
||||
|
||||
<StackCustom>
|
||||
{listData.map((item, index) => (
|
||||
<View key={index}>
|
||||
<GridDetail_4_8
|
||||
label={
|
||||
<CenterCustom>
|
||||
<ActionIcon
|
||||
icon={
|
||||
<IconEdit size={ICON_SIZE_BUTTON} color="black" />
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(`/admin/event/type-update?id=${index}`);
|
||||
}}
|
||||
/>
|
||||
</CenterCustom>
|
||||
}
|
||||
value={<TextCustom bold>{item.label}</TextCustom>}
|
||||
/>
|
||||
<Divider />
|
||||
</View>
|
||||
))}
|
||||
{loadData ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(listData) ? (
|
||||
<TextCustom align="center" color="gray">
|
||||
Belum ada data
|
||||
</TextCustom>
|
||||
) : (
|
||||
listData?.map((item, index) => (
|
||||
<View key={index}>
|
||||
<GridViewCustomSpan
|
||||
span1={2}
|
||||
span2={5}
|
||||
span3={5}
|
||||
component1={
|
||||
<CenterCustom>
|
||||
<ActionIcon
|
||||
icon={
|
||||
<IconEdit size={ICON_SIZE_BUTTON} color="black" />
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(`/admin/event/type-update?id=${item.id}`);
|
||||
}}
|
||||
/>
|
||||
</CenterCustom>
|
||||
}
|
||||
style2={{ alignItems: "center" }}
|
||||
component2={
|
||||
<CenterCustom>
|
||||
<BadgeCustom
|
||||
color={colorActivationForBadge({
|
||||
status: item?.active,
|
||||
})}
|
||||
>
|
||||
{item?.active ? "Aktif" : "Tidak Aktif"}
|
||||
</BadgeCustom>
|
||||
</CenterCustom>
|
||||
}
|
||||
component3={<TextCustom >{item.name}</TextCustom>}
|
||||
/>
|
||||
</View>
|
||||
))
|
||||
)}
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
</>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const listData = [
|
||||
{
|
||||
label: "Seminar",
|
||||
value: "seminar",
|
||||
},
|
||||
{
|
||||
label: "Workshop",
|
||||
value: "workshop",
|
||||
},
|
||||
{
|
||||
label: "Konferensi",
|
||||
value: "konferensi",
|
||||
},
|
||||
{
|
||||
label: "Lomba",
|
||||
value: "lomba",
|
||||
},
|
||||
{
|
||||
label: "Pameran",
|
||||
value: "pameran",
|
||||
},
|
||||
{
|
||||
label: "Pesta",
|
||||
value: "pesta",
|
||||
},
|
||||
{
|
||||
label: "Pertandingan",
|
||||
value: "pertandingan",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,20 +1,91 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
BoxButtonOnFooter,
|
||||
ButtonCustom,
|
||||
Spacing,
|
||||
TextCustom,
|
||||
TextInputCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import { useLocalSearchParams, useRouter } from "expo-router";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import {
|
||||
apiAdminMasterTypeOfEventGetOne,
|
||||
apiAdminMasterTypeOfEventUpdate,
|
||||
} from "@/service/api-admin/api-master-admin";
|
||||
|
||||
import { useFocusEffect, useLocalSearchParams, useRouter } from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
import { Switch } from "react-native-paper";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminEventTypeOfEventUpdate() {
|
||||
const { id } = useLocalSearchParams();
|
||||
console.log("id >", id);
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const [data, setData] = useState<{ name: string; active: boolean }>({
|
||||
name: "",
|
||||
active: false,
|
||||
});
|
||||
const [isLoading, setLoading] = useState<boolean>(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiAdminMasterTypeOfEventGetOne({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData({
|
||||
name: response.data.name,
|
||||
active: response.data.active,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR UPDATE]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handlerSubmit = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const response = await apiAdminMasterTypeOfEventUpdate({
|
||||
id: id as string,
|
||||
data: data,
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Gagal mengupdate tipe acara",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Berhasil mengupdate tipe acara",
|
||||
});
|
||||
router.back();
|
||||
} catch (error) {
|
||||
console.log("[ERROR UPDATE]", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const buttonSubmit = (
|
||||
<BoxButtonOnFooter>
|
||||
<ButtonCustom onPress={() => router.back()}>Update</ButtonCustom>
|
||||
<ButtonCustom isLoading={isLoading} onPress={() => handlerSubmit()}>
|
||||
Update
|
||||
</ButtonCustom>
|
||||
</BoxButtonOnFooter>
|
||||
);
|
||||
return (
|
||||
@@ -23,7 +94,19 @@ export default function AdminEventTypeOfEventUpdate() {
|
||||
headerComponent={<AdminBackButtonAntTitle title="Ubah Tipe Acara" />}
|
||||
footerComponent={buttonSubmit}
|
||||
>
|
||||
<TextInputCustom placeholder="Masukkan Tipe Acara" value="" />
|
||||
<TextInputCustom
|
||||
placeholder="Masukkan Tipe Acara"
|
||||
value={data.name}
|
||||
onChangeText={(text) => setData({ ...data, name: text })}
|
||||
/>
|
||||
|
||||
<TextCustom>Aktivasi</TextCustom>
|
||||
<Spacing height={10} />
|
||||
<Switch
|
||||
color={MainColor.yellow}
|
||||
value={data.active}
|
||||
onValueChange={(value) => setData({ ...data, active: value })}
|
||||
/>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,58 +1,79 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
ActionIcon,
|
||||
AlertDefaultSystem,
|
||||
BadgeCustom,
|
||||
BaseBox,
|
||||
DrawerCustom,
|
||||
MenuDrawerDynamicGrid,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import { IconDot, IconView } from "@/components/_Icon/IconComponent";
|
||||
import { IconTrash } from "@/components/_Icon/IconTrash";
|
||||
import { IconDot } from "@/components/_Icon/IconComponent";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
|
||||
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
|
||||
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import {
|
||||
ICON_SIZE_BUTTON,
|
||||
ICON_SIZE_MEDIUM,
|
||||
ICON_SIZE_XLARGE,
|
||||
} from "@/constants/constans-value";
|
||||
import { ICON_SIZE_XLARGE } from "@/constants/constans-value";
|
||||
import { apiAdminForumPostingById } from "@/service/api-admin/api-admin-forum";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { router } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import { Divider } from "react-native-paper";
|
||||
import Toast from "react-native-toast-message";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export default function AdminForumDetailPosting() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [openDrawerPage, setOpenDrawerPage] = useState(false);
|
||||
const [openDrawerAction, setOpenDrawerAction] = useState(false);
|
||||
const [id, setId] = useState<any>();
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const handlerAction = (item: { value: string; path: string }) => {
|
||||
if (item.value === "delete") {
|
||||
AlertDefaultSystem({
|
||||
title: "Hapus Posting",
|
||||
message: "Apakah Anda yakin ingin menghapus posting ini?",
|
||||
textLeft: "Batal",
|
||||
textRight: "Hapus",
|
||||
onPressRight: () => {
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Posting berhasil dihapus",
|
||||
});
|
||||
},
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiAdminForumPostingById({
|
||||
id: id as string,
|
||||
});
|
||||
} else {
|
||||
router.navigate(item.path as any);
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
setOpenDrawerAction(false);
|
||||
};
|
||||
|
||||
const listDataAction = [
|
||||
{
|
||||
label: "Username",
|
||||
value: data?.Author?.username || "-",
|
||||
},
|
||||
{
|
||||
label: "Status",
|
||||
value:
|
||||
(data && (
|
||||
<BadgeCustom
|
||||
color={
|
||||
data?.ForumMaster_StatusPosting?.status === "Open"
|
||||
? MainColor.green
|
||||
: MainColor.red
|
||||
}
|
||||
>
|
||||
{data?.ForumMaster_StatusPosting?.status || "-"}
|
||||
</BadgeCustom>
|
||||
)) ||
|
||||
"-",
|
||||
},
|
||||
{
|
||||
label: "Komentar",
|
||||
value: data?.JumlahKomentar || 0,
|
||||
},
|
||||
{
|
||||
label: "Total Report",
|
||||
value: data?.JumlahReportPosting || 0,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper
|
||||
@@ -60,14 +81,25 @@ export default function AdminForumDetailPosting() {
|
||||
<AdminBackButtonAntTitle
|
||||
title="Detail Posting"
|
||||
rightComponent={
|
||||
<ActionIcon
|
||||
icon={<IconDot size={16} color={MainColor.darkblue} />}
|
||||
onPress={() => setOpenDrawerPage(true)}
|
||||
/>
|
||||
data &&
|
||||
data?.isActive && (
|
||||
<ActionIcon
|
||||
icon={<IconDot size={16} color={MainColor.darkblue} />}
|
||||
onPress={() => setOpenDrawerPage(true)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{data && !data?.isActive && (
|
||||
<BaseBox>
|
||||
<TextCustom bold align="center" color="red">
|
||||
Postingan ini telah di nonaktifkan
|
||||
</TextCustom>
|
||||
</BaseBox>
|
||||
)}
|
||||
|
||||
<BaseBox>
|
||||
<StackCustom gap={"sm"}>
|
||||
{listDataAction.map((item, i) => (
|
||||
@@ -77,50 +109,14 @@ export default function AdminForumDetailPosting() {
|
||||
value={<TextCustom>{item.value}</TextCustom>}
|
||||
/>
|
||||
))}
|
||||
<TextCustom bold>Posting</TextCustom>
|
||||
<TextCustom>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
Asperiores cupiditate nobis dignissimos explicabo quo unde dolorum
|
||||
numquam eos ab laborum fugiat illo nam velit quibusdam, maxime
|
||||
assumenda aut vero provident!
|
||||
</TextCustom>
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
|
||||
{/* <AdminComp_BoxTitle title="Komentar" rightComponent={rightComponent} /> */}
|
||||
<BaseBox>
|
||||
<AdminTitleTable title1="Aksi" title2="Username" title3="Komentar" />
|
||||
<Spacing />
|
||||
<Divider />
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<Ionicons
|
||||
name="ellipsis-vertical-outline"
|
||||
size={ICON_SIZE_BUTTON}
|
||||
color="black"
|
||||
/>
|
||||
}
|
||||
onPress={() => {
|
||||
setOpenDrawerAction(true);
|
||||
setId(index + 1);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={<TextCustom truncate={1}>Username username</TextCustom>}
|
||||
value3={
|
||||
<TextCustom truncate={2}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
Blanditiis asperiores quidem deleniti architecto eaque et
|
||||
nostrum, ad consequuntur eveniet quisquam quae voluptatum
|
||||
ducimus! Dolorem nobis modi officia debitis, beatae mollitia.
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
<StackCustom gap={"sm"}>
|
||||
<TextCustom bold>Postingan</TextCustom>
|
||||
<TextCustom>{(data && data?.diskusi) || "-"}</TextCustom>
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
</ViewWrapper>
|
||||
|
||||
@@ -143,6 +139,18 @@ export default function AdminForumDetailPosting() {
|
||||
value: "detail",
|
||||
path: `/admin/forum/${id}/list-report-posting`,
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
<Ionicons
|
||||
name="list"
|
||||
size={ICON_SIZE_XLARGE}
|
||||
color={MainColor.white}
|
||||
/>
|
||||
),
|
||||
label: "Daftar Komentar",
|
||||
value: "detail",
|
||||
path: `/admin/forum/${id}/list-comment`,
|
||||
},
|
||||
]}
|
||||
onPressItem={(item) => {
|
||||
router.navigate(item.path as any);
|
||||
@@ -150,54 +158,6 @@ export default function AdminForumDetailPosting() {
|
||||
}}
|
||||
/>
|
||||
</DrawerCustom>
|
||||
|
||||
<DrawerCustom
|
||||
isVisible={openDrawerAction}
|
||||
closeDrawer={() => setOpenDrawerAction(false)}
|
||||
height={"auto"}
|
||||
>
|
||||
<MenuDrawerDynamicGrid
|
||||
data={[
|
||||
{
|
||||
icon: <IconView />,
|
||||
label: "Detail Komentar",
|
||||
value: "detail",
|
||||
path: `admin/forum/${id}/list-report-comment`,
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
<IconTrash size={ICON_SIZE_MEDIUM} color={MainColor.white} />
|
||||
),
|
||||
label: "Hapus Komentar",
|
||||
value: "delete",
|
||||
path: "",
|
||||
color: MainColor.red,
|
||||
},
|
||||
]}
|
||||
onPressItem={(item) => {
|
||||
handlerAction(item as any);
|
||||
}}
|
||||
/>
|
||||
</DrawerCustom>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const listDataAction = [
|
||||
{
|
||||
label: "Username",
|
||||
value: "Username",
|
||||
},
|
||||
{
|
||||
label: "Status",
|
||||
value: <BadgeCustom color={MainColor.green}>Open</BadgeCustom>,
|
||||
},
|
||||
{
|
||||
label: "Komentar",
|
||||
value: "10",
|
||||
},
|
||||
{
|
||||
label: "Total Report",
|
||||
value: "1",
|
||||
},
|
||||
];
|
||||
|
||||
91
app/(application)/admin/forum/[id]/list-comment.tsx
Normal file
91
app/(application)/admin/forum/[id]/list-comment.tsx
Normal file
@@ -0,0 +1,91 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
LoaderCustom,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper
|
||||
} from "@/components";
|
||||
import { IconOpenTo } from "@/components/_Icon/IconOpenTo";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
|
||||
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
|
||||
import { apiAdminForumCommentById } from "@/service/api-admin/api-admin-forum";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { Divider } from "react-native-paper";
|
||||
|
||||
export default function AdminForumListComment() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [listComment, setListComment] = useState<any[] | null>(null);
|
||||
const [loadList, setLoadList] = useState(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadComment();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadComment = async () => {
|
||||
try {
|
||||
setLoadList(true);
|
||||
const response = await apiAdminForumCommentById({
|
||||
id: id as string,
|
||||
category: "get-all",
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setListComment(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
setListComment([]);
|
||||
} finally {
|
||||
setLoadList(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper
|
||||
headerComponent={<AdminBackButtonAntTitle title="Daftar Komentar" />}
|
||||
>
|
||||
<StackCustom>
|
||||
<AdminTitleTable title1="Aksi" title2="Report" title3="Komentar" />
|
||||
<Divider />
|
||||
{loadList ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(listComment) ? (
|
||||
<TextCustom align="center" color="gray">
|
||||
Tidak ada komentar
|
||||
</TextCustom>
|
||||
) : (
|
||||
listComment?.map((item: any, index: number) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<IconOpenTo
|
||||
onPress={() => {
|
||||
router.push(
|
||||
`/admin/forum/${item.id}/list-report-comment`
|
||||
);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={
|
||||
<TextCustom truncate={1}>
|
||||
{item?.countReport || 0}
|
||||
</TextCustom>
|
||||
}
|
||||
value3={
|
||||
<TextCustom truncate={2}>{item?.komentar || "-"}</TextCustom>
|
||||
}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</StackCustom>
|
||||
</ViewWrapper>
|
||||
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
ActionIcon,
|
||||
AlertDefaultSystem,
|
||||
BaseBox,
|
||||
DrawerCustom,
|
||||
LoaderCustom,
|
||||
MenuDrawerDynamicGrid,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
@@ -18,14 +19,64 @@ import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
|
||||
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import { router } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
apiAdminForumCommentById,
|
||||
apiAdminForumDeactivateComment,
|
||||
apiAdminForumListReportCommentById,
|
||||
} from "@/service/api-admin/api-admin-forum";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { Divider } from "react-native-paper";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminForumReportComment() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
const [listReport, setListReport] = useState<any[] | null>(null);
|
||||
const [loadList, setLoadList] = useState(false);
|
||||
const [openDrawer, setOpenDrawer] = useState(false);
|
||||
const [openDrawerAction, setOpenDrawerAction] = useState(false);
|
||||
const [selectedReport, setSelectedReport] = useState({
|
||||
id: "",
|
||||
username: "",
|
||||
kategori: "",
|
||||
keterangan: "",
|
||||
deskripsi: "",
|
||||
});
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadList(true);
|
||||
const response = await apiAdminForumCommentById({
|
||||
id: id as string,
|
||||
category: "get-one",
|
||||
});
|
||||
|
||||
const responseReport = await apiAdminForumListReportCommentById({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
if (responseReport.success) {
|
||||
setListReport(responseReport.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
setData(null);
|
||||
setListReport([]);
|
||||
} finally {
|
||||
setLoadList(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -44,53 +95,65 @@ export default function AdminForumReportComment() {
|
||||
>
|
||||
<BaseBox>
|
||||
<StackCustom gap={"sm"}>
|
||||
{listData.map((item, i) => (
|
||||
<GridDetail_4_8
|
||||
key={i}
|
||||
label={<TextCustom bold>{item.label}</TextCustom>}
|
||||
value={<TextCustom>{item.value}</TextCustom>}
|
||||
/>
|
||||
))}
|
||||
<TextCustom bold>Posting</TextCustom>
|
||||
<TextCustom>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
Asperiores cupiditate nobis dignissimos explicabo quo unde dolorum
|
||||
numquam eos ab laborum fugiat illo nam velit quibusdam, maxime
|
||||
assumenda aut vero provident!
|
||||
</TextCustom>
|
||||
<GridDetail_4_8
|
||||
label={<TextCustom bold>Username</TextCustom>}
|
||||
value={<TextCustom>{data?.Author?.username || "-"}</TextCustom>}
|
||||
/>
|
||||
<GridDetail_4_8
|
||||
label={<TextCustom bold>Komentar</TextCustom>}
|
||||
value={<TextCustom>{data?.komentar || "-"}</TextCustom>}
|
||||
/>
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
|
||||
<AdminComp_BoxTitle title="Daftar Report Komentar" />
|
||||
|
||||
<BaseBox>
|
||||
<StackCustom>
|
||||
<AdminTitleTable
|
||||
title1="Aksi"
|
||||
title2="Username"
|
||||
title2="Pelapor"
|
||||
title3="Kategori Report"
|
||||
/>
|
||||
<Spacing />
|
||||
<Divider />
|
||||
{Array.from({ length: 5 }).map((_, index) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={<IconView size={ICON_SIZE_BUTTON} color="black" />}
|
||||
onPress={() => {
|
||||
setOpenDrawerAction(true);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={<TextCustom truncate={1}>Username username</TextCustom>}
|
||||
value3={
|
||||
<TextCustom truncate={2} align="center">
|
||||
SPAM
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</BaseBox>
|
||||
{loadList ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(listReport) ? (
|
||||
<TextCustom align="center" color="gray">
|
||||
Tidak ada report
|
||||
</TextCustom>
|
||||
) : (
|
||||
listReport?.map((item: any, index: number) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={<IconView size={ICON_SIZE_BUTTON} color="black" />}
|
||||
onPress={() => {
|
||||
setOpenDrawerAction(true);
|
||||
setSelectedReport({
|
||||
id: item.id,
|
||||
username: item.User?.username,
|
||||
kategori: item.ForumMaster_KategoriReport?.title,
|
||||
keterangan: item.ForumMaster_KategoriReport?.deskripsi,
|
||||
deskripsi: item.deskripsi,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={
|
||||
<TextCustom truncate={1}>
|
||||
{item?.User?.username || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
value3={
|
||||
<TextCustom truncate={2} align="center">
|
||||
{item?.ForumMaster_KategoriReport?.title || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</StackCustom>
|
||||
</ViewWrapper>
|
||||
|
||||
<DrawerCustom
|
||||
@@ -114,7 +177,19 @@ export default function AdminForumReportComment() {
|
||||
message: "Apakah Anda yakin ingin menghapus komentar ini?",
|
||||
textLeft: "Batal",
|
||||
textRight: "Hapus",
|
||||
onPressRight: () => {
|
||||
onPressRight: async () => {
|
||||
const deleteComment = await apiAdminForumDeactivateComment({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
if (!deleteComment.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Komentar gagal dihapus",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setOpenDrawer(false);
|
||||
Toast.show({
|
||||
type: "success",
|
||||
@@ -132,37 +207,39 @@ export default function AdminForumReportComment() {
|
||||
closeDrawer={() => setOpenDrawerAction(false)}
|
||||
height={"auto"}
|
||||
>
|
||||
{listDataAction.map((item, i) => (
|
||||
<StackCustom>
|
||||
<GridDetail_4_8
|
||||
key={i}
|
||||
label={<TextCustom bold>{item.label}</TextCustom>}
|
||||
value={<TextCustom>{item.value}</TextCustom>}
|
||||
label={<TextCustom bold>Pelapor</TextCustom>}
|
||||
value={<TextCustom>{selectedReport?.username || "-"}</TextCustom>}
|
||||
/>
|
||||
))}
|
||||
|
||||
{selectedReport?.kategori && (
|
||||
<>
|
||||
<GridDetail_4_8
|
||||
label={<TextCustom bold>Kategori Report</TextCustom>}
|
||||
value={
|
||||
<TextCustom>{selectedReport?.kategori || "-"}</TextCustom>
|
||||
}
|
||||
/>
|
||||
<GridDetail_4_8
|
||||
label={<TextCustom bold>Keterangan</TextCustom>}
|
||||
value={
|
||||
<TextCustom>{selectedReport?.keterangan || "-"}</TextCustom>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{selectedReport?.deskripsi && (
|
||||
<GridDetail_4_8
|
||||
label={<TextCustom bold>Deskripsi</TextCustom>}
|
||||
value={
|
||||
<TextCustom>{selectedReport?.deskripsi || "-"}</TextCustom>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</StackCustom>
|
||||
</DrawerCustom>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const listData = [
|
||||
{
|
||||
label: "Username",
|
||||
value: "Username",
|
||||
},
|
||||
];
|
||||
|
||||
const listDataAction = [
|
||||
{
|
||||
label: "Username",
|
||||
value: "Riyusa",
|
||||
},
|
||||
{
|
||||
label: "Kategori Report",
|
||||
value: "SPAM",
|
||||
},
|
||||
{
|
||||
label: "Deskripsi",
|
||||
value:
|
||||
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Blanditiis asperiores quidem deleniti architecto eaque et nostrum, ad consequuntur eveniet quisquam quae voluptatum ducimus! Dolorem nobis modi officia debitis, beatae mollitia.",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
ActionIcon,
|
||||
AlertDefaultSystem,
|
||||
BadgeCustom,
|
||||
BaseBox,
|
||||
DrawerCustom,
|
||||
LoaderCustom,
|
||||
MenuDrawerDynamicGrid,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
@@ -19,15 +20,64 @@ import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
|
||||
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import { router } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
apiAdminForumDeactivatePosting,
|
||||
apiAdminForumListReportPostingById,
|
||||
apiAdminForumPostingById,
|
||||
} from "@/service/api-admin/api-admin-forum";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { Divider } from "react-native-paper";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminForumReportPosting() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [openDrawerPage, setOpenDrawerPage] = useState(false);
|
||||
const [openDrawerAction, setOpenDrawerAction] = useState(false);
|
||||
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
const [listReport, setListReport] = useState<any[] | null>(null);
|
||||
const [loadListReport, setLoadListReport] = useState(false);
|
||||
const [selectedReport, setSelectedReport] = useState({
|
||||
id: "",
|
||||
username: "",
|
||||
kategori: "",
|
||||
keterangan: "",
|
||||
deskripsi: "",
|
||||
});
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadListReport(true);
|
||||
const response = await apiAdminForumPostingById({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
const responseReport = await apiAdminForumListReportPostingById({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
|
||||
if (responseReport.success) {
|
||||
setListReport(responseReport.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadListReport(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper
|
||||
@@ -45,50 +95,86 @@ export default function AdminForumReportPosting() {
|
||||
>
|
||||
<BaseBox>
|
||||
<StackCustom gap={"sm"}>
|
||||
{listData.map((item, i) => (
|
||||
<GridDetail_4_8
|
||||
key={i}
|
||||
label={<TextCustom bold>{item.label}</TextCustom>}
|
||||
value={<TextCustom>{item.value}</TextCustom>}
|
||||
/>
|
||||
))}
|
||||
<TextCustom bold>Posting</TextCustom>
|
||||
<TextCustom>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
Asperiores cupiditate nobis dignissimos explicabo quo unde dolorum
|
||||
numquam eos ab laborum fugiat illo nam velit quibusdam, maxime
|
||||
assumenda aut vero provident!
|
||||
</TextCustom>
|
||||
<GridDetail_4_8
|
||||
label={<TextCustom bold>Username</TextCustom>}
|
||||
value={<TextCustom>{data?.Author?.username || "-"}</TextCustom>}
|
||||
/>
|
||||
|
||||
<GridDetail_4_8
|
||||
label={<TextCustom bold>Status</TextCustom>}
|
||||
value={
|
||||
data && data?.ForumMaster_StatusPosting?.status ? (
|
||||
<BadgeCustom
|
||||
color={
|
||||
data?.ForumMaster_StatusPosting?.status === "Open"
|
||||
? MainColor.green
|
||||
: MainColor.red
|
||||
}
|
||||
>
|
||||
{data?.ForumMaster_StatusPosting?.status === "Open"
|
||||
? "Open"
|
||||
: "Close"}
|
||||
</BadgeCustom>
|
||||
) : (
|
||||
<TextCustom>{"-"}</TextCustom>
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
<GridDetail_4_8
|
||||
label={<TextCustom bold>Postingan</TextCustom>}
|
||||
value={<TextCustom>{data?.diskusi || "-"}</TextCustom>}
|
||||
/>
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
|
||||
<AdminComp_BoxTitle title="Daftar Report Posting" />
|
||||
<BaseBox>
|
||||
<StackCustom gap={"sm"}>
|
||||
<AdminTitleTable
|
||||
title1="Aksi"
|
||||
title2="Username"
|
||||
title2="Pelapor"
|
||||
title3="Kategori Report"
|
||||
/>
|
||||
<Spacing />
|
||||
<Divider />
|
||||
{Array.from({ length: 5 }).map((_, index) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={<IconView size={ICON_SIZE_BUTTON} color="black" />}
|
||||
onPress={() => setOpenDrawerAction(true)}
|
||||
/>
|
||||
}
|
||||
value2={<TextCustom truncate={1}>Username username</TextCustom>}
|
||||
value3={
|
||||
<TextCustom truncate={2} align="center">
|
||||
SPAM
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</BaseBox>
|
||||
{loadListReport ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(listReport) ? (
|
||||
<TextCustom align="center" color={"gray"}>
|
||||
Belum ada report
|
||||
</TextCustom>
|
||||
) : (
|
||||
listReport?.map((item: any, index: number) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={<IconView size={ICON_SIZE_BUTTON} color="black" />}
|
||||
onPress={() => {
|
||||
setOpenDrawerAction(true);
|
||||
setSelectedReport({
|
||||
id: item?.id,
|
||||
username: item?.User?.username,
|
||||
kategori: item?.ForumMaster_KategoriReport?.title,
|
||||
keterangan: item?.ForumMaster_KategoriReport?.deskripsi,
|
||||
deskripsi: item?.deskripsi,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={
|
||||
<TextCustom truncate={1}>
|
||||
{item?.User?.username || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
value3={
|
||||
<TextCustom truncate={2} align="center">
|
||||
{item?.ForumMaster_KategoriReport?.title || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</StackCustom>
|
||||
</ViewWrapper>
|
||||
|
||||
<DrawerCustom
|
||||
@@ -112,13 +198,25 @@ export default function AdminForumReportPosting() {
|
||||
message: "Apakah Anda yakin ingin menghapus posting ini?",
|
||||
textLeft: "Batal",
|
||||
textRight: "Hapus",
|
||||
onPressRight: () => {
|
||||
onPressRight: async () => {
|
||||
const response = await apiAdminForumDeactivatePosting({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Posting gagal dihapus",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setOpenDrawerPage(false);
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Posting berhasil dihapus",
|
||||
});
|
||||
router.back()
|
||||
router.back();
|
||||
},
|
||||
});
|
||||
}}
|
||||
@@ -130,41 +228,39 @@ export default function AdminForumReportPosting() {
|
||||
closeDrawer={() => setOpenDrawerAction(false)}
|
||||
height={"auto"}
|
||||
>
|
||||
{listDataAction.map((item, i) => (
|
||||
<StackCustom>
|
||||
<GridDetail_4_8
|
||||
key={i}
|
||||
label={<TextCustom bold>{item.label}</TextCustom>}
|
||||
value={<TextCustom>{item.value}</TextCustom>}
|
||||
label={<TextCustom bold>Pelapor</TextCustom>}
|
||||
value={<TextCustom>{selectedReport?.username || "-"}</TextCustom>}
|
||||
/>
|
||||
))}
|
||||
|
||||
{selectedReport?.kategori && (
|
||||
<>
|
||||
<GridDetail_4_8
|
||||
label={<TextCustom bold>Kategori Report</TextCustom>}
|
||||
value={
|
||||
<TextCustom>{selectedReport?.kategori || "-"}</TextCustom>
|
||||
}
|
||||
/>
|
||||
<GridDetail_4_8
|
||||
label={<TextCustom bold>Keterangan</TextCustom>}
|
||||
value={
|
||||
<TextCustom>{selectedReport?.keterangan || "-"}</TextCustom>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{selectedReport?.deskripsi && (
|
||||
<GridDetail_4_8
|
||||
label={<TextCustom bold>Deskripsi</TextCustom>}
|
||||
value={
|
||||
<TextCustom>{selectedReport?.deskripsi || "-"}</TextCustom>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</StackCustom>
|
||||
</DrawerCustom>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const listData = [
|
||||
{
|
||||
label: "Username",
|
||||
value: "Username",
|
||||
},
|
||||
{
|
||||
label: "Status",
|
||||
value: <BadgeCustom color={MainColor.green}>Open</BadgeCustom>,
|
||||
},
|
||||
];
|
||||
|
||||
const listDataAction = [
|
||||
{
|
||||
label: "Username",
|
||||
value: "Firman Nusantara",
|
||||
},
|
||||
{
|
||||
label: "Kategori Report",
|
||||
value: "SPAM",
|
||||
},
|
||||
{
|
||||
label: "Deskripsi",
|
||||
value:
|
||||
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Blanditiis asperiores quidem deleniti architecto eaque et nostrum, ad consequuntur eveniet quisquam quae voluptatum ducimus! Dolorem nobis modi officia debitis, beatae mollitia.",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,13 +1,53 @@
|
||||
import { Spacing, StackCustom, ViewWrapper } from "@/components";
|
||||
import {
|
||||
IconPublish,
|
||||
IconReport,
|
||||
} from "@/components/_Icon/IconComponent";
|
||||
import { IconPublish, IconReport } from "@/components/_Icon/IconComponent";
|
||||
import AdminComp_BoxDashboard from "@/components/_ShareComponent/Admin/BoxDashboard";
|
||||
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { apiAdminForum } from "@/service/api-admin/api-admin-forum";
|
||||
import { useFocusEffect } from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export default function AdminForum() {
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
handlerLoadList();
|
||||
}, [])
|
||||
);
|
||||
|
||||
const handlerLoadList = async () => {
|
||||
try {
|
||||
const response = await apiAdminForum({
|
||||
category: "dashboard",
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const listData = [
|
||||
{
|
||||
label: "Posting",
|
||||
value: data?.posting || 0,
|
||||
icon: <IconPublish size={25} color={MainColor.green} />,
|
||||
},
|
||||
{
|
||||
label: "Report Posting",
|
||||
value: data?.reportPosting || 0,
|
||||
icon: <IconReport size={25} color={MainColor.orange} />,
|
||||
},
|
||||
{
|
||||
label: "Report Comment",
|
||||
value: data?.reportComment || 0,
|
||||
icon: <IconReport size={25} color={MainColor.red} />,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper>
|
||||
@@ -22,21 +62,3 @@ export default function AdminForum() {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const listData = [
|
||||
{
|
||||
label: "Posting",
|
||||
value: 4,
|
||||
icon: <IconPublish size={25} color={MainColor.green} />,
|
||||
},
|
||||
{
|
||||
label: "Report Posting",
|
||||
value: 7,
|
||||
icon: <IconReport size={25} color={MainColor.orange} />,
|
||||
},
|
||||
{
|
||||
label: "Report Comment",
|
||||
value: 5,
|
||||
icon: <IconReport size={25} color={MainColor.red} />,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
ActionIcon,
|
||||
BaseBox,
|
||||
LoaderCustom,
|
||||
SearchInput,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
@@ -12,15 +13,47 @@ import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
|
||||
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
|
||||
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import { router } from "expo-router";
|
||||
import React from "react";
|
||||
import { apiAdminForum } from "@/service/api-admin/api-admin-forum";
|
||||
import { router, useFocusEffect } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { Divider } from "react-native-paper";
|
||||
|
||||
export default function AdminForumPosting() {
|
||||
const [list, setList] = useState<any | null>(null);
|
||||
const [loadList, setLoadList] = useState(false);
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
handlerLoadList();
|
||||
}, [search])
|
||||
);
|
||||
|
||||
const handlerLoadList = async () => {
|
||||
try {
|
||||
setLoadList(true);
|
||||
const response = await apiAdminForum({
|
||||
category: "posting",
|
||||
search: search,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setList(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadList(false);
|
||||
}
|
||||
};
|
||||
|
||||
const rightComponent = (
|
||||
<SearchInput
|
||||
containerStyle={{ width: "100%", marginBottom: 0 }}
|
||||
placeholder="Cari"
|
||||
value={search}
|
||||
onChangeText={setSearch}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -28,33 +61,39 @@ export default function AdminForumPosting() {
|
||||
<>
|
||||
<ViewWrapper headerComponent={<AdminTitlePage title="Forum" />}>
|
||||
<AdminComp_BoxTitle title={"Posting"} rightComponent={rightComponent} />
|
||||
<BaseBox>
|
||||
<StackCustom>
|
||||
<AdminTitleTable title1="Aksi" title2="Username" title3="Postingan" />
|
||||
<Spacing />
|
||||
<Divider />
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={<IconView size={ICON_SIZE_BUTTON} color="black" />}
|
||||
onPress={() => {
|
||||
router.push(`/admin/forum/${index + 1}`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={<TextCustom truncate={1}>Username username</TextCustom>}
|
||||
value3={
|
||||
<TextCustom truncate={2}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
Blanditiis asperiores quidem deleniti architecto eaque et
|
||||
nostrum, ad consequuntur eveniet quisquam quae voluptatum
|
||||
ducimus! Dolorem nobis modi officia debitis, beatae mollitia.
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</BaseBox>
|
||||
{loadList ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(list) ? (
|
||||
<TextCustom align="center" color="gray">
|
||||
Belum ada data
|
||||
</TextCustom>
|
||||
) : (
|
||||
list?.map((item: any, index: number) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={<IconView size={ICON_SIZE_BUTTON} color="black" />}
|
||||
onPress={() => {
|
||||
router.push(`/admin/forum/${item?.id}`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={
|
||||
<TextCustom truncate={1}>
|
||||
{item?.Author?.username || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
value3={
|
||||
<TextCustom truncate={2}>{item?.diskusi || "-"}</TextCustom>
|
||||
}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</StackCustom>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
ActionIcon,
|
||||
BaseBox,
|
||||
Divider,
|
||||
LoaderCustom,
|
||||
SearchInput,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
@@ -14,14 +14,48 @@ import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
|
||||
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import { router } from "expo-router";
|
||||
import { apiAdminForum } from "@/service/api-admin/api-admin-forum";
|
||||
import { router, useFocusEffect } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { Divider } from "react-native-paper";
|
||||
|
||||
export default function AdminForumReportComment() {
|
||||
const [listData, setListData] = useState<any[] | null>(null);
|
||||
const [loadList, setLoadList] = useState<boolean>(false);
|
||||
const [search, setSearch] = useState<string>("");
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [search])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadList(true);
|
||||
|
||||
const response = await apiAdminForum({
|
||||
category: "report_comment",
|
||||
search: search,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setListData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadList(false);
|
||||
}
|
||||
};
|
||||
|
||||
const rightComponent = (
|
||||
<SearchInput
|
||||
containerStyle={{ width: "100%", marginBottom: 0 }}
|
||||
placeholder="Cari Komentar"
|
||||
value={search}
|
||||
onChangeText={setSearch}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -29,36 +63,56 @@ export default function AdminForumReportComment() {
|
||||
<>
|
||||
<ViewWrapper headerComponent={<AdminTitlePage title="Forum" />}>
|
||||
<AdminComp_BoxTitle
|
||||
title="Report Comment"
|
||||
title="Report Komentar"
|
||||
rightComponent={rightComponent}
|
||||
/>
|
||||
|
||||
<BaseBox>
|
||||
<AdminTitleTable title1="Aksi" title2="Pelapor" title3="Jenis Laporan" />
|
||||
<Spacing />
|
||||
<StackCustom gap={"sm"}>
|
||||
<AdminTitleTable
|
||||
title1="Aksi"
|
||||
title2="Pelapor"
|
||||
title3="Jenis Laporan"
|
||||
/>
|
||||
<Divider />
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<IconView size={ICON_SIZE_BUTTON} color={MainColor.black} />
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(`/admin/forum/${index + 1}/list-report-comment`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={<TextCustom truncate={1}>Username username</TextCustom>}
|
||||
value3={
|
||||
<TextCustom truncate={2} align="center">
|
||||
SPAM
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</BaseBox>
|
||||
{loadList ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(listData) ? (
|
||||
<TextCustom align="center" color="gray">
|
||||
Belum ada data
|
||||
</TextCustom>
|
||||
) : (
|
||||
listData?.map((item: any, index: number) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<IconView
|
||||
size={ICON_SIZE_BUTTON}
|
||||
color={MainColor.black}
|
||||
/>
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(
|
||||
`/admin/forum/${item?.Forum_Komentar?.id}/list-report-comment`
|
||||
);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={
|
||||
<TextCustom truncate={1}>
|
||||
{item?.User?.username || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
value3={
|
||||
<TextCustom truncate={2} align="center">
|
||||
{item?.ForumMaster_KategoriReport?.title || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</StackCustom>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
ActionIcon,
|
||||
BaseBox,
|
||||
Divider,
|
||||
LoaderCustom,
|
||||
SearchInput,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
ViewWrapper
|
||||
} from "@/components";
|
||||
import { IconView } from "@/components/_Icon/IconComponent";
|
||||
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
|
||||
@@ -15,17 +15,47 @@ import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
|
||||
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import { router } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import { apiAdminForum } from "@/service/api-admin/api-admin-forum";
|
||||
import { router, useFocusEffect } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export default function AdminForumReportPosting() {
|
||||
const [openDrawer, setOpenDrawer] = useState(false);
|
||||
const [id, setId] = useState<any>();
|
||||
const [listData, setListData] = useState<any[] | null>(null);
|
||||
const [loadList, setLoadList] = useState<boolean>(false);
|
||||
const [search, setSearch] = useState<string>("");
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [search])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadList(true);
|
||||
|
||||
const response = await apiAdminForum({
|
||||
category: "report_posting",
|
||||
search: search,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setListData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadList(false);
|
||||
}
|
||||
};
|
||||
|
||||
const rightComponent = (
|
||||
<SearchInput
|
||||
containerStyle={{ width: "100%", marginBottom: 0 }}
|
||||
placeholder="Cari"
|
||||
placeholder="Cari Postingan"
|
||||
value={search}
|
||||
onChangeText={setSearch}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -37,36 +67,49 @@ export default function AdminForumReportPosting() {
|
||||
rightComponent={rightComponent}
|
||||
/>
|
||||
|
||||
<BaseBox>
|
||||
<StackCustom gap={"sm"}>
|
||||
<AdminTitleTable title1="Aksi" title2="Pelapor" title3="Postingan" />
|
||||
<Spacing />
|
||||
|
||||
<Divider />
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<IconView size={ICON_SIZE_BUTTON} color={MainColor.black} />
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(`/admin/forum/${id}/list-report-posting`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={<TextCustom truncate={1}>Username username</TextCustom>}
|
||||
value3={
|
||||
<TextCustom truncate={2} align="center">
|
||||
Lorem, ipsum dolor sit amet consectetur adipisicing elit.
|
||||
Omnis laborum doloremque eius velit voluptate corrupti vel,
|
||||
provident quaerat tempore animi sed accusamus amet.
|
||||
Temporibus, praesentium? Rem voluptatum nesciunt voluptas
|
||||
repellat.
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</BaseBox>
|
||||
{loadList ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(listData) ? (
|
||||
<TextCustom align="center" color="gray">
|
||||
Belum ada data
|
||||
</TextCustom>
|
||||
) : (
|
||||
listData?.map((item: any, index: number) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<IconView
|
||||
size={ICON_SIZE_BUTTON}
|
||||
color={MainColor.black}
|
||||
/>
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(
|
||||
`/admin/forum/${item?.Forum_Posting?.id}/list-report-posting`
|
||||
);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={
|
||||
<TextCustom truncate={1}>
|
||||
{item?.User?.username || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
value3={
|
||||
<TextCustom truncate={2} align="center">
|
||||
{item?.Forum_Posting?.diskusi || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</StackCustom>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
AlertDefaultSystem,
|
||||
BadgeCustom,
|
||||
@@ -7,17 +8,43 @@ import {
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
|
||||
import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview";
|
||||
import ReportBox from "@/components/Box/ReportBox";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import funUpdateStatusJob from "@/screens/Admin/Job/funUpdateStatus";
|
||||
import { apiAdminJobGetById } from "@/service/api-admin/api-admin-job";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminJobDetailStatus() {
|
||||
const { id, status } = useLocalSearchParams();
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiAdminJobGetById({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const colorBadge = () => {
|
||||
if (status === "publish") {
|
||||
@@ -32,11 +59,11 @@ export default function AdminJobDetailStatus() {
|
||||
const listData = [
|
||||
{
|
||||
label: "Username",
|
||||
value: "Bagas Banuna",
|
||||
value: data?.Author?.username || "-",
|
||||
},
|
||||
{
|
||||
label: "Judul",
|
||||
value: `Judul Proyek: ${id}Lorem ipsum dolor sit amet consectetur adipisicing elit.`,
|
||||
value: data?.title || "-",
|
||||
},
|
||||
{
|
||||
label: "Status",
|
||||
@@ -48,24 +75,43 @@ export default function AdminJobDetailStatus() {
|
||||
},
|
||||
{
|
||||
label: "Konten",
|
||||
value: "Lorem ipsum dolor sit amet consectetur adipisicing elit.",
|
||||
value: data?.content || "-",
|
||||
},
|
||||
{
|
||||
label: "Deskripsi",
|
||||
value: "Lorem ipsum dolor sit amet consectetur adipisicing elit.",
|
||||
value: data?.deskripsi || "-",
|
||||
},
|
||||
// {
|
||||
// label: "Poster",
|
||||
// value: (
|
||||
// <ButtonCustom
|
||||
// href={`/(application)/()/${id}`}
|
||||
// >
|
||||
// Lihat Poster
|
||||
// </ButtonCustom>
|
||||
// ),
|
||||
// },
|
||||
];
|
||||
|
||||
const handleUpdate = async ({
|
||||
changeStatus,
|
||||
}: {
|
||||
changeStatus: "publish" | "review" | "reject";
|
||||
}) => {
|
||||
try {
|
||||
const response = await funUpdateStatusJob({
|
||||
id: id as string,
|
||||
changeStatus,
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Gagal mempublikasikan data",
|
||||
});
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Berhasil mempublikasikan data",
|
||||
});
|
||||
|
||||
router.back();
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper
|
||||
@@ -73,8 +119,8 @@ export default function AdminJobDetailStatus() {
|
||||
>
|
||||
<BaseBox>
|
||||
<StackCustom>
|
||||
{listData.map((item, i) => (
|
||||
<Grid key={i}>
|
||||
{listData?.map((item, index) => (
|
||||
<Grid key={index}>
|
||||
<Grid.Col
|
||||
span={4}
|
||||
style={{ justifyContent: "center", paddingRight: 10 }}
|
||||
@@ -87,12 +133,19 @@ export default function AdminJobDetailStatus() {
|
||||
</Grid>
|
||||
))}
|
||||
|
||||
<TextCustom bold>Poster</TextCustom>
|
||||
|
||||
<DummyLandscapeImage />
|
||||
{data && data?.imageId && (
|
||||
<StackCustom>
|
||||
<TextCustom bold>Poster</TextCustom>
|
||||
<DummyLandscapeImage imageId={data?.imageId} />
|
||||
</StackCustom>
|
||||
)}
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
|
||||
{data && data?.catatan && (status === "reject" || status === "review") && (
|
||||
<ReportBox text={data?.catatan}/>
|
||||
)}
|
||||
|
||||
{status === "review" && (
|
||||
<AdminButtonReview
|
||||
onPublish={() => {
|
||||
@@ -101,24 +154,22 @@ export default function AdminJobDetailStatus() {
|
||||
message: "Apakah anda yakin ingin mempublikasikan data ini?",
|
||||
textLeft: "Batal",
|
||||
textRight: "Ya",
|
||||
onPressLeft: () => {
|
||||
router.back();
|
||||
},
|
||||
onPressRight: () => {
|
||||
router.back();
|
||||
handleUpdate({ changeStatus: "publish" });
|
||||
},
|
||||
});
|
||||
}}
|
||||
onReject={() => {
|
||||
router.push(`/admin/job/${id}/reject-input`);
|
||||
router.push(`/admin/job/${id}/${status}/reject-input`);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{status === "reject" && (
|
||||
<AdminButtonReject
|
||||
title="Tambah Catatan"
|
||||
onReject={() => {
|
||||
router.push(`/admin/job/${id}/reject-input`);
|
||||
router.push(`/admin/job/${id}/${status}/reject-input`);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
115
app/(application)/admin/job/[id]/[status]/reject-input.tsx
Normal file
115
app/(application)/admin/job/[id]/[status]/reject-input.tsx
Normal file
@@ -0,0 +1,115 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
AlertDefaultSystem,
|
||||
BoxButtonOnFooter,
|
||||
TextAreaCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
|
||||
import funUpdateStatusJob from "@/screens/Admin/Job/funUpdateStatus";
|
||||
import { apiAdminJobGetById } from "@/service/api-admin/api-admin-job";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminJobRejectInput() {
|
||||
const { id, status } = useLocalSearchParams();
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiAdminJobGetById({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data.catatan);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdate = async ({
|
||||
changeStatus,
|
||||
}: {
|
||||
changeStatus: "publish" | "review" | "reject";
|
||||
}) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await funUpdateStatusJob({
|
||||
id: id as string,
|
||||
changeStatus,
|
||||
data: data,
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Report gagal",
|
||||
});
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Report berhasil",
|
||||
});
|
||||
|
||||
if (status === "review") {
|
||||
router.replace(`/admin/job/reject/status`);
|
||||
} else if (status === "reject") {
|
||||
router.back();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const buttonSubmit = (
|
||||
<BoxButtonOnFooter>
|
||||
<AdminButtonReject
|
||||
isLoading={isLoading}
|
||||
title="Report"
|
||||
onReject={() =>
|
||||
AlertDefaultSystem({
|
||||
title: "Reject",
|
||||
message: "Apakah anda yakin ingin menolak data ini?",
|
||||
textLeft: "Batal",
|
||||
textRight: "Ya",
|
||||
onPressRight: () => {
|
||||
handleUpdate({ changeStatus: "reject" });
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</BoxButtonOnFooter>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper
|
||||
footerComponent={buttonSubmit}
|
||||
headerComponent={<AdminBackButtonAntTitle title="Penolakan Job" />}
|
||||
>
|
||||
<TextAreaCustom
|
||||
value={data}
|
||||
onChangeText={setData}
|
||||
placeholder="Masukan alasan"
|
||||
required
|
||||
showCount
|
||||
maxLength={1000}
|
||||
/>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
import {
|
||||
AlertDefaultSystem,
|
||||
BoxButtonOnFooter,
|
||||
TextAreaCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function AdminJobRejectInput() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [value, setValue] = useState(id as string);
|
||||
const buttonSubmit = (
|
||||
<BoxButtonOnFooter>
|
||||
<AdminButtonReject
|
||||
title="Reject"
|
||||
onReject={() =>
|
||||
AlertDefaultSystem({
|
||||
title: "Reject",
|
||||
message: "Apakah anda yakin ingin menolak data ini?",
|
||||
textLeft: "Batal",
|
||||
textRight: "Ya",
|
||||
onPressLeft: () => {
|
||||
router.back();
|
||||
},
|
||||
onPressRight: () => {
|
||||
console.log("value:", value);
|
||||
router.replace(`/admin/job/reject/status`);
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</BoxButtonOnFooter>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper
|
||||
footerComponent={buttonSubmit}
|
||||
headerComponent={<AdminBackButtonAntTitle title="Penolakan Job" />}
|
||||
>
|
||||
<TextAreaCustom
|
||||
value={value}
|
||||
onChangeText={setValue}
|
||||
placeholder="Masukan alasan"
|
||||
required
|
||||
showCount
|
||||
maxLength={1000}
|
||||
/>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
ActionIcon,
|
||||
BaseBox,
|
||||
LoaderCustom,
|
||||
SearchInput,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper
|
||||
} from "@/components";
|
||||
@@ -11,17 +12,48 @@ import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
|
||||
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
|
||||
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import { apiAdminJob } from "@/service/api-admin/api-admin-job";
|
||||
import { Octicons } from "@expo/vector-icons";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { Divider } from "react-native-paper";
|
||||
|
||||
export default function AdminJobStatus() {
|
||||
const { status } = useLocalSearchParams();
|
||||
const [list, setList] = useState<any | null>(null);
|
||||
const [loadList, setLoadList] = useState(false);
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
handlerLoadList();
|
||||
}, [status, search])
|
||||
);
|
||||
|
||||
const handlerLoadList = async () => {
|
||||
try {
|
||||
setLoadList(true);
|
||||
const response = await apiAdminJob({
|
||||
category: status as "publish" | "review" | "reject",
|
||||
search,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setList(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadList(false);
|
||||
}
|
||||
};
|
||||
|
||||
const rightComponent = (
|
||||
<SearchInput
|
||||
containerStyle={{ width: "100%", marginBottom: 0 }}
|
||||
placeholder="Cari"
|
||||
onChangeText={setSearch}
|
||||
value={search}
|
||||
/>
|
||||
);
|
||||
return (
|
||||
@@ -32,44 +64,53 @@ export default function AdminJobStatus() {
|
||||
rightComponent={rightComponent}
|
||||
/>
|
||||
|
||||
<BaseBox>
|
||||
<StackCustom>
|
||||
<AdminTitleTable
|
||||
title1="Aksi"
|
||||
title2="Username"
|
||||
title3="Judul Pekerjaan"
|
||||
/>
|
||||
<Spacing />
|
||||
{/* <Spacing /> */}
|
||||
<Divider />
|
||||
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<Octicons
|
||||
name="eye"
|
||||
size={ICON_SIZE_BUTTON}
|
||||
color="black"
|
||||
/>
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(`/admin/job/${index}/${status}`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={<TextCustom truncate={1}>Username username</TextCustom>}
|
||||
value3={
|
||||
<TextCustom truncate={2}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
Blanditiis asperiores quidem deleniti architecto eaque et
|
||||
nostrum, ad consequuntur eveniet quisquam quae voluptatum
|
||||
ducimus! Dolorem nobis modi officia debitis, beatae mollitia.
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</BaseBox>
|
||||
{loadList ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(list) ? (
|
||||
<TextCustom align="center" color="gray">
|
||||
Tidak ada data
|
||||
</TextCustom>
|
||||
) : (
|
||||
list?.map((item: any, index: number) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<Octicons
|
||||
name="eye"
|
||||
size={ICON_SIZE_BUTTON}
|
||||
color="black"
|
||||
/>
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(`/admin/job/${item.id}/${status}`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={
|
||||
<TextCustom align="center" truncate={1}>
|
||||
{item?.Author?.username || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
value3={
|
||||
<TextCustom truncate={2} align="center">
|
||||
{item?.title || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</StackCustom>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import { Spacing, StackCustom, ViewWrapper } from "@/components";
|
||||
import {
|
||||
IconPublish,
|
||||
@@ -7,15 +8,45 @@ import {
|
||||
import AdminComp_BoxDashboard from "@/components/_ShareComponent/Admin/BoxDashboard";
|
||||
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { apiAdminJob } from "@/service/api-admin/api-admin-job";
|
||||
import { useFocusEffect } from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export default function AdminJob() {
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
const [loadList, setLoadList] = useState(false);
|
||||
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
handlerLoadList();
|
||||
}, [])
|
||||
);
|
||||
|
||||
const handlerLoadList = async () => {
|
||||
try {
|
||||
setLoadList(true);
|
||||
const response = await apiAdminJob({
|
||||
category: "dashboard",
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadList(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper>
|
||||
<AdminTitlePage title="Job Vacancy" />
|
||||
<Spacing />
|
||||
<StackCustom gap={"xs"}>
|
||||
{listData.map((item, i) => (
|
||||
{listData(data).map((item: any, i: number) => (
|
||||
<AdminComp_BoxDashboard key={i} item={item} />
|
||||
))}
|
||||
</StackCustom>
|
||||
@@ -24,20 +55,20 @@ export default function AdminJob() {
|
||||
);
|
||||
}
|
||||
|
||||
const listData = [
|
||||
const listData = (data: any) => [
|
||||
{
|
||||
label: "Publish",
|
||||
value: 4,
|
||||
value: (data && data?.publish) || 0,
|
||||
icon: <IconPublish size={25} color={MainColor.green} />,
|
||||
},
|
||||
{
|
||||
label: "Review",
|
||||
value: 7,
|
||||
value: (data && data?.review) || 0,
|
||||
icon: <IconReview size={25} color={MainColor.orange} />,
|
||||
},
|
||||
{
|
||||
label: "Reject",
|
||||
value: 5,
|
||||
value: (data && data?.reject) || 0,
|
||||
icon: <IconReject size={25} color={MainColor.red} />,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,102 +1,166 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
AlertDefaultSystem,
|
||||
BadgeCustom,
|
||||
BaseBox,
|
||||
CircleContainer,
|
||||
Grid,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
AlertDefaultSystem,
|
||||
BadgeCustom,
|
||||
BaseBox,
|
||||
CircleContainer,
|
||||
Grid,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
|
||||
import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview";
|
||||
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
|
||||
import ReportBox from "@/components/Box/ReportBox";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import funUpdateStatusVoting from "@/screens/Admin/Voting/funUpdateStatus";
|
||||
import { apiAdminVotingById } from "@/service/api-admin/api-admin-voting";
|
||||
import { colorBadgeStatus } from "@/utils/colorBadge";
|
||||
import { dateTimeView } from "@/utils/dateTimeView";
|
||||
import { Entypo } from "@expo/vector-icons";
|
||||
import dayjs from "dayjs";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { List } from "react-native-paper";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminVotingDetail() {
|
||||
const { id, status } = useLocalSearchParams();
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const colorBadge = () => {
|
||||
if (status === "publish") {
|
||||
return MainColor.green;
|
||||
} else if (status === "review") {
|
||||
return MainColor.orange;
|
||||
} else if (status === "reject") {
|
||||
return MainColor.red;
|
||||
} else {
|
||||
return MainColor.placeholder;
|
||||
console.log("[status]", status);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiAdminVotingById({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const listData = [
|
||||
{
|
||||
label: "Username",
|
||||
value: "Bagas Banuna",
|
||||
value: (data && data?.Author?.username) || "-",
|
||||
},
|
||||
{
|
||||
label: "Judul",
|
||||
value: `Judul Proyek: ${id}Lorem ipsum dolor sit amet consectetur adipisicing elit.`,
|
||||
value: (data && data?.title) || "-",
|
||||
},
|
||||
{
|
||||
label: "Status",
|
||||
value: (
|
||||
<BadgeCustom color={colorBadge()}>
|
||||
{_.startCase(status as string)}
|
||||
</BadgeCustom>
|
||||
),
|
||||
value:
|
||||
data && data?.Voting_Status?.name ? (
|
||||
<BadgeCustom color={colorBadgeStatus({ status: status as string })}>
|
||||
{status === "history" ? "Riwayat" : _.startCase(status as string)}
|
||||
</BadgeCustom>
|
||||
) : (
|
||||
"-"
|
||||
),
|
||||
},
|
||||
{
|
||||
label: "Mulai Voting",
|
||||
value: dayjs().format("DD/MM/YYYY"),
|
||||
value:
|
||||
(data && data?.awalVote && dateTimeView({ date: data?.awalVote })) ||
|
||||
"-",
|
||||
},
|
||||
{
|
||||
label: "Voting Berakhir",
|
||||
value: dayjs().format("DD/MM/YYYY"),
|
||||
value:
|
||||
(data && data?.akhirVote && dateTimeView({ date: data?.akhirVote })) ||
|
||||
"-",
|
||||
},
|
||||
|
||||
{
|
||||
label: "Deskripsi",
|
||||
value: "Lorem ipsum dolor sit amet consectetur adipisicing elit.",
|
||||
value: (data && data?.deskripsi) || "-",
|
||||
},
|
||||
{
|
||||
label: "Daftar Pilhan",
|
||||
value: (
|
||||
<>
|
||||
<List.Item
|
||||
title={<TextCustom>Pilihan 1</TextCustom>}
|
||||
left={(props) => (
|
||||
<List.Icon {...props} icon="circle" color={MainColor.yellow} />
|
||||
)}
|
||||
/>
|
||||
<List.Item
|
||||
title={<TextCustom>Pilihan 2</TextCustom>}
|
||||
left={(props) => (
|
||||
<List.Icon {...props} icon="circle" color={MainColor.yellow} />
|
||||
)}
|
||||
/>
|
||||
<List.Item
|
||||
title={<TextCustom>Pilihan 3</TextCustom>}
|
||||
left={(props) => (
|
||||
<List.Icon {...props} icon="circle" color={MainColor.yellow} />
|
||||
)}
|
||||
/>
|
||||
<List.Item
|
||||
title={<TextCustom>Pilihan 4</TextCustom>}
|
||||
left={(props) => (
|
||||
<List.Icon {...props} icon="circle" color={MainColor.yellow} />
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
),
|
||||
label: "Daftar Pilihan",
|
||||
value:
|
||||
data && data?.Voting_DaftarNamaVote
|
||||
? data?.Voting_DaftarNamaVote?.map((item: any, i: number) => (
|
||||
<List.Item
|
||||
key={i}
|
||||
title={<TextCustom>{item?.value}</TextCustom>}
|
||||
left={(props) => (
|
||||
<Entypo name="chevron-right" color={MainColor.yellow} />
|
||||
)}
|
||||
/>
|
||||
))
|
||||
: "-",
|
||||
},
|
||||
];
|
||||
|
||||
const handleUpdate = async ({
|
||||
changeStatus,
|
||||
}: {
|
||||
changeStatus: "publish" | "review" | "reject";
|
||||
}) => {
|
||||
try {
|
||||
const dateNow = new Date();
|
||||
// const dateNowHour = dateNow.getHours();
|
||||
// const awalVoteHour = dayjs(data?.awalVote).hour();
|
||||
|
||||
const isBefore = dayjs(dateNow).diff(dayjs(data?.awalVote), "hours") < 0;
|
||||
console.log("[IS BEFORE]", isBefore);
|
||||
|
||||
if (!isBefore) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Tanggal & waktu telah lewat",
|
||||
text2: "Silahkan report dan ubah tanggal & waktu voting",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Berhasil mempublikasikan data",
|
||||
});
|
||||
|
||||
setIsLoading(true);
|
||||
const response = await funUpdateStatusVoting({
|
||||
id: id as string,
|
||||
changeStatus,
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Gagal mempublikasikan data",
|
||||
});
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Berhasil mempublikasikan data",
|
||||
});
|
||||
|
||||
router.back();
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper
|
||||
@@ -114,46 +178,59 @@ export default function AdminVotingDetail() {
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
|
||||
{status === "publish" && (
|
||||
<BaseBox>
|
||||
<TextCustom bold align="center">
|
||||
Hasil Voting
|
||||
</TextCustom>
|
||||
<Spacing />
|
||||
<Grid>
|
||||
|
||||
{Array.from({length: 4}).map((_, index) => (
|
||||
<Grid.Col key={index} span={3} style={{ paddingRight: 3, paddingLeft: 3 }}>
|
||||
<StackCustom gap={"sm"}>
|
||||
<CircleContainer value={index % 3 * 3} style={{ alignSelf: "center" }} />
|
||||
<TextCustom size="small" align="center">
|
||||
Pilihan {index + 1}
|
||||
</TextCustom>
|
||||
</StackCustom>
|
||||
</Grid.Col>
|
||||
))}
|
||||
</Grid>
|
||||
</BaseBox>
|
||||
)}
|
||||
{status === "publish" ||
|
||||
(status === "history" && (
|
||||
<BaseBox>
|
||||
<TextCustom bold align="center">
|
||||
Hasil Voting
|
||||
</TextCustom>
|
||||
<Spacing />
|
||||
<Grid>
|
||||
{data?.Voting_DaftarNamaVote?.map(
|
||||
(item: any, index: number) => (
|
||||
<Grid.Col
|
||||
key={index}
|
||||
span={12 / data?.Voting_DaftarNamaVote?.length}
|
||||
style={{ paddingRight: 3, paddingLeft: 3 }}
|
||||
>
|
||||
<StackCustom gap={"sm"}>
|
||||
<CircleContainer
|
||||
value={item?.jumlah}
|
||||
style={{ alignSelf: "center" }}
|
||||
/>
|
||||
<TextCustom size="small" align="center">
|
||||
{item?.value}
|
||||
</TextCustom>
|
||||
</StackCustom>
|
||||
</Grid.Col>
|
||||
)
|
||||
)}
|
||||
</Grid>
|
||||
</BaseBox>
|
||||
))}
|
||||
|
||||
{data &&
|
||||
data?.catatan &&
|
||||
(status === "review" || status === "reject") && (
|
||||
<ReportBox text={data?.catatan} />
|
||||
)}
|
||||
|
||||
{status === "review" && (
|
||||
<AdminButtonReview
|
||||
isLoading={isLoading}
|
||||
onPublish={() => {
|
||||
AlertDefaultSystem({
|
||||
title: "Publish",
|
||||
message: "Apakah anda yakin ingin mempublikasikan data ini?",
|
||||
textLeft: "Cancel",
|
||||
textRight: "Publish",
|
||||
onPressLeft: () => {
|
||||
router.back();
|
||||
},
|
||||
onPressRight: () => {
|
||||
router.back();
|
||||
handleUpdate({ changeStatus: "publish" });
|
||||
},
|
||||
});
|
||||
}}
|
||||
onReject={() => {
|
||||
router.push(`/admin/voting/${id}/reject-input`);
|
||||
router.push(`/admin/voting/${id}/${status}/reject-input`);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -162,7 +239,7 @@ export default function AdminVotingDetail() {
|
||||
<AdminButtonReject
|
||||
title="Tambah Catatan"
|
||||
onReject={() => {
|
||||
router.push(`/admin/voting/${id}/reject-input`);
|
||||
router.push(`/admin/voting/${id}/${status}/reject-input`);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
113
app/(application)/admin/voting/[id]/[status]/reject-input.tsx
Normal file
113
app/(application)/admin/voting/[id]/[status]/reject-input.tsx
Normal file
@@ -0,0 +1,113 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
AlertDefaultSystem,
|
||||
BoxButtonOnFooter,
|
||||
TextAreaCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
|
||||
import funUpdateStatusVoting from "@/screens/Admin/Voting/funUpdateStatus";
|
||||
import { apiAdminVotingById } from "@/service/api-admin/api-admin-voting";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminVotingRejectInput() {
|
||||
const { id, status } = useLocalSearchParams();
|
||||
const [data, setData] = useState("");
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiAdminVotingById({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data.catatan);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdate = async ({
|
||||
changeStatus,
|
||||
}: {
|
||||
changeStatus: "publish" | "review" | "reject";
|
||||
}) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await funUpdateStatusVoting({
|
||||
id: id as string,
|
||||
changeStatus,
|
||||
data: data,
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Report gagal",
|
||||
});
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Report berhasil",
|
||||
});
|
||||
|
||||
if (status === "review") {
|
||||
router.replace(`/admin/voting/reject/status`);
|
||||
} else if (status === "reject") {
|
||||
router.back();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const buttonSubmit = (
|
||||
<BoxButtonOnFooter>
|
||||
<AdminButtonReject
|
||||
title="Reject"
|
||||
isLoading={isLoading}
|
||||
onReject={() =>
|
||||
AlertDefaultSystem({
|
||||
title: "Reject",
|
||||
message: "Apakah anda yakin ingin menolak data ini?",
|
||||
textLeft: "Batal",
|
||||
textRight: "Ya",
|
||||
onPressRight: () => handleUpdate({ changeStatus: "reject" }),
|
||||
})
|
||||
}
|
||||
/>
|
||||
</BoxButtonOnFooter>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper
|
||||
footerComponent={buttonSubmit}
|
||||
headerComponent={<AdminBackButtonAntTitle title="Penolakan Voting" />}
|
||||
>
|
||||
<TextAreaCustom
|
||||
value={data}
|
||||
onChangeText={setData}
|
||||
placeholder="Masukan alasan"
|
||||
required
|
||||
showCount
|
||||
maxLength={1000}
|
||||
/>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
import {
|
||||
AlertDefaultSystem,
|
||||
BoxButtonOnFooter,
|
||||
TextAreaCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function AdminVotingRejectInput() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [value, setValue] = useState(id as string);
|
||||
const buttonSubmit = (
|
||||
<BoxButtonOnFooter>
|
||||
<AdminButtonReject
|
||||
title="Reject"
|
||||
onReject={() =>
|
||||
AlertDefaultSystem({
|
||||
title: "Reject",
|
||||
message: "Apakah anda yakin ingin menolak data ini?",
|
||||
textLeft: "Batal",
|
||||
textRight: "Ya",
|
||||
onPressLeft: () => {
|
||||
router.back();
|
||||
},
|
||||
onPressRight: () => {
|
||||
console.log("value:", value);
|
||||
router.replace(`/admin/voting/reject/status`);
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</BoxButtonOnFooter>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper
|
||||
footerComponent={buttonSubmit}
|
||||
headerComponent={<AdminBackButtonAntTitle title="Penolakan Voting" />}
|
||||
>
|
||||
<TextAreaCustom
|
||||
value={value}
|
||||
onChangeText={setValue}
|
||||
placeholder="Masukan alasan"
|
||||
required
|
||||
showCount
|
||||
maxLength={1000}
|
||||
/>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,27 +1,60 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
ActionIcon,
|
||||
BaseBox,
|
||||
SearchInput,
|
||||
Spacing,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
ActionIcon,
|
||||
LoaderCustom,
|
||||
SearchInput,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
|
||||
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
|
||||
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
|
||||
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import { apiAdminVoting } from "@/service/api-admin/api-admin-voting";
|
||||
import { Octicons } from "@expo/vector-icons";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { Divider } from "react-native-paper";
|
||||
|
||||
export default function AdminVotingStatus() {
|
||||
const { status } = useLocalSearchParams();
|
||||
const [list, setList] = useState<any | null>(null);
|
||||
const [loadList, setLoadList] = useState(false);
|
||||
const [search, setSearch] = useState<string>("");
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [status, search])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadList(true);
|
||||
const response = await apiAdminVoting({
|
||||
category: status as "publish" | "review" | "reject" as any,
|
||||
search,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setList(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadList(false);
|
||||
}
|
||||
};
|
||||
|
||||
const rightComponent = (
|
||||
<SearchInput
|
||||
containerStyle={{ width: "100%", marginBottom: 0 }}
|
||||
placeholder="Cari"
|
||||
value={search}
|
||||
onChangeText={setSearch}
|
||||
/>
|
||||
);
|
||||
return (
|
||||
@@ -32,44 +65,52 @@ export default function AdminVotingStatus() {
|
||||
rightComponent={rightComponent}
|
||||
/>
|
||||
|
||||
<BaseBox>
|
||||
<StackCustom gap={"sm"}>
|
||||
<AdminTitleTable
|
||||
title1="Aksi"
|
||||
title2="Username"
|
||||
title3="Judul Voting"
|
||||
/>
|
||||
<Spacing />
|
||||
<Divider />
|
||||
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<AdminTableValue
|
||||
key={index}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<Octicons
|
||||
name="eye"
|
||||
size={ICON_SIZE_BUTTON}
|
||||
color="black"
|
||||
/>
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(`/admin/voting/${index}/${status}`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={<TextCustom truncate={1}>Username username</TextCustom>}
|
||||
value3={
|
||||
<TextCustom truncate={2}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
Blanditiis asperiores quidem deleniti architecto eaque et
|
||||
nostrum, ad consequuntur eveniet quisquam quae voluptatum
|
||||
ducimus! Dolorem nobis modi officia debitis, beatae mollitia.
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</BaseBox>
|
||||
{loadList ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(list) ? (
|
||||
<TextCustom align="center" bold color="gray">
|
||||
Belum ada data
|
||||
</TextCustom>
|
||||
) : (
|
||||
list.map((item: any, i: number) => (
|
||||
<AdminTableValue
|
||||
key={i}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<Octicons
|
||||
name="eye"
|
||||
size={ICON_SIZE_BUTTON}
|
||||
color="black"
|
||||
/>
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(`/admin/voting/${item.id}/${status}`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={
|
||||
<TextCustom truncate={1}>
|
||||
{item?.Author?.username || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
value3={
|
||||
<TextCustom align="center" truncate={2}>
|
||||
{item?.title || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</StackCustom>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
|
||||
104
app/(application)/admin/voting/history.tsx
Normal file
104
app/(application)/admin/voting/history.tsx
Normal file
@@ -0,0 +1,104 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
ActionIcon,
|
||||
LoaderCustom,
|
||||
SearchInput,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper
|
||||
} from "@/components";
|
||||
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
|
||||
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
|
||||
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
|
||||
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import { apiAdminVoting } from "@/service/api-admin/api-admin-voting";
|
||||
import { Octicons } from "@expo/vector-icons";
|
||||
import { router, useFocusEffect } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { Divider } from "react-native-paper";
|
||||
|
||||
export default function AdminVotingHistory() {
|
||||
const [list, setList] = useState<any | null>(null);
|
||||
const [loadList, setLoadList] = useState(false);
|
||||
const [search, setSearch] = useState<string>("");
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [ search])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadList(true);
|
||||
const response = await apiAdminVoting({
|
||||
category: "history",
|
||||
search,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setList(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadList(false);
|
||||
}
|
||||
};
|
||||
|
||||
const rightComponent = (
|
||||
<SearchInput
|
||||
containerStyle={{ width: "100%", marginBottom: 0 }}
|
||||
placeholder="Cari"
|
||||
value={search}
|
||||
onChangeText={setSearch}
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper headerComponent={<AdminTitlePage title="Voting" />}>
|
||||
<AdminComp_BoxTitle
|
||||
title="Riwayat"
|
||||
rightComponent={rightComponent}
|
||||
/>
|
||||
|
||||
<StackCustom gap={"sm"}>
|
||||
<AdminTitleTable
|
||||
title1="Aksi"
|
||||
title2="Username"
|
||||
title3="Judul Voting"
|
||||
/>
|
||||
<Divider />
|
||||
|
||||
{loadList ? <LoaderCustom/> : _.isEmpty(list) ? <TextCustom align="center" bold color="gray">Belum ada data</TextCustom> : list.map((item: any, i: number) => (
|
||||
<AdminTableValue
|
||||
key={i}
|
||||
value1={
|
||||
<ActionIcon
|
||||
icon={
|
||||
<Octicons
|
||||
name="eye"
|
||||
size={ICON_SIZE_BUTTON}
|
||||
color="black"
|
||||
/>
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(`/admin/voting/${item.id}/history`);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
value2={<TextCustom truncate={1}>{item?.Author?.username || "-"}</TextCustom>}
|
||||
value3={
|
||||
<TextCustom align="center" truncate={2}>
|
||||
{item?.title || "-"}
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</StackCustom>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -8,8 +8,56 @@ import {
|
||||
import AdminComp_BoxDashboard from "@/components/_ShareComponent/Admin/BoxDashboard";
|
||||
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { apiAdminVoting } from "@/service/api-admin/api-admin-voting";
|
||||
import { useFocusEffect } from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export default function AdminVoting() {
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiAdminVoting({
|
||||
category: "dashboard",
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const listData = [
|
||||
{
|
||||
label: "Publish",
|
||||
value: (data && data?.publish) || 0,
|
||||
icon: <IconPublish size={25} color={MainColor.green} />,
|
||||
},
|
||||
{
|
||||
label: "Review",
|
||||
value: (data && data?.review) || 0,
|
||||
icon: <IconReview size={25} color={MainColor.orange} />,
|
||||
},
|
||||
{
|
||||
label: "Reject",
|
||||
value: (data && data?.reject) || 0,
|
||||
icon: <IconReject size={25} color={MainColor.red} />,
|
||||
},
|
||||
{
|
||||
label: "Riwayat",
|
||||
value: (data && data?.history) || 0,
|
||||
icon: <IconArchive size={25} color={MainColor.white_gray} />,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper>
|
||||
@@ -24,26 +72,3 @@ export default function AdminVoting() {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const listData = [
|
||||
{
|
||||
label: "Publish",
|
||||
value: 4,
|
||||
icon: <IconPublish size={25} color={MainColor.green} />,
|
||||
},
|
||||
{
|
||||
label: "Review",
|
||||
value: 7,
|
||||
icon: <IconReview size={25} color={MainColor.orange} />,
|
||||
},
|
||||
{
|
||||
label: "Reject",
|
||||
value: 5,
|
||||
icon: <IconReject size={25} color={MainColor.red} />,
|
||||
},
|
||||
{
|
||||
label: "Riwayat",
|
||||
value: 5,
|
||||
icon: <IconArchive size={25} color={MainColor.white_gray} />,
|
||||
},
|
||||
];
|
||||
|
||||
3
bun.lock
3
bun.lock
@@ -17,7 +17,6 @@
|
||||
"axios": "^1.11.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"expo": "^54.0.0",
|
||||
"expo-blur": "~15.0.7",
|
||||
"expo-camera": "~17.0.7",
|
||||
"expo-clipboard": "~8.0.7",
|
||||
"expo-constants": "~18.0.8",
|
||||
@@ -1153,8 +1152,6 @@
|
||||
|
||||
"expo-asset": ["expo-asset@12.0.8", "", { "dependencies": { "@expo/image-utils": "^0.8.7", "expo-constants": "~18.0.8" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-jj2U8zw9+7orST2rlQGULYiqPoECOuUyffs2NguGrq84bYbkM041T7TOMXH2raPVJnM9lEAP54ezI6XL+GVYqw=="],
|
||||
|
||||
"expo-blur": ["expo-blur@15.0.7", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-SugQQbQd+zRPy8z2G5qDD4NqhcD7srBF7fN7O7yq6q7ZFK59VWvpDxtMoUkmSfdxgqONsrBN/rLdk00USADrMg=="],
|
||||
|
||||
"expo-camera": ["expo-camera@17.0.7", "", { "dependencies": { "invariant": "^2.2.4" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*", "react-native-web": "*" }, "optionalPeers": ["react-native-web"] }, "sha512-jdZfijfFjlVAuuIkDheA41YKpigPjqsN0juRvgyr7Lcyz+fvwZ3/RP50/n/hvuozH657wHxPfiyVVFa00z8TcQ=="],
|
||||
|
||||
"expo-clipboard": ["expo-clipboard@8.0.7", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-zvlfFV+wB2QQrQnHWlo0EKHAkdi2tycLtE+EXFUWTPZYkgu1XcH+aiKfd4ul7Z0SDF+1IuwoiW9AA9eO35aj3Q=="],
|
||||
|
||||
16
components/Box/ReportBox.tsx
Normal file
16
components/Box/ReportBox.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import StackCustom from "../Stack/StackCustom";
|
||||
import TextCustom from "../Text/TextCustom";
|
||||
import BaseBox from "./BaseBox";
|
||||
|
||||
export default function ReportBox({ text }: { text: string }) {
|
||||
return (
|
||||
<BaseBox>
|
||||
<StackCustom gap={"sm"}>
|
||||
<TextCustom bold>
|
||||
Catatan penolakan
|
||||
</TextCustom>
|
||||
<TextCustom>{text}</TextCustom>
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
);
|
||||
}
|
||||
@@ -1,27 +1,39 @@
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import React from "react";
|
||||
import { StyleProp, StyleSheet, TextInput, View, ViewStyle } from "react-native";
|
||||
import {
|
||||
StyleProp,
|
||||
StyleSheet,
|
||||
View,
|
||||
ViewStyle
|
||||
} from "react-native";
|
||||
import TextCustom from "../Text/TextCustom";
|
||||
|
||||
interface CircularInputProps {
|
||||
value?: string | number
|
||||
value?: string | number;
|
||||
onChange?: (value: string | number) => void;
|
||||
icon?: React.ReactNode;
|
||||
style?: StyleProp<ViewStyle>
|
||||
style?: StyleProp<ViewStyle>;
|
||||
}
|
||||
|
||||
const CircularInput: React.FC<CircularInputProps> = ({ value, onChange, icon, style }) => {
|
||||
const CircularInput: React.FC<CircularInputProps> = ({
|
||||
value,
|
||||
onChange,
|
||||
icon,
|
||||
style,
|
||||
}) => {
|
||||
return (
|
||||
<View style={[styles.circleContainer, style]}>
|
||||
{icon ? (
|
||||
icon
|
||||
) : (
|
||||
<TextInput
|
||||
value={String(value)}
|
||||
onChangeText={onChange}
|
||||
<TextCustom
|
||||
// text={String(value)}
|
||||
style={styles.input}
|
||||
keyboardType="numeric"
|
||||
maxLength={2} // Batasan maksimal karakter
|
||||
/>
|
||||
// keyboardType="numeric"
|
||||
// maxLength={2} // Batasan maksimal karakter
|
||||
>
|
||||
{value}
|
||||
</TextCustom>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
@@ -39,7 +51,7 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
input: {
|
||||
color: MainColor.yellow, // Warna kuning
|
||||
fontSize: 24,
|
||||
fontSize: 18,
|
||||
fontWeight: "bold",
|
||||
textAlign: "center",
|
||||
padding: 0,
|
||||
|
||||
@@ -196,6 +196,7 @@ const DateTimeInput_Android: React.FC<DateTimeInputProps> = ({
|
||||
onChange={handleConfirmTime}
|
||||
minimumDate={minimumDate}
|
||||
maximumDate={maximumDate}
|
||||
themeVariant="light"
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -145,6 +145,7 @@ const DateTimeInput_IOS: React.FC<DateTimeInputProps> = ({
|
||||
onChange={handleConfirm}
|
||||
minimumDate={minimumDate}
|
||||
maximumDate={maximumDate}
|
||||
themeVariant="light"
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
|
||||
@@ -27,6 +27,8 @@ type SelectProps = {
|
||||
onChange: (value: string | number) => void;
|
||||
borderRadius?: number;
|
||||
styleContainer?: StyleProp<ViewStyle>;
|
||||
allowClear?: boolean; // <-- new prop
|
||||
clearLabel?: string; // default: "Kosongkan"
|
||||
};
|
||||
|
||||
const SelectCustom: React.FC<SelectProps> = ({
|
||||
@@ -39,13 +41,21 @@ const SelectCustom: React.FC<SelectProps> = ({
|
||||
onChange,
|
||||
borderRadius = 8,
|
||||
styleContainer,
|
||||
allowClear = true, // bisa dimatikan jika tidak perlu
|
||||
clearLabel = "Hapus Pilihan",
|
||||
}) => {
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
|
||||
const selectedItem = data.find((item) => item.value === value);
|
||||
|
||||
const hasError = required && value === null; // <-- check if empty and required
|
||||
|
||||
// Gabungkan opsi clear di atas daftar
|
||||
const renderData = allowClear
|
||||
? [...data,
|
||||
// { label: clearLabel, value: "__clear__" }
|
||||
]
|
||||
: data;
|
||||
|
||||
return (
|
||||
<View style={[GStyles.inputContainerArea, styleContainer]}>
|
||||
{label && (
|
||||
@@ -54,29 +64,64 @@ const SelectCustom: React.FC<SelectProps> = ({
|
||||
{required && <Text style={GStyles.inputRequired}> *</Text>}
|
||||
</Text>
|
||||
)}
|
||||
<Pressable
|
||||
|
||||
{/* Input Container */}
|
||||
<View
|
||||
style={[
|
||||
{ borderRadius, },
|
||||
hasError ? GStyles.inputErrorBorder : null,
|
||||
{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
// backgroundColor: "red",
|
||||
// flex: 1,
|
||||
borderRadius,
|
||||
},
|
||||
GStyles.inputContainerInput,
|
||||
hasError ? GStyles.inputErrorBorder : null,
|
||||
disabled && GStyles.disabledBox,
|
||||
]} // <-- add error style
|
||||
onPress={() => !disabled && setModalVisible(true)}
|
||||
]}
|
||||
>
|
||||
<Text
|
||||
style={
|
||||
selectedItem
|
||||
? disabled
|
||||
? GStyles.inputTextDisabled
|
||||
: GStyles.inputText
|
||||
: disabled
|
||||
? GStyles.inputPlaceholderDisabled
|
||||
: GStyles.inputPlaceholder
|
||||
}
|
||||
<Pressable
|
||||
style={[
|
||||
{
|
||||
flex: 1,
|
||||
borderRadius,
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 10,
|
||||
height: 50,
|
||||
},
|
||||
|
||||
// GStyles.inputContainerInput,
|
||||
// hasError ? GStyles.inputErrorBorder : null,
|
||||
// disabled && GStyles.disabledBox,
|
||||
]}
|
||||
onPress={() => !disabled && setModalVisible(true)}
|
||||
>
|
||||
{selectedItem?.label || placeholder}
|
||||
</Text>
|
||||
</Pressable>
|
||||
<Text
|
||||
style={
|
||||
selectedItem
|
||||
? disabled
|
||||
? GStyles.inputTextDisabled
|
||||
: GStyles.inputText
|
||||
: disabled
|
||||
? GStyles.inputPlaceholderDisabled
|
||||
: GStyles.inputPlaceholder
|
||||
}
|
||||
>
|
||||
{selectedItem?.label || placeholder}
|
||||
</Text>
|
||||
</Pressable>
|
||||
|
||||
{/* Tombol Clear (Hanya muncul jika ada nilai terpilih & allowClear aktif) */}
|
||||
{!disabled && allowClear && value !== null && value !== undefined && (
|
||||
<TouchableOpacity
|
||||
style={{ paddingHorizontal: 10 }}
|
||||
onPress={() => onChange(null as any)} // null dikirim sebagai value
|
||||
>
|
||||
<Text style={{ fontSize: 18, color: "#999" }}>×</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<Modal visible={modalVisible} transparent animationType="fade">
|
||||
<TouchableOpacity
|
||||
@@ -86,19 +131,38 @@ const SelectCustom: React.FC<SelectProps> = ({
|
||||
>
|
||||
<View style={GStyles.selectModalContent}>
|
||||
<FlatList
|
||||
data={data}
|
||||
data={renderData}
|
||||
keyExtractor={(item) => String(item.value)}
|
||||
renderItem={({ item }) => (
|
||||
<TouchableOpacity
|
||||
style={GStyles.selectOption}
|
||||
onPress={() => {
|
||||
onChange(item.value);
|
||||
setModalVisible(false);
|
||||
}}
|
||||
>
|
||||
<Text>{item.label}</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
renderItem={({ item }) => {
|
||||
if (item.value === "__clear__") {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
GStyles.selectOption,
|
||||
{ backgroundColor: "#fdd" },
|
||||
]}
|
||||
onPress={() => {
|
||||
onChange(null as any); // kosongkan nilai
|
||||
setModalVisible(false);
|
||||
}}
|
||||
>
|
||||
<Text>{item.label}</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={GStyles.selectOption}
|
||||
onPress={() => {
|
||||
onChange(item.value);
|
||||
setModalVisible(false);
|
||||
}}
|
||||
>
|
||||
<Text>{item.label}</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
|
||||
@@ -23,7 +23,7 @@ interface TextCustomProps {
|
||||
bold?: boolean;
|
||||
semiBold?: boolean;
|
||||
size?: "default" | "large" | "small" | "xlarge" | number
|
||||
color?: "default" | "yellow" | "red" | "gray" | "green" | "black"
|
||||
color?: "default" | "yellow" | "red" | "gray" | "green" | "black" | "orange"
|
||||
align?: TextAlign; // Prop untuk alignment
|
||||
truncate?: boolean | number;
|
||||
onPress?: () => void;
|
||||
@@ -62,6 +62,7 @@ const TextCustom: React.FC<TextCustomProps> = ({
|
||||
else if (color === "gray") selectedStyles.push(styles.gray);
|
||||
else if (color === "green") selectedStyles.push(styles.green);
|
||||
else if (color === "black") selectedStyles.push(styles.black);
|
||||
else if (color === "orange") selectedStyles.push(styles.orange);
|
||||
|
||||
// Alignment
|
||||
if (align) {
|
||||
@@ -140,4 +141,7 @@ export const styles = StyleSheet.create({
|
||||
black: {
|
||||
color: MainColor.black,
|
||||
},
|
||||
orange: {
|
||||
color: MainColor.orange,
|
||||
},
|
||||
});
|
||||
|
||||
27
components/_Icon/IconOpenTo.tsx
Normal file
27
components/_Icon/IconOpenTo.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { ICON_SIZE_XLARGE } from "@/constants/constans-value";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import React from "react";
|
||||
|
||||
export { IconOpenTo };
|
||||
|
||||
function IconOpenTo({
|
||||
color,
|
||||
size,
|
||||
onPress,
|
||||
}: {
|
||||
color?: string;
|
||||
size?: number;
|
||||
onPress?: () => void;
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<Ionicons
|
||||
onPress={onPress}
|
||||
name="open"
|
||||
size={size || ICON_SIZE_XLARGE}
|
||||
color={color || MainColor.yellow}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -5,17 +5,20 @@ import { MainColor } from "@/constants/color-palet";
|
||||
export default function AdminButtonReject({
|
||||
title,
|
||||
onReject,
|
||||
isLoading,
|
||||
}: {
|
||||
title: string;
|
||||
onReject: () => void;
|
||||
isLoading?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<ButtonCustom
|
||||
iconLeft={<IconReject />}
|
||||
iconLeft={<IconReject size={16} />}
|
||||
backgroundColor={MainColor.red}
|
||||
textColor="white"
|
||||
onPress={onReject}
|
||||
isLoading={isLoading}
|
||||
>
|
||||
{title}
|
||||
</ButtonCustom>
|
||||
|
||||
@@ -4,9 +4,11 @@ import Grid from "@/components/Grid/GridCustom";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
|
||||
export default function AdminButtonReview({
|
||||
isLoading,
|
||||
onPublish,
|
||||
onReject,
|
||||
}: {
|
||||
isLoading?: boolean;
|
||||
onPublish: () => void;
|
||||
onReject: () => void;
|
||||
}) {
|
||||
@@ -15,6 +17,7 @@ export default function AdminButtonReview({
|
||||
<Grid>
|
||||
<Grid.Col span={6} style={{ paddingRight: 10 }}>
|
||||
<ButtonCustom
|
||||
isLoading={isLoading}
|
||||
iconLeft={<IconPublish />}
|
||||
backgroundColor={MainColor.green}
|
||||
textColor="white"
|
||||
|
||||
@@ -7,10 +7,12 @@ export default function AdminTableValue({
|
||||
value1,
|
||||
value2,
|
||||
value3,
|
||||
bottomLine = false,
|
||||
}: {
|
||||
value1: React.ReactNode;
|
||||
value2: React.ReactNode;
|
||||
value3: React.ReactNode;
|
||||
bottomLine?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
@@ -50,7 +52,7 @@ export default function AdminTableValue({
|
||||
{value3}
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<Divider />
|
||||
{bottomLine && <Divider />}
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { MainColor } from "@/constants/color-palet";
|
||||
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
||||
import TextInputCustom from "../TextInput/TextInputCustom";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { StyleProp, ViewStyle, TextStyle } from "react-native";
|
||||
import { StyleProp, ViewStyle, TextStyle, StyleSheet } from "react-native";
|
||||
|
||||
interface SearchInputProps {
|
||||
placeholder?: string;
|
||||
@@ -12,6 +12,8 @@ interface SearchInputProps {
|
||||
containerStyle?: StyleProp<ViewStyle>;
|
||||
style?: StyleProp<TextStyle>;
|
||||
onChangeText?: (value: string) => void;
|
||||
value?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
export default function SearchInput({
|
||||
placeholder,
|
||||
@@ -21,6 +23,8 @@ export default function SearchInput({
|
||||
containerStyle,
|
||||
style,
|
||||
onChangeText,
|
||||
value,
|
||||
disabled,
|
||||
...props
|
||||
}: SearchInputProps) {
|
||||
return (
|
||||
@@ -29,14 +33,21 @@ export default function SearchInput({
|
||||
<Ionicons
|
||||
name="search-outline"
|
||||
size={ICON_SIZE_SMALL}
|
||||
color={MainColor.placeholder}
|
||||
color={disabled ? MainColor.white_gray : MainColor.placeholder}
|
||||
/>
|
||||
}
|
||||
value={value}
|
||||
onChangeText={onChangeText}
|
||||
placeholder={placeholder}
|
||||
borderRadius={50}
|
||||
containerStyle={[containerStyle, { marginBottom: 0 }]}
|
||||
containerStyle={[disabled ? styleses.disabled : styleses.containerStyle]}
|
||||
disabled={disabled}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const styleses = StyleSheet.create({
|
||||
containerStyle: { width: "100%", marginBottom: 0 },
|
||||
disabled: { width: "100%", marginBottom: 0, color: MainColor.white_gray },
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
StyleProp,
|
||||
ViewStyle,
|
||||
} from "react-native";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
import { NativeSafeAreaViewProps, SafeAreaView } from "react-native-safe-area-context";
|
||||
|
||||
interface ViewWrapperProps {
|
||||
children: React.ReactNode;
|
||||
@@ -21,6 +21,7 @@ interface ViewWrapperProps {
|
||||
footerComponent?: React.ReactNode;
|
||||
floatingButton?: React.ReactNode;
|
||||
hideFooter?: boolean;
|
||||
edgesFooter?: NativeSafeAreaViewProps["edges"];
|
||||
style?: StyleProp<ViewStyle>;
|
||||
}
|
||||
|
||||
@@ -37,6 +38,7 @@ const ViewWrapper = ({
|
||||
footerComponent,
|
||||
floatingButton,
|
||||
hideFooter = false,
|
||||
edgesFooter =[],
|
||||
style,
|
||||
}: ViewWrapperProps) => {
|
||||
const assetBackground = require("../../assets/images/main-background.png");
|
||||
@@ -77,7 +79,7 @@ const ViewWrapper = ({
|
||||
|
||||
{footerComponent ? (
|
||||
<SafeAreaView
|
||||
edges={["bottom"]}
|
||||
edges={Platform.OS === "ios" ? edgesFooter : ["bottom"]}
|
||||
style={{
|
||||
backgroundColor: MainColor.darkblue,
|
||||
height: OS_HEIGHT
|
||||
|
||||
@@ -23,7 +23,7 @@ export {
|
||||
|
||||
// OS Height
|
||||
const OS_ANDROID_HEIGHT = 115
|
||||
const OS_IOS_HEIGHT = 65
|
||||
const OS_IOS_HEIGHT = 70
|
||||
const OS_HEIGHT = Platform.OS === "ios" ? OS_IOS_HEIGHT : OS_ANDROID_HEIGHT
|
||||
|
||||
// Text Size
|
||||
|
||||
@@ -91,14 +91,11 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
setToken(token);
|
||||
await AsyncStorage.setItem("authToken", token);
|
||||
|
||||
const responseUser = await apiConfig.get(
|
||||
`/mobile?token=${token}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
const responseUser = await apiConfig.get(`/mobile?token=${token}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
const dataUser = responseUser.data.data;
|
||||
|
||||
setUser(dataUser);
|
||||
@@ -147,9 +144,7 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
await AsyncStorage.setItem("userData", JSON.stringify(dataUser));
|
||||
return dataUser;
|
||||
} catch (error: any) {
|
||||
throw new Error(
|
||||
error.response?.data?.message || "Gagal mengambil data user"
|
||||
);
|
||||
console.log(error.response?.data?.message + "user" || "Gagal mengambil data user");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
||||
8
index.js
Normal file
8
index.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import { registerRootComponent } from 'expo';
|
||||
|
||||
import App from './App';
|
||||
|
||||
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
|
||||
// It also ensures that whether you load the app in Expo Go or in a native build,
|
||||
// the environment is set up appropriately
|
||||
registerRootComponent(App);
|
||||
@@ -9,25 +9,17 @@
|
||||
/* Begin PBXBuildFile section */
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; };
|
||||
3E483D87269347231471F774 /* libPods-HIPMIBADUNG.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 10F5AA024C601F56B4EEA12E /* libPods-HIPMIBADUNG.a */; };
|
||||
3E9DE75169D0FBDB1B473165 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = F0C0055A487C52DF43B9AA8C /* PrivacyInfo.xcprivacy */; };
|
||||
BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; };
|
||||
E3BE778B8B6E53CE5D518808 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A445166333AB51CC299A7683 /* ExpoModulesProvider.swift */; };
|
||||
F11748422D0307B40044C1D9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F11748412D0307B40044C1D9 /* AppDelegate.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
10F5AA024C601F56B4EEA12E /* libPods-HIPMIBADUNG.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HIPMIBADUNG.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
13B07F961A680F5B00A75B9A /* HIPMIBADUNG.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HIPMIBADUNG.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = HIPMIBADUNG/Images.xcassets; sourceTree = "<group>"; };
|
||||
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = HIPMIBADUNG/Info.plist; sourceTree = "<group>"; };
|
||||
43EA3CD4BD89A00F8AB4791D /* Pods-HIPMIBADUNG.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HIPMIBADUNG.release.xcconfig"; path = "Target Support Files/Pods-HIPMIBADUNG/Pods-HIPMIBADUNG.release.xcconfig"; sourceTree = "<group>"; };
|
||||
7355472C9F7484C7F5780400 /* Pods-HIPMIBADUNG.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HIPMIBADUNG.debug.xcconfig"; path = "Target Support Files/Pods-HIPMIBADUNG/Pods-HIPMIBADUNG.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
A445166333AB51CC299A7683 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-HIPMIBADUNG/ExpoModulesProvider.swift"; sourceTree = "<group>"; };
|
||||
AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = HIPMIBADUNG/SplashScreen.storyboard; sourceTree = "<group>"; };
|
||||
BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = "<group>"; };
|
||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
|
||||
F0C0055A487C52DF43B9AA8C /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = HIPMIBADUNG/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
F11748412D0307B40044C1D9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = HIPMIBADUNG/AppDelegate.swift; sourceTree = "<group>"; };
|
||||
F11748442D0722820044C1D9 /* HIPMIBADUNG-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "HIPMIBADUNG-Bridging-Header.h"; path = "HIPMIBADUNG/HIPMIBADUNG-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
@@ -37,7 +29,6 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3E483D87269347231471F774 /* libPods-HIPMIBADUNG.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -53,7 +44,6 @@
|
||||
13B07FB51A68108700A75B9A /* Images.xcassets */,
|
||||
13B07FB61A68108700A75B9A /* Info.plist */,
|
||||
AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */,
|
||||
F0C0055A487C52DF43B9AA8C /* PrivacyInfo.xcprivacy */,
|
||||
);
|
||||
name = HIPMIBADUNG;
|
||||
sourceTree = "<group>";
|
||||
@@ -62,28 +52,10 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
|
||||
10F5AA024C601F56B4EEA12E /* libPods-HIPMIBADUNG.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
523B30FE431343BE096F5C21 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7355472C9F7484C7F5780400 /* Pods-HIPMIBADUNG.debug.xcconfig */,
|
||||
43EA3CD4BD89A00F8AB4791D /* Pods-HIPMIBADUNG.release.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7E80613205F5353A90501151 /* HIPMIBADUNG */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A445166333AB51CC299A7683 /* ExpoModulesProvider.swift */,
|
||||
);
|
||||
name = HIPMIBADUNG;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -98,8 +70,6 @@
|
||||
832341AE1AAA6A7D00B99B32 /* Libraries */,
|
||||
83CBBA001A601CBA00E9B192 /* Products */,
|
||||
2D16E6871FA4F8E400B85C8A /* Frameworks */,
|
||||
523B30FE431343BE096F5C21 /* Pods */,
|
||||
92643B17548A700FA33507C4 /* ExpoModulesProviders */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
sourceTree = "<group>";
|
||||
@@ -114,14 +84,6 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
92643B17548A700FA33507C4 /* ExpoModulesProviders */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7E80613205F5353A90501151 /* HIPMIBADUNG */,
|
||||
);
|
||||
name = ExpoModulesProviders;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
BB2F792B24A3F905000567C9 /* Supporting */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -139,13 +101,11 @@
|
||||
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "HIPMIBADUNG" */;
|
||||
buildPhases = (
|
||||
08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */,
|
||||
4DF2145C6600FA4F2932F421 /* [Expo] Configure project */,
|
||||
13B07F871A680F5B00A75B9A /* Sources */,
|
||||
13B07F8C1A680F5B00A75B9A /* Frameworks */,
|
||||
13B07F8E1A680F5B00A75B9A /* Resources */,
|
||||
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
|
||||
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */,
|
||||
4BE0A502450842B2C872639D /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -195,7 +155,6 @@
|
||||
BB2F792D24A3F905000567C9 /* Expo.plist in Resources */,
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
|
||||
3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */,
|
||||
3E9DE75169D0FBDB1B473165 /* PrivacyInfo.xcprivacy in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -209,6 +168,8 @@
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"$(SRCROOT)/.xcode.env",
|
||||
"$(SRCROOT)/.xcode.env.local",
|
||||
);
|
||||
name = "Bundle React Native code and images";
|
||||
outputPaths = (
|
||||
@@ -239,43 +200,6 @@
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
4BE0A502450842B2C872639D /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-HIPMIBADUNG/Pods-HIPMIBADUNG-frameworks.sh",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-HIPMIBADUNG/Pods-HIPMIBADUNG-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
4DF2145C6600FA4F2932F421 /* [Expo] Configure project */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[Expo] Configure project";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-HIPMIBADUNG/expo-configure-project.sh\"\n";
|
||||
};
|
||||
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -284,76 +208,14 @@
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-HIPMIBADUNG/Pods-HIPMIBADUNG-resources.sh",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/ExpoConstants_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ExpoFileSystem/ExpoFileSystem_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ExpoSystemUI/ExpoSystemUI_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly/RCT-Folly_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/RNCAsyncStorage/RNCAsyncStorage_resources.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/RNSVG/RNSVGFilters.bundle",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/AntDesign.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Entypo.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Feather.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Brands.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Regular.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Solid.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome6_Brands.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome6_Regular.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome6_Solid.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Fontisto.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Foundation.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/MaterialCommunityIcons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Octicons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Zocial.ttf",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage/SDWebImage.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/boost/boost_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/expo-dev-launcher/EXDevLauncher.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/expo-dev-menu/EXDevMenu.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/glog/glog_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/react-native-maps/ReactNativeMapsPrivacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/EXUpdates/EXUpdates.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoConstants_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoFileSystem_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoSystemUI_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCT-Folly_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNCAsyncStorage_resources.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNSVGFilters.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AntDesign.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Entypo.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EvilIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Feather.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Brands.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Regular.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Solid.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome6_Brands.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome6_Regular.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome6_Solid.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Fontisto.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Foundation.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Ionicons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialCommunityIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Octicons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SimpleLineIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Zocial.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SDWebImage.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/boost_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXDevLauncher.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXDevMenu.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/glog_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ReactNativeMapsPrivacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXUpdates.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
@@ -368,7 +230,6 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F11748422D0307B40044C1D9 /* AppDelegate.swift in Sources */,
|
||||
E3BE778B8B6E53CE5D518808 /* ExpoModulesProvider.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -377,13 +238,10 @@
|
||||
/* Begin XCBuildConfiguration section */
|
||||
13B07F941A680F5B00A75B9A /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7355472C9F7484C7F5780400 /* Pods-HIPMIBADUNG.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = HIPMIBADUNG/HIPMIBADUNG.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = A3FZDNQTUG;
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
@@ -401,26 +259,23 @@
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.anonymous.hipmi-mobile";
|
||||
PRODUCT_NAME = HIPMIBADUNG;
|
||||
PRODUCT_NAME = "HIPMIBADUNG";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "HIPMIBADUNG/HIPMIBADUNG-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
CODE_SIGN_ENTITLEMENTS = HIPMIBADUNG/HIPMIBADUNG.entitlements;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
13B07F951A680F5B00A75B9A /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 43EA3CD4BD89A00F8AB4791D /* Pods-HIPMIBADUNG.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = HIPMIBADUNG/HIPMIBADUNG.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = A3FZDNQTUG;
|
||||
INFOPLIST_FILE = HIPMIBADUNG/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@@ -433,13 +288,13 @@
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.anonymous.hipmi-mobile";
|
||||
PRODUCT_NAME = HIPMIBADUNG;
|
||||
PRODUCT_NAME = "HIPMIBADUNG";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "HIPMIBADUNG/HIPMIBADUNG-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
CODE_SIGN_ENTITLEMENTS = HIPMIBADUNG/HIPMIBADUNG.entitlements;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -495,14 +350,10 @@
|
||||
/usr/lib/swift,
|
||||
"$(inherited)",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\"";
|
||||
LIBRARY_SEARCH_PATHS = "\"$(inherited)\"";
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = "$(inherited) ";
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
|
||||
USE_HERMES = true;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -551,12 +402,9 @@
|
||||
/usr/lib/swift,
|
||||
"$(inherited)",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\"";
|
||||
LIBRARY_SEARCH_PATHS = "\"$(inherited)\"";
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
OTHER_LDFLAGS = "$(inherited) ";
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
USE_HERMES = true;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
|
||||
10
ios/HIPMIBADUNG.xcworkspace/contents.xcworkspacedata
generated
10
ios/HIPMIBADUNG.xcworkspace/contents.xcworkspacedata
generated
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:HIPMIBADUNG.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -1,48 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPITypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>CA92.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>0A2A.1</string>
|
||||
<string>3B52.1</string>
|
||||
<string>C617.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>E174.1</string>
|
||||
<string>85F4.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>35F9.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>NSPrivacyCollectedDataTypes</key>
|
||||
<array/>
|
||||
<key>NSPrivacyTracking</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,11 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="EXPO-VIEWCONTROLLER-1">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24093.7" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="EXPO-VIEWCONTROLLER-1">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24053.1"/>
|
||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
@@ -35,6 +36,9 @@
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="SplashScreenLogo" width="200" height="200"/>
|
||||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
<namedColor name="SplashScreenBackground">
|
||||
<color alpha="1.000" blue="1.00000000000000" green="1.00000000000000" red="1.00000000000000" customColorSpace="sRGB" colorSpace="custom"/>
|
||||
</namedColor>
|
||||
|
||||
20
ios/Podfile
20
ios/Podfile
@@ -4,12 +4,11 @@ require File.join(File.dirname(`node --print "require.resolve('react-native/pack
|
||||
require 'json'
|
||||
podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {}
|
||||
|
||||
ENV['RCT_NEW_ARCH_ENABLED'] = '0' if podfile_properties['newArchEnabled'] == 'false'
|
||||
ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] = podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR']
|
||||
|
||||
ENV['RCT_NEW_ARCH_ENABLED'] ||= '0' if podfile_properties['newArchEnabled'] == 'false'
|
||||
ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] ||= podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR']
|
||||
ENV['RCT_USE_RN_DEP'] ||= '1' if podfile_properties['ios.buildReactNativeFromSource'] != 'true' && podfile_properties['newArchEnabled'] != 'false'
|
||||
ENV['RCT_USE_PREBUILT_RNCORE'] ||= '1' if podfile_properties['ios.buildReactNativeFromSource'] != 'true' && podfile_properties['newArchEnabled'] != 'false'
|
||||
platform :ios, podfile_properties['ios.deploymentTarget'] || '15.1'
|
||||
install! 'cocoapods',
|
||||
:deterministic_uuids => false
|
||||
|
||||
prepare_react_native_project!
|
||||
|
||||
@@ -49,16 +48,5 @@ target 'HIPMIBADUNG' do
|
||||
:mac_catalyst_enabled => false,
|
||||
:ccache_enabled => podfile_properties['apple.ccacheEnabled'] == 'true',
|
||||
)
|
||||
|
||||
# This is necessary for Xcode 14, because it signs resource bundles by default
|
||||
# when building for devices.
|
||||
installer.target_installation_results.pod_target_installation_results
|
||||
.each do |pod_name, target_installation_result|
|
||||
target_installation_result.resource_bundle_targets.each do |resource_bundle_target|
|
||||
resource_bundle_target.build_configurations.each do |config|
|
||||
config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
2944
ios/Podfile.lock
2944
ios/Podfile.lock
File diff suppressed because it is too large
Load Diff
7
metro.config.js
Normal file
7
metro.config.js
Normal file
@@ -0,0 +1,7 @@
|
||||
// Learn more https://docs.expo.io/guides/customizing-metro
|
||||
const { getDefaultConfig } = require('expo/metro-config');
|
||||
|
||||
/** @type {import('expo/metro-config').MetroConfig} */
|
||||
const config = getDefaultConfig(__dirname);
|
||||
|
||||
module.exports = config;
|
||||
@@ -24,7 +24,6 @@
|
||||
"axios": "^1.11.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"expo": "^54.0.0",
|
||||
"expo-blur": "~15.0.7",
|
||||
"expo-camera": "~17.0.7",
|
||||
"expo-clipboard": "~8.0.7",
|
||||
"expo-constants": "~18.0.8",
|
||||
|
||||
@@ -6,7 +6,11 @@ import {
|
||||
DummyLandscapeImage,
|
||||
} from "@/components";
|
||||
|
||||
export default function AdminDonation_BoxOfDonationStory() {
|
||||
export default function AdminDonation_BoxOfDonationStory({
|
||||
data,
|
||||
}: {
|
||||
data: any;
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<BaseBox>
|
||||
@@ -14,19 +18,9 @@ export default function AdminDonation_BoxOfDonationStory() {
|
||||
<Spacing />
|
||||
|
||||
<StackCustom>
|
||||
<TextCustom>
|
||||
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Rem magni
|
||||
perspiciatis eius ipsam provident, impedit, fugiat aliquid nobis
|
||||
pariatur asperiores fuga quidem temporibus labore, molestias
|
||||
perferendis optio ipsum. Praesentium, tempore?
|
||||
</TextCustom>
|
||||
<DummyLandscapeImage />
|
||||
<TextCustom>
|
||||
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Rem magni
|
||||
perspiciatis eius ipsam provident, impedit, fugiat aliquid nobis
|
||||
pariatur asperiores fuga quidem temporibus labore, molestias
|
||||
perferendis optio ipsum. Praesentium, tempore?
|
||||
</TextCustom>
|
||||
<TextCustom>{(data && data?.pembukaan) || "-"}</TextCustom>
|
||||
<DummyLandscapeImage imageId={data?.imageId || "-"} />
|
||||
<TextCustom>{(data && data?.cerita) || "-"}</TextCustom>
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
</>
|
||||
|
||||
23
screens/Admin/Donation/funDonationUpdateStatus.ts
Normal file
23
screens/Admin/Donation/funDonationUpdateStatus.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { apiAdminDonationUpdateStatus } from "@/service/api-admin/api-admin-donation";
|
||||
|
||||
export const funUpdateStatusDonation = async ({
|
||||
id,
|
||||
changeStatus,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
changeStatus: "publish" | "review" | "reject";
|
||||
data?: string;
|
||||
}) => {
|
||||
try {
|
||||
const response = await apiAdminDonationUpdateStatus({
|
||||
id: id,
|
||||
changeStatus: changeStatus as any,
|
||||
data: data,
|
||||
});
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
23
screens/Admin/Event/funUpdateStatus.ts
Normal file
23
screens/Admin/Event/funUpdateStatus.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { apiAdminEventUpdateStatus } from "@/service/api-admin/api-admin-event";
|
||||
|
||||
export const funUpdateStatusEvent = async ({
|
||||
id,
|
||||
changeStatus,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
changeStatus: "publish" | "review" | "reject";
|
||||
data?: string;
|
||||
}) => {
|
||||
try {
|
||||
const response = await apiAdminEventUpdateStatus({
|
||||
id: id,
|
||||
changeStatus: changeStatus as any,
|
||||
data: data,
|
||||
});
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
26
screens/Admin/Job/funUpdateStatus.ts
Normal file
26
screens/Admin/Job/funUpdateStatus.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { apiAdminJobUpdate } from "@/service/api-admin/api-admin-job";
|
||||
|
||||
const funUpdateStatusJob = async ({
|
||||
id,
|
||||
changeStatus,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
changeStatus: "publish" | "review" | "reject";
|
||||
data?: string;
|
||||
}) => {
|
||||
try {
|
||||
const response = await apiAdminJobUpdate({
|
||||
id: id,
|
||||
status: changeStatus as any,
|
||||
data: data,
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export default funUpdateStatusJob;
|
||||
26
screens/Admin/Voting/funUpdateStatus.ts
Normal file
26
screens/Admin/Voting/funUpdateStatus.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { apiAdminVotingUpdateStatus } from "@/service/api-admin/api-admin-voting";
|
||||
|
||||
const funUpdateStatusVoting = async ({
|
||||
id,
|
||||
changeStatus,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
changeStatus: "publish" | "review" | "reject";
|
||||
data?: string;
|
||||
}) => {
|
||||
try {
|
||||
const response = await apiAdminVotingUpdateStatus({
|
||||
id: id,
|
||||
status: changeStatus as any,
|
||||
data: data,
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export default funUpdateStatusVoting;
|
||||
@@ -38,7 +38,7 @@ const adminListMenu: NavbarItem[] = [
|
||||
{ label: "Review", link: "/admin/event/review/status" },
|
||||
{ label: "Reject", link: "/admin/event/reject/status" },
|
||||
{ label: "Tipe Acara", link: "/admin/event/type-of-event" },
|
||||
{ label: "Riwayat", link: "/admin/event/riwayat/status" },
|
||||
{ label: "Riwayat", link: "/admin/event/history/status" },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -49,7 +49,7 @@ const adminListMenu: NavbarItem[] = [
|
||||
{ label: "Publish", link: "/admin/voting/publish/status" },
|
||||
{ label: "Review", link: "/admin/voting/review/status" },
|
||||
{ label: "Reject", link: "/admin/voting/reject/status" },
|
||||
{ label: "Riwayat", link: "/admin/voting/riwayat/status" },
|
||||
{ label: "Riwayat", link: "/admin/voting/history" },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -69,7 +69,7 @@ const adminListMenu: NavbarItem[] = [
|
||||
{ label: "Dashboard", link: "/admin/forum" },
|
||||
{ label: "Posting", link: "/admin/forum/posting" },
|
||||
{ label: "Report Posting", link: "/admin/forum/report-posting" },
|
||||
{ label: "Report Comment", link: "/admin/forum/report-comment" },
|
||||
{ label: "Report Komentar", link: "/admin/forum/report-comment" },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -131,7 +131,7 @@ const superAdminListMenu: NavbarItem[] = [
|
||||
{ label: "Review", link: "/admin/event/review/status" },
|
||||
{ label: "Reject", link: "/admin/event/reject/status" },
|
||||
{ label: "Tipe Acara", link: "/admin/event/type-of-event" },
|
||||
{ label: "Riwayat", link: "/admin/event/riwayat/status" },
|
||||
{ label: "Riwayat", link: "/admin/event/history/status" },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -142,7 +142,7 @@ const superAdminListMenu: NavbarItem[] = [
|
||||
{ label: "Publish", link: "/admin/voting/publish/status" },
|
||||
{ label: "Review", link: "/admin/voting/review/status" },
|
||||
{ label: "Reject", link: "/admin/voting/reject/status" },
|
||||
{ label: "Riwayat", link: "/admin/voting/riwayat/status" },
|
||||
{ label: "Riwayat", link: "/admin/voting/history" },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -162,7 +162,7 @@ const superAdminListMenu: NavbarItem[] = [
|
||||
{ label: "Dashboard", link: "/admin/forum" },
|
||||
{ label: "Posting", link: "/admin/forum/posting" },
|
||||
{ label: "Report Posting", link: "/admin/forum/report-posting" },
|
||||
{ label: "Report Comment", link: "/admin/forum/report-comment" },
|
||||
{ label: "Report Komentar", link: "/admin/forum/report-comment" },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -15,23 +15,24 @@ function Collaboration_BoxPublishSection({
|
||||
data: any;
|
||||
rightComponentAvatar?: React.ReactNode;
|
||||
}) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<BoxWithHeaderSection href={href}>
|
||||
<StackCustom gap={0}>
|
||||
<AvatarUsernameAndOtherComponent
|
||||
avatarHref={`/profile/${data?.Author?.id}`}
|
||||
avatarHref={`/profile/${data?.Author?.Profile?.id}`}
|
||||
name={data?.Author?.username || "Username"}
|
||||
rightComponent={rightComponentAvatar}
|
||||
avatar={data?.Author?.Profile?.imageId}
|
||||
withBottomLine
|
||||
/>
|
||||
|
||||
<StackCustom>
|
||||
<StackCustom style={{paddingBlock: 10}}>
|
||||
<TextCustom truncate size="large" bold align="center">
|
||||
{data?.title || "-"}
|
||||
</TextCustom>
|
||||
<TextCustom truncate={2}>{data?.purpose || "-"}</TextCustom>
|
||||
{/* <TextCustom truncate={2}>{data?.purpose || "-"}</TextCustom> */}
|
||||
{/* <TextCustom bold size="small" >
|
||||
2 Partisipan
|
||||
</TextCustom> */}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
BaseBox,
|
||||
Grid,
|
||||
DummyLandscapeImage,
|
||||
Grid,
|
||||
ProgressCustom,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ProgressCustom,
|
||||
} from "@/components";
|
||||
import { countDownAndCondition } from "@/utils/countDownAndCondition";
|
||||
import { useEffect, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
|
||||
export default function Donation_BoxPublish({
|
||||
@@ -15,6 +18,27 @@ export default function Donation_BoxPublish({
|
||||
id: string;
|
||||
data: any;
|
||||
}) {
|
||||
const [value, setValue] = useState({
|
||||
sisa: 0,
|
||||
reminder: false,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
updateCountDown();
|
||||
}, [data]);
|
||||
|
||||
const updateCountDown = () => {
|
||||
const countDown = countDownAndCondition({
|
||||
duration: data?.durasiDonasi,
|
||||
publishTime: data?.publishTime,
|
||||
});
|
||||
|
||||
setValue({
|
||||
sisa: countDown.durationDay,
|
||||
reminder: countDown.reminder,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<BaseBox paddingTop={7} paddingBottom={7} href={`/donation/${id}`}>
|
||||
@@ -36,13 +60,22 @@ export default function Donation_BoxPublish({
|
||||
{data?.title || "-"}
|
||||
</TextCustom>
|
||||
<TextCustom size="small">
|
||||
Sisa hari: {data?.durasiDonasi || 0}
|
||||
{value.reminder ? (
|
||||
<TextCustom bold color="red">
|
||||
Waktu berakhir
|
||||
</TextCustom>
|
||||
) : (
|
||||
<TextCustom>Sisa hari: {value.sisa}</TextCustom>
|
||||
)}
|
||||
</TextCustom>
|
||||
</View>
|
||||
<ProgressCustom
|
||||
label={data?.progres + "%" || "0%"}
|
||||
value={data?.progres || 0}
|
||||
size="lg"
|
||||
value={Number(data?.progres) || 0}
|
||||
showLabel={true}
|
||||
label={data?.progres + "%"}
|
||||
animated
|
||||
color="primary"
|
||||
/>
|
||||
{/* <TextCustom>
|
||||
Terkumpul : Rp 300.000
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import {
|
||||
BaseBox,
|
||||
StackCustom,
|
||||
DummyLandscapeImage,
|
||||
TextCustom,
|
||||
Grid,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
} from "@/components";
|
||||
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
|
||||
import React from "react";
|
||||
@@ -12,10 +12,15 @@ import { View } from "react-native";
|
||||
export default function Donation_ComponentBoxDetailData({
|
||||
bottomSection,
|
||||
data,
|
||||
sisaHari,
|
||||
reminder,
|
||||
}: {
|
||||
bottomSection?: React.ReactNode;
|
||||
data: any;
|
||||
sisaHari: number;
|
||||
reminder: boolean;
|
||||
}) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<BaseBox>
|
||||
@@ -25,9 +30,13 @@ export default function Donation_ComponentBoxDetailData({
|
||||
<TextCustom bold size="large">
|
||||
{data?.title || "-"}
|
||||
</TextCustom>
|
||||
<TextCustom size="small">
|
||||
Durasi: {data?.DonasiMaster_Durasi?.name || "-"}
|
||||
</TextCustom>
|
||||
{reminder ? (
|
||||
<TextCustom bold color="red">
|
||||
Waktu berakhir
|
||||
</TextCustom>
|
||||
) : (
|
||||
<TextCustom>Sisa hari: {sisaHari}</TextCustom>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<Grid>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user