Compare commits
19 Commits
amalia/22-
...
amalia/28-
| Author | SHA1 | Date | |
|---|---|---|---|
| e9f1b14bd6 | |||
| 9607774056 | |||
| 07caea8ae5 | |||
| 94c48889c6 | |||
| d0849143f2 | |||
| a7aeb3d3f9 | |||
| e755273ab1 | |||
| d460653408 | |||
| bb242c9be8 | |||
| c01a1885c2 | |||
| 2651e4bd18 | |||
| 171c5f0eeb | |||
| abeb26e565 | |||
| 191699af04 | |||
| 5cb81856de | |||
| 37fda41dc1 | |||
| 298113488c | |||
| d88c332b03 | |||
| f5c29e86fa |
@@ -84,9 +84,9 @@ export default function DetailAnnouncement() {
|
||||
</View>
|
||||
:
|
||||
<>
|
||||
<View style={Styles.rowItemsCenter}>
|
||||
<View style={[Styles.rowItemsCenter, { alignItems: 'flex-start' }]}>
|
||||
<MaterialIcons name="campaign" size={30} color="black" style={Styles.mr05} />
|
||||
<Text style={[Styles.textDefaultSemiBold]}>{data?.title}</Text>
|
||||
<Text style={[Styles.textDefaultSemiBold, Styles.w90]}>{data?.title}</Text>
|
||||
</View>
|
||||
<View style={[Styles.mt10]}>
|
||||
{
|
||||
|
||||
@@ -99,7 +99,7 @@ export default function CreateAnnouncement() {
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={disableBtn || loading ? true : false}
|
||||
disable={disableBtn || divisionMember.length == 0 || loading ? true : false}
|
||||
category="create"
|
||||
onPress={() => {
|
||||
divisionMember.length == 0
|
||||
|
||||
@@ -87,7 +87,7 @@ export default function Announcement() {
|
||||
<View>
|
||||
<InputSearch onChange={setSearch} />
|
||||
</View>
|
||||
<View style={[{ flex: 2 }]}>
|
||||
<View style={[{ flex: 2 }, Styles.mt05]}>
|
||||
{
|
||||
loading ?
|
||||
arrSkeleton.map((item, index) => {
|
||||
@@ -114,7 +114,7 @@ export default function Announcement() {
|
||||
</View>
|
||||
}
|
||||
title={item.title}
|
||||
desc={item.desc.replace(/<[^>]*>?/gm, '')}
|
||||
desc={item.desc.replace(/<[^>]*>?/gm, '').replace(/\r?\n|\r/g, ' ')}
|
||||
rightTopInfo={item.createdAt}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -5,6 +5,7 @@ import ButtonBackHeader from "@/components/buttonBackHeader"
|
||||
import DrawerBottom from "@/components/drawerBottom"
|
||||
import MenuItemRow from "@/components/menuItemRow"
|
||||
import ModalLoading from "@/components/modalLoading"
|
||||
import Text from "@/components/Text"
|
||||
import { ConstEnv } from "@/constants/ConstEnv"
|
||||
import Styles from "@/constants/Styles"
|
||||
import { apiDeleteBanner, apiGetBanner } from "@/lib/api"
|
||||
@@ -121,26 +122,37 @@ export default function BannerList() {
|
||||
}
|
||||
style={[Styles.h100]}
|
||||
>
|
||||
<View style={[Styles.p15, Styles.mb100]}>
|
||||
{entities.map((index: any, key: number) => (
|
||||
<BorderBottomItem
|
||||
key={key}
|
||||
onPress={() => {
|
||||
setDataId(index.id)
|
||||
setSelectFile(index)
|
||||
setModal(true)
|
||||
}}
|
||||
borderType="all"
|
||||
icon={
|
||||
<Image
|
||||
source={{ uri: `${ConstEnv.url_storage}/files/${index.image}` }}
|
||||
style={[Styles.imgListBanner]}
|
||||
{
|
||||
entities.length > 0
|
||||
?
|
||||
<View style={[Styles.p15, Styles.mb100]}>
|
||||
{entities.map((index: any, key: number) => (
|
||||
<BorderBottomItem
|
||||
key={key}
|
||||
onPress={() => {
|
||||
setDataId(index.id)
|
||||
setSelectFile(index)
|
||||
setModal(true)
|
||||
}}
|
||||
borderType="all"
|
||||
icon={
|
||||
<Image
|
||||
source={{ uri: `${ConstEnv.url_storage}/files/${index.image}` }}
|
||||
style={[Styles.imgListBanner]}
|
||||
/>
|
||||
}
|
||||
title={index.title}
|
||||
width={65}
|
||||
/>
|
||||
}
|
||||
title={index.title}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
:
|
||||
<View style={[Styles.p15, Styles.mb100]}>
|
||||
<Text style={[Styles.textDefault, Styles.cGray, { textAlign: 'center' }]}>Tidak ada data</Text>
|
||||
</View>
|
||||
}
|
||||
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<DrawerBottom animation="slide" isVisible={isModal} setVisible={() => setModal(false)} title="Menu">
|
||||
|
||||
@@ -122,7 +122,7 @@ export default function Discussion() {
|
||||
</View>
|
||||
}
|
||||
</View>
|
||||
<View style={[{ flex: 2 }]}>
|
||||
<View style={[{ flex: 2 }, Styles.mt05]}>
|
||||
{
|
||||
loading ?
|
||||
arrSkeleton.map((item: any, i: number) => {
|
||||
@@ -153,7 +153,7 @@ export default function Discussion() {
|
||||
status != "false" && <LabelStatus category={item.status === 1 ? "success" : "error"} text={item.status === 1 ? "BUKA" : "TUTUP"} size="small" />
|
||||
}
|
||||
rightTopInfo={item.createdAt}
|
||||
desc={item.desc}
|
||||
desc={item.desc.replace(/<[^>]*>?/gm, ' ').replace(/\r?\n|\r/g, ' ')}
|
||||
leftBottomInfo={
|
||||
<View style={[Styles.rowItemsCenter]}>
|
||||
<Ionicons name="chatbox-ellipses-outline" size={18} color="grey" style={Styles.mr05} />
|
||||
@@ -176,34 +176,6 @@ export default function Discussion() {
|
||||
/>
|
||||
}
|
||||
/>
|
||||
// data.map((item: any, i: number) => {
|
||||
// return (
|
||||
// <BorderBottomItem
|
||||
// key={i}
|
||||
// onPress={() => { router.push(`/discussion/${item.id}`) }}
|
||||
// borderType="bottom"
|
||||
// icon={
|
||||
// <View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
|
||||
// <MaterialIcons name="chat" size={25} color={'#384288'} />
|
||||
// </View>
|
||||
// }
|
||||
// title={item.title}
|
||||
// subtitle={
|
||||
// status != "false" && <LabelStatus category={item.status === 1 ? "success" : "error"} text={item.status === 1 ? "BUKA" : "TUTUP"} size="small" />
|
||||
// }
|
||||
// rightTopInfo={item.createdAt}
|
||||
// desc={item.desc}
|
||||
// leftBottomInfo={
|
||||
// <View style={[Styles.rowItemsCenter]}>
|
||||
// <Ionicons name="chatbox-ellipses-outline" size={18} color="grey" style={Styles.mr05} />
|
||||
// <Text style={[Styles.textInformation, Styles.cGray, Styles.mb05]}>Diskusikan</Text>
|
||||
// </View>
|
||||
// }
|
||||
// rightBottomInfo={`${item.total_komentar} Komentar`}
|
||||
|
||||
// />
|
||||
// )
|
||||
// })
|
||||
:
|
||||
<Text style={[Styles.textDefault, Styles.cGray, { textAlign: 'center' }]}>Tidak ada data</Text>
|
||||
}
|
||||
|
||||
@@ -9,10 +9,11 @@ import { valueTypeEventRepeat } from "@/constants/TypeEventRepeat"
|
||||
import { apiGetCalendarOne, apiUpdateCalendar } from "@/lib/api"
|
||||
import { stringToDateTime } from "@/lib/fun_stringToDate"
|
||||
import { useAuthSession } from "@/providers/AuthProvider"
|
||||
import { useHeaderHeight } from "@react-navigation/elements"
|
||||
import { Stack, router, useLocalSearchParams } from "expo-router"
|
||||
import moment from "moment"
|
||||
import { useEffect, useState } from "react"
|
||||
import { SafeAreaView, ScrollView, View } from "react-native"
|
||||
import { KeyboardAvoidingView, Platform, SafeAreaView, ScrollView, View } from "react-native"
|
||||
import Toast from "react-native-toast-message"
|
||||
|
||||
export default function EditEventCalendar() {
|
||||
@@ -22,6 +23,7 @@ export default function EditEventCalendar() {
|
||||
const { id, detail } = useLocalSearchParams<{ id: string, detail: string }>()
|
||||
const [idCalendar, setIdCalendar] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
const headerHeight = useHeaderHeight()
|
||||
|
||||
const [error, setError] = useState({
|
||||
title: false,
|
||||
@@ -176,94 +178,100 @@ export default function EditEventCalendar() {
|
||||
/>
|
||||
}}
|
||||
/>
|
||||
<ScrollView>
|
||||
<View style={[Styles.p15, Styles.mb100]}>
|
||||
<InputForm
|
||||
label="Nama Acara"
|
||||
type="default"
|
||||
placeholder="Nama Acara"
|
||||
required
|
||||
bg="white"
|
||||
value={data.title}
|
||||
onChange={(val) => validationForm("title", val)}
|
||||
error={error.title}
|
||||
errorText="Nama acara tidak boleh kosong"
|
||||
/>
|
||||
<InputDate
|
||||
onChange={(val) => validationForm("dateStart", val)}
|
||||
mode="date"
|
||||
value={data.dateStart}
|
||||
label="Tanggal Acara"
|
||||
required
|
||||
error={error.dateStart}
|
||||
errorText="Tanggal acara tidak boleh kosong"
|
||||
placeholder="Pilih Tanggal Acara"
|
||||
/>
|
||||
<View style={[Styles.rowSpaceBetween, Styles.mv10]}>
|
||||
<View style={[{ width: "48%" }]}>
|
||||
<InputDate
|
||||
onChange={(val) => validationForm("timeStart", val)}
|
||||
mode="time"
|
||||
value={data.timeStart}
|
||||
label="Waktu Awal"
|
||||
required
|
||||
error={error.timeStart}
|
||||
errorText="Waktu awal tidak valid"
|
||||
placeholder="--:--"
|
||||
/>
|
||||
</View>
|
||||
<View style={[{ width: "48%" }]}>
|
||||
<InputDate
|
||||
onChange={(val) => validationForm("timeEnd", val)}
|
||||
mode="time"
|
||||
value={data.timeEnd}
|
||||
label="Waktu Akhir"
|
||||
required
|
||||
error={error.timeEnd}
|
||||
errorText="Waktu akhir tidak valid"
|
||||
placeholder="--:--"
|
||||
/>
|
||||
<KeyboardAvoidingView
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
|
||||
keyboardVerticalOffset={headerHeight}
|
||||
>
|
||||
<ScrollView>
|
||||
<View style={[Styles.p15]}>
|
||||
<InputForm
|
||||
label="Nama Acara"
|
||||
type="default"
|
||||
placeholder="Nama Acara"
|
||||
required
|
||||
bg="white"
|
||||
value={data.title}
|
||||
onChange={(val) => validationForm("title", val)}
|
||||
error={error.title}
|
||||
errorText="Nama acara tidak boleh kosong"
|
||||
/>
|
||||
<InputDate
|
||||
onChange={(val) => validationForm("dateStart", val)}
|
||||
mode="date"
|
||||
value={data.dateStart}
|
||||
label="Tanggal Acara"
|
||||
required
|
||||
error={error.dateStart}
|
||||
errorText="Tanggal acara tidak boleh kosong"
|
||||
placeholder="Pilih Tanggal Acara"
|
||||
/>
|
||||
<View style={[Styles.rowSpaceBetween, Styles.mv10]}>
|
||||
<View style={[{ width: "48%" }]}>
|
||||
<InputDate
|
||||
onChange={(val) => validationForm("timeStart", val)}
|
||||
mode="time"
|
||||
value={data.timeStart}
|
||||
label="Waktu Awal"
|
||||
required
|
||||
error={error.timeStart}
|
||||
errorText="Waktu awal tidak valid"
|
||||
placeholder="--:--"
|
||||
/>
|
||||
</View>
|
||||
<View style={[{ width: "48%" }]}>
|
||||
<InputDate
|
||||
onChange={(val) => validationForm("timeEnd", val)}
|
||||
mode="time"
|
||||
value={data.timeEnd}
|
||||
label="Waktu Akhir"
|
||||
required
|
||||
error={error.timeEnd}
|
||||
errorText="Waktu akhir tidak valid"
|
||||
placeholder="--:--"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<InputForm
|
||||
label="Link Meet"
|
||||
type="default"
|
||||
placeholder="Link Meet"
|
||||
bg="white"
|
||||
value={data.linkMeet}
|
||||
onChange={(val) => validationForm("linkMeet", val)}
|
||||
/>
|
||||
<SelectForm
|
||||
bg="white"
|
||||
label="Ulangi Acara"
|
||||
placeholder="Ulangi Acara"
|
||||
value={choose.label}
|
||||
required
|
||||
onPress={() => { setSelect(true) }}
|
||||
/>
|
||||
<InputForm
|
||||
label="Jumlah Pengulangan"
|
||||
type="numeric"
|
||||
placeholder="Jumlah Pengulangan"
|
||||
required
|
||||
bg="white"
|
||||
value={String(data.repeatValue)}
|
||||
onChange={(val) => validationForm("repeatValue", val)}
|
||||
error={error.repeatValue}
|
||||
errorText="Jumlah pengulangan tidak valid"
|
||||
disable={choose.val == "once"}
|
||||
/>
|
||||
<InputForm
|
||||
label="Deskripsi"
|
||||
type="default"
|
||||
placeholder="Deskripsi"
|
||||
bg="white"
|
||||
value={data.desc}
|
||||
onChange={(val) => validationForm("desc", val)}
|
||||
multiline
|
||||
/>
|
||||
</View>
|
||||
<InputForm
|
||||
label="Link Meet"
|
||||
type="default"
|
||||
placeholder="Link Meet"
|
||||
bg="white"
|
||||
value={data.linkMeet}
|
||||
onChange={(val) => validationForm("linkMeet", val)}
|
||||
/>
|
||||
<SelectForm
|
||||
bg="white"
|
||||
label="Ulangi Acara"
|
||||
placeholder="Ulangi Acara"
|
||||
value={choose.label}
|
||||
required
|
||||
onPress={() => { setSelect(true) }}
|
||||
/>
|
||||
<InputForm
|
||||
label="Jumlah Pengulangan"
|
||||
type="numeric"
|
||||
placeholder="Jumlah Pengulangan"
|
||||
required
|
||||
bg="white"
|
||||
value={String(data.repeatValue)}
|
||||
onChange={(val) => validationForm("repeatValue", val)}
|
||||
error={error.repeatValue}
|
||||
errorText="Jumlah pengulangan tidak valid"
|
||||
disable={choose.val == "once"}
|
||||
/>
|
||||
<InputForm
|
||||
label="Deskripsi"
|
||||
type="default"
|
||||
placeholder="Deskripsi"
|
||||
bg="white"
|
||||
value={data.desc}
|
||||
onChange={(val) => validationForm("desc", val)}
|
||||
multiline
|
||||
/>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</ScrollView>
|
||||
</KeyboardAvoidingView>
|
||||
|
||||
|
||||
<ModalSelect
|
||||
category={"type-event-repeat"}
|
||||
|
||||
@@ -165,12 +165,12 @@ export default function DetailEventCalendar() {
|
||||
>
|
||||
<View style={[Styles.p15]}>
|
||||
<View style={[Styles.wrapPaper, Styles.mb15]}>
|
||||
<View style={Styles.rowItemsCenter}>
|
||||
<View style={[Styles.rowItemsCenter, { alignItems: 'flex-start' }]}>
|
||||
<MaterialCommunityIcons name="calendar-text" size={30} color="black" style={Styles.mr10} />
|
||||
{
|
||||
loading ?
|
||||
<Skeleton width={80} height={10} borderRadius={10} widthType="percent" />
|
||||
: <Text style={[Styles.textDefault]}>{data?.title}</Text>
|
||||
: <Text style={[Styles.textDefault, Styles.w90]}>{data?.title}</Text>
|
||||
}
|
||||
|
||||
</View>
|
||||
@@ -219,13 +219,13 @@ export default function DetailEventCalendar() {
|
||||
<Text style={[Styles.textDefault]}>{data?.linkMeet ? data.linkMeet : '-'}</Text>
|
||||
}
|
||||
</View>
|
||||
<View style={[Styles.rowItemsCenter, Styles.mt10]}>
|
||||
<View style={[Styles.rowItemsCenter, Styles.mt10, {alignItems:'flex-start'}]}>
|
||||
<MaterialCommunityIcons name="card-text-outline" size={30} color="black" style={Styles.mr10} />
|
||||
{
|
||||
loading ?
|
||||
<Skeleton width={80} height={10} borderRadius={10} widthType="percent" />
|
||||
:
|
||||
<Text style={[Styles.textDefault]}>{data?.desc}</Text>
|
||||
<Text style={[Styles.textDefault, Styles.w90]}>{data?.desc}</Text>
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -121,7 +121,7 @@ export default function DiscussionDivision() {
|
||||
<InputSearch onChange={setSearch} />
|
||||
</View>
|
||||
|
||||
<View style={[{ flex: 2 }]}>
|
||||
<View style={[{ flex: 2 }, Styles.mt05]}>
|
||||
{
|
||||
loading ?
|
||||
arrSkeleton.map((item: any, i: number) => {
|
||||
|
||||
@@ -8,7 +8,7 @@ import SectionMemberTask from "@/components/task/sectionMemberTask";
|
||||
import SectionReportTask from "@/components/task/sectionReportTask";
|
||||
import SectionTanggalTugasTask from "@/components/task/sectionTanggalTugasTask";
|
||||
import Styles from "@/constants/Styles";
|
||||
import { apiGetTaskOne } from "@/lib/api";
|
||||
import { apiGetDivisionOneFeature, apiGetTaskOne } from "@/lib/api";
|
||||
import { useAuthSession } from "@/providers/AuthProvider";
|
||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
@@ -32,6 +32,35 @@ export default function DetailTaskDivision() {
|
||||
const [progress, setProgress] = useState(0)
|
||||
const update = useSelector((state: any) => state.taskUpdate)
|
||||
const [refreshing, setRefreshing] = useState(false)
|
||||
const [isMemberDivision, setIsMemberDivision] = useState(false);
|
||||
const [isAdminDivision, setIsAdminDivision] = useState(false);
|
||||
const entityUser = useSelector((state: any) => state.user);
|
||||
|
||||
async function handleCheckMember() {
|
||||
try {
|
||||
const hasil = await decryptToken(String(token?.current));
|
||||
const response = await apiGetDivisionOneFeature({
|
||||
id,
|
||||
user: hasil,
|
||||
cat: "check-member",
|
||||
});
|
||||
|
||||
setIsMemberDivision(response.data);
|
||||
|
||||
const response2 = await apiGetDivisionOneFeature({
|
||||
id,
|
||||
user: hasil,
|
||||
cat: "check-admin",
|
||||
});
|
||||
setIsAdminDivision(response2.data);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
handleCheckMember()
|
||||
}, [])
|
||||
|
||||
|
||||
async function handleLoad(cat: 'data' | 'progress') {
|
||||
@@ -74,7 +103,9 @@ export default function DetailTaskDivision() {
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: loading ? 'Loading... ' : data?.title,
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <HeaderRightTaskDetail id={detail} division={id} status={data?.status} />,
|
||||
headerRight: () => (entityUser.role == "user" || entityUser.role == "coadmin") && !isMemberDivision
|
||||
? <></>
|
||||
: <HeaderRightTaskDetail id={detail} division={id} status={data?.status} isAdminDivision={isAdminDivision} />,
|
||||
}}
|
||||
/>
|
||||
<ScrollView
|
||||
@@ -91,10 +122,10 @@ export default function DetailTaskDivision() {
|
||||
}
|
||||
<SectionProgress text={`Kemajuan Kegiatan ${progress}%`} progress={progress} />
|
||||
<SectionReportTask refreshing={refreshing} />
|
||||
<SectionTanggalTugasTask refreshing={refreshing} />
|
||||
<SectionFileTask refreshing={refreshing} />
|
||||
<SectionLinkTask refreshing={refreshing} />
|
||||
<SectionMemberTask refreshing={refreshing} />
|
||||
<SectionTanggalTugasTask refreshing={refreshing} isMemberDivision={isMemberDivision} />
|
||||
<SectionFileTask refreshing={refreshing} isMemberDivision={isMemberDivision} />
|
||||
<SectionLinkTask refreshing={refreshing} isMemberDivision={isMemberDivision} />
|
||||
<SectionMemberTask refreshing={refreshing} isMemberDivision={isMemberDivision} />
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
|
||||
@@ -179,7 +179,7 @@ export default function ListTask() {
|
||||
</Pressable>
|
||||
</View>
|
||||
</View>
|
||||
<View style={[{ flex: 2 }]}>
|
||||
<View style={[{ flex: 2 }, Styles.mt05]}>
|
||||
{
|
||||
loading ?
|
||||
isList ?
|
||||
|
||||
@@ -7,6 +7,7 @@ import ImageUser from "@/components/imageNew"
|
||||
import SectionCancel from "@/components/sectionCancel"
|
||||
import Skeleton from "@/components/skeleton"
|
||||
import SkeletonTwoItem from "@/components/skeletonTwoItem"
|
||||
import Text from "@/components/Text"
|
||||
import { ColorsStatus } from "@/constants/ColorsStatus"
|
||||
import { ConstEnv } from "@/constants/ConstEnv"
|
||||
import Styles from "@/constants/Styles"
|
||||
@@ -15,7 +16,7 @@ import { useAuthSession } from "@/providers/AuthProvider"
|
||||
import { Feather, MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons"
|
||||
import { router, Stack, useLocalSearchParams } from "expo-router"
|
||||
import { useEffect, useState } from "react"
|
||||
import { Pressable, SafeAreaView, ScrollView, Text, View } from "react-native"
|
||||
import { Pressable, SafeAreaView, ScrollView, View } from "react-native"
|
||||
import Toast from "react-native-toast-message"
|
||||
import { useSelector } from "react-redux"
|
||||
|
||||
|
||||
@@ -51,9 +51,8 @@ export default function CreateDivisionAddAdmin() {
|
||||
async function handleAddMember() {
|
||||
try {
|
||||
setLoading(true)
|
||||
dispatch(setFormCreateDivision({ ...update, admin: selectMember }))
|
||||
const hasil = await decryptToken(String(token?.current))
|
||||
const response = await apiCreateDivision({ ...update, user: hasil })
|
||||
const response = await apiCreateDivision({ ...update, admin: selectMember, user: hasil })
|
||||
if (response.success) {
|
||||
Toast.show({ type: 'small', text1: 'Berhasil membuat divisi', })
|
||||
dispatch(setFormCreateDivision({ admin: [], member: [], data: { idGroup: '', name: '', desc: '' } }))
|
||||
|
||||
@@ -180,7 +180,7 @@ export default function ListDivision() {
|
||||
</View>
|
||||
}
|
||||
|
||||
<View style={[Styles.rowSpaceBetween]}>
|
||||
<View style={[Styles.rowSpaceBetween, { alignItems: 'center' }]}>
|
||||
<InputSearch width={68} onChange={setSearch} />
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
@@ -200,7 +200,7 @@ export default function ListDivision() {
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<View style={[{ flex: 2 }]}>
|
||||
<View style={[{ flex: 2 }, Styles.mt05]}>
|
||||
{
|
||||
loading ?
|
||||
isList ?
|
||||
|
||||
@@ -122,7 +122,7 @@ export default function EditProfile() {
|
||||
}
|
||||
} else if (cat == "phone") {
|
||||
setData({ ...data, phone: val });
|
||||
if (val == "" || !(val.length >= 10 && val.length <= 15)) {
|
||||
if (val == "" || !(val.length >= 9 && val.length <= 16)) {
|
||||
setError({ ...error, phone: true });
|
||||
} else {
|
||||
setError({ ...error, phone: false });
|
||||
|
||||
@@ -34,7 +34,7 @@ export default function Index() {
|
||||
const arrSkeleton = Array.from({ length: 5 }, (_, index) => index)
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [status, setStatus] = useState<'true' | 'false'>('true')
|
||||
|
||||
const [loadingSubmit, setLoadingSubmit] = useState(false)
|
||||
const [idChoose, setIdChoose] = useState('')
|
||||
const [activeChoose, setActiveChoose] = useState(true)
|
||||
const [titleChoose, setTitleChoose] = useState('')
|
||||
@@ -49,12 +49,14 @@ export default function Index() {
|
||||
|
||||
async function handleEdit() {
|
||||
try {
|
||||
setLoadingSubmit(true)
|
||||
const hasil = await decryptToken(String(token?.current))
|
||||
const response = await apiEditGroup({ user: hasil, name: titleChoose }, idChoose)
|
||||
dispatch(setUpdateGroup(!update))
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
setLoadingSubmit(false)
|
||||
setVisibleEdit(false)
|
||||
setModal(false)
|
||||
Toast.show({ type: 'small', text1: 'Berhasil mengupdate data', })
|
||||
@@ -126,7 +128,7 @@ export default function Index() {
|
||||
|
||||
return (
|
||||
<View style={[Styles.p15, { flex: 1 }]}>
|
||||
<View>
|
||||
<View style={[Styles.mb10]}>
|
||||
<View style={[Styles.wrapBtnTab]}>
|
||||
<ButtonTab
|
||||
active={status == "false" ? "false" : "true"}
|
||||
@@ -145,7 +147,7 @@ export default function Index() {
|
||||
</View>
|
||||
<InputSearch onChange={setSearch} />
|
||||
</View>
|
||||
<View style={{ flex: 2 }}>
|
||||
<View style={[{ flex: 2 }, Styles.mt05]}>
|
||||
{
|
||||
loading ?
|
||||
arrSkeleton.map((item, index) => {
|
||||
@@ -234,7 +236,7 @@ export default function Index() {
|
||||
onChange={(val) => { validationForm(val, 'title') }} />
|
||||
</View>
|
||||
<View>
|
||||
<ButtonForm text="SIMPAN" disabled={Object.values(error).some((v) => v == true) || titleChoose == ""} onPress={() => { handleEdit() }} />
|
||||
<ButtonForm text="SIMPAN" disabled={Object.values(error).some((v) => v == true) || titleChoose == "" || loadingSubmit} onPress={() => { handleEdit() }} />
|
||||
</View>
|
||||
</View>
|
||||
</DrawerBottom>
|
||||
|
||||
@@ -22,8 +22,8 @@ import { useDispatch, useSelector } from "react-redux";
|
||||
export default function Home() {
|
||||
const entities = useSelector((state: any) => state.entities)
|
||||
const dispatch = useDispatch()
|
||||
const { token, decryptToken } = useAuthSession()
|
||||
const insets = useSafeAreaInsets();
|
||||
const { token, decryptToken, signOut } = useAuthSession()
|
||||
const insets = useSafeAreaInsets()
|
||||
|
||||
useEffect(() => {
|
||||
handleUserLogin()
|
||||
@@ -31,7 +31,11 @@ export default function Home() {
|
||||
|
||||
async function handleUserLogin() {
|
||||
const hasil = await decryptToken(String(token?.current))
|
||||
apiGetProfile({ id: hasil }).then((data) => dispatch(setEntities(data.data)));
|
||||
apiGetProfile({ id: hasil })
|
||||
.then((data) => dispatch(setEntities(data.data)))
|
||||
.catch((error) => {
|
||||
signOut()
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -95,7 +95,7 @@ export default function MemberDetail() {
|
||||
:
|
||||
<>
|
||||
<ImageUser src={`${ConstEnv.url_storage}/files/${data?.img}`} size="lg" />
|
||||
<Text style={[Styles.textSubtitle, Styles.cWhite, Styles.mt10]}>{data?.name}</Text>
|
||||
<Text style={[Styles.textSubtitle, Styles.cWhite, Styles.mt10, { textAlign: 'center' }]}>{data?.name}</Text>
|
||||
<Text style={[Styles.textMediumNormal, Styles.cWhite]}>{data?.role}</Text>
|
||||
</>
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ export default function CreateMember() {
|
||||
}
|
||||
} else if (cat == "phone") {
|
||||
setDataForm({ ...dataForm, phone: val });
|
||||
if (val == "" || !(val.length >= 10 && val.length <= 15)) {
|
||||
if (val == "" || !(val.length >= 9 && val.length <= 16)) {
|
||||
setError({ ...error, phone: true });
|
||||
} else {
|
||||
setError({ ...error, phone: false });
|
||||
|
||||
@@ -149,7 +149,7 @@ export default function EditMember() {
|
||||
}
|
||||
} else if (cat == "phone") {
|
||||
setData({ ...data, phone: val });
|
||||
if (val == "" || !(val.length >= 10 && val.length <= 15)) {
|
||||
if (val == "" || !(val.length >= 9 && val.length <= 16)) {
|
||||
setError({ ...error, phone: true });
|
||||
} else {
|
||||
setError({ ...error, phone: false });
|
||||
|
||||
@@ -129,7 +129,7 @@ export default function Index() {
|
||||
</View>
|
||||
}
|
||||
</View>
|
||||
<View style={[{ flex: 2 }]}>
|
||||
<View style={[{ flex: 2 }, Styles.mt05]}>
|
||||
{
|
||||
loading ?
|
||||
arrSkeleton.map((item, index) => {
|
||||
|
||||
@@ -40,6 +40,7 @@ export default function Index() {
|
||||
const [data, setData] = useState<Props[]>([])
|
||||
const [search, setSearch] = useState('')
|
||||
const [nameGroup, setNameGroup] = useState('')
|
||||
const [loadingSubmit, setLoadingSubmit] = useState(false)
|
||||
const [chooseData, setChooseData] = useState({ name: '', id: '', active: false, idGroup: '' })
|
||||
const [error, setError] = useState({
|
||||
name: false,
|
||||
@@ -94,15 +95,20 @@ export default function Index() {
|
||||
|
||||
async function handleEdit() {
|
||||
try {
|
||||
setLoadingSubmit(true)
|
||||
const hasil = await decryptToken(String(token?.current))
|
||||
const response = await apiEditPosition({ user: hasil, name: chooseData.name, idGroup: chooseData.idGroup }, chooseData.id)
|
||||
dispatch(setUpdatePosition(!update))
|
||||
if (response.success) {
|
||||
dispatch(setUpdatePosition(!update))
|
||||
} else {
|
||||
Toast.show({ type: 'small', text1: response.message, })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
setLoadingSubmit(false)
|
||||
setVisibleEdit(false)
|
||||
setModal(false)
|
||||
Toast.show({ type: 'small', text1: 'Berhasil mengupdate data', })
|
||||
}
|
||||
|
||||
}
|
||||
@@ -165,7 +171,7 @@ export default function Index() {
|
||||
</View>
|
||||
}
|
||||
</View>
|
||||
<View style={[{ flex: 2 }]}>
|
||||
<View style={[{ flex: 2 }, Styles.mt05]}>
|
||||
{
|
||||
loading ?
|
||||
arrSkeleton.map((item, index) => {
|
||||
@@ -251,7 +257,7 @@ export default function Index() {
|
||||
/>
|
||||
</View>
|
||||
<View style={Styles.mb30}>
|
||||
<ButtonForm text="SIMPAN" onPress={() => { checkForm() }} />
|
||||
<ButtonForm text="SIMPAN" onPress={() => { handleEdit() }} disabled={Object.values(error).some((v) => v == true) || chooseData.name == "" || loadingSubmit} />
|
||||
</View>
|
||||
</View>
|
||||
</DrawerBottom>
|
||||
|
||||
@@ -178,7 +178,7 @@ export default function ListProject() {
|
||||
n={4}
|
||||
/>
|
||||
</ScrollView>
|
||||
<View style={[Styles.rowSpaceBetween]}>
|
||||
<View style={[Styles.rowSpaceBetween, { alignItems: 'center' }]}>
|
||||
<InputSearch width={68} onChange={setSearch} />
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
|
||||
@@ -75,7 +75,6 @@ export default function Search() {
|
||||
headerTitleAlign: 'center'
|
||||
}}
|
||||
/>
|
||||
{/* <ScrollView> */}
|
||||
<View style={[Styles.p15]}>
|
||||
<InputSearch onChange={handleSearch} />
|
||||
{
|
||||
@@ -163,13 +162,12 @@ export default function Search() {
|
||||
|
||||
</View>
|
||||
:
|
||||
<View style={Styles.contentItemCenter}>
|
||||
<View style={[Styles.contentItemCenter, Styles.mt10]}>
|
||||
<Text style={[Styles.textInformation, Styles.cGray]}>Tidak ada data</Text>
|
||||
</View>
|
||||
}
|
||||
|
||||
</View>
|
||||
{/* </ScrollView> */}
|
||||
</SafeAreaView>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import ViewLogin from "@/components/auth/viewLogin";
|
||||
import ViewVerification from "@/components/auth/viewVerification";
|
||||
import Text from '@/components/Text';
|
||||
import ToastCustom from "@/components/toastCustom";
|
||||
import { requestPermission } from "@/lib/useNotification";
|
||||
import { useAuthSession } from "@/providers/AuthProvider";
|
||||
import { Redirect } from "expo-router";
|
||||
|
||||
@@ -28,14 +28,13 @@ export default function ViewLogin({ onValidate }: Props) {
|
||||
const otp = Math.floor(1000 + Math.random() * 9000)
|
||||
const responseOtp = await apiSendOtp({ phone: `62${phone}`, otp })
|
||||
if (responseOtp == 200) {
|
||||
// localStorage.setItem('user', response.id)
|
||||
await AsyncStorage.setItem('user', response.id);
|
||||
return onValidate({ phone: `62${phone}`, otp })
|
||||
}
|
||||
}
|
||||
return Toast.show({ type: 'small', text1: response.message, })
|
||||
return Toast.show({ type: 'small', text1: response.message, position: 'top' })
|
||||
} catch (error) {
|
||||
return Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
|
||||
return Toast.show({ type: 'small', text1: 'Terjadi kesalahan', position: 'top' })
|
||||
} finally {
|
||||
setLoadingLogin(false)
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ export default function ViewVerification({ phone, otp }: Props) {
|
||||
const encrypted = await encryptToken(valueUser);
|
||||
signIn(encrypted);
|
||||
} else {
|
||||
return Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
|
||||
return Toast.show({ type: 'small', text1: 'Terjadi kesalahan', position: 'top' })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ export default function ViewVerification({ phone, otp }: Props) {
|
||||
if (value === otpFix.toString()) {
|
||||
login()
|
||||
} else {
|
||||
return Toast.show({ type: 'small', text1: 'Kode OTP tidak sesuai' });
|
||||
return Toast.show({ type: 'small', text1: 'Kode OTP tidak sesuai', position: 'top' });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ export default function BorderBottomItem({ title, subtitle, icon, desc, onPress,
|
||||
</View>
|
||||
|
||||
</View>
|
||||
{desc && <Text style={[Styles.textDefault, Styles.mt05, { textAlign: 'justify', color: textColorFix }]} numberOfLines={descEllipsize == false ? 0 : 2} ellipsizeMode='tail'>{desc}</Text>}
|
||||
{desc && <Text style={[Styles.textDefault, Styles.mt05, { textAlign: 'left', color: textColorFix }]} numberOfLines={descEllipsize == false ? 0 : 2} ellipsizeMode='tail'>{desc}</Text>}
|
||||
{
|
||||
(leftBottomInfo || rightBottomInfo) &&
|
||||
(
|
||||
|
||||
@@ -44,7 +44,7 @@ export default function DrawerBottom({ isVisible, setVisible, title, children, a
|
||||
>
|
||||
<View style={[Styles.modalContentNew, { height: tinggiFix }]}>
|
||||
<View style={[Styles.titleContainerNew]}>
|
||||
<Text style={Styles.textDefault}>{title}</Text>
|
||||
<Text numberOfLines={1} ellipsizeMode='tail' style={[Styles.textDefault, Styles.w90]}>{title}</Text>
|
||||
<Pressable onPress={() => setVisible(false)}>
|
||||
<MaterialIcons name="close" color="black" size={22} />
|
||||
</Pressable>
|
||||
@@ -57,7 +57,7 @@ export default function DrawerBottom({ isVisible, setVisible, title, children, a
|
||||
:
|
||||
<View style={[Styles.modalContentNew, { height: tinggiFix }]}>
|
||||
<View style={[Styles.titleContainerNew]}>
|
||||
<Text style={Styles.textDefault}>{title}</Text>
|
||||
<Text numberOfLines={1} ellipsizeMode='tail' style={[Styles.textDefault, Styles.w90]}>{title}</Text>
|
||||
<Pressable onPress={() => setVisible(false)}>
|
||||
<MaterialIcons name="close" color="black" size={22} />
|
||||
</Pressable>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Styles from "@/constants/Styles"
|
||||
import { Pressable, View } from "react-native"
|
||||
import Styles from "@/constants/Styles";
|
||||
import { Pressable, View } from "react-native";
|
||||
import Text from "./Text";
|
||||
|
||||
type Props = {
|
||||
@@ -17,8 +17,8 @@ export default function EventItem({ category, title, user, jamAwal, jamAkhir, on
|
||||
<View style={[Styles.dividerEvent, { backgroundColor: category == 'orange' ? '#FB804C' : '#535FCA' }]} />
|
||||
<View>
|
||||
<Text>{jamAwal} - {jamAkhir}</Text>
|
||||
<Text style={[Styles.textDefaultSemiBold, Styles.mv05]}>{title}</Text>
|
||||
<Text>Dibuat oleh : {user}</Text>
|
||||
<Text numberOfLines={1} ellipsizeMode="tail" style={[Styles.textDefaultSemiBold, Styles.mv05]}>{title}</Text>
|
||||
<Text numberOfLines={1} ellipsizeMode="tail">Dibuat oleh : {user}</Text>
|
||||
</View>
|
||||
</Pressable>
|
||||
)
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Dimensions, Image, View } from "react-native";
|
||||
import { useSharedValue } from "react-native-reanimated";
|
||||
import Carousel, { ICarouselInstance } from "react-native-reanimated-carousel";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import Text from "../Text";
|
||||
|
||||
export default function CaraouselHome() {
|
||||
const { decryptToken, token } = useAuthSession()
|
||||
@@ -21,7 +22,13 @@ export default function CaraouselHome() {
|
||||
|
||||
async function handleBannerView() {
|
||||
const hasil = await decryptToken(String(token?.current))
|
||||
apiGetBanner({ user: hasil }).then((data) => dispatch(setEntities(data.data)))
|
||||
apiGetBanner({ user: hasil }).then((data) => {
|
||||
if (data.data.length > 0) {
|
||||
dispatch(setEntities(data.data))
|
||||
} else {
|
||||
dispatch(setEntities([]))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function handleUser() {
|
||||
@@ -40,22 +47,30 @@ export default function CaraouselHome() {
|
||||
|
||||
return (
|
||||
<View style={[Styles.mv15]}>
|
||||
<Carousel
|
||||
ref={ref}
|
||||
width={width}
|
||||
height={width / 2.5}
|
||||
data={entities}
|
||||
loop={true}
|
||||
autoPlay={true}
|
||||
autoPlayInterval={5000}
|
||||
onProgressChange={progress}
|
||||
renderItem={({ index }) => (
|
||||
<Image
|
||||
source={{ uri: `${ConstEnv.url_storage}/files/${entities[index].image}` }}
|
||||
style={[Styles.caraoselContent]}
|
||||
{
|
||||
entities.length > 0 ?
|
||||
<Carousel
|
||||
ref={ref}
|
||||
width={width}
|
||||
height={width / 2.5}
|
||||
data={entities}
|
||||
loop={true}
|
||||
autoPlay={true}
|
||||
autoPlayInterval={5000}
|
||||
onProgressChange={progress}
|
||||
renderItem={({ index }) => (
|
||||
<Image
|
||||
source={{ uri: `${ConstEnv.url_storage}/files/${entities[index].image}` }}
|
||||
style={[Styles.caraoselContent]}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
:
|
||||
<View style={[Styles.caraoselContent, { height: width / 2.5 }]}>
|
||||
<Text style={[Styles.textDefault, Styles.cWhite, { textAlign: 'center' }]}>BANNER</Text>
|
||||
</View>
|
||||
}
|
||||
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@@ -19,15 +19,16 @@ type Props = {
|
||||
value?: string
|
||||
disable?: boolean
|
||||
multiline?: boolean
|
||||
mb?: boolean
|
||||
};
|
||||
|
||||
|
||||
export function InputForm({ label, value, placeholder, onChange, info, disable, error, errorText, required, itemLeft, itemRight, type, round, width, bg, multiline }: Props) {
|
||||
export function InputForm({ label, value, placeholder, onChange, info, disable, error, errorText, required, itemLeft, itemRight, type, round, width, bg, multiline, mb = true }: Props) {
|
||||
const lebar = Dimensions.get("window").width;
|
||||
|
||||
if (itemLeft != undefined || itemRight != undefined) {
|
||||
return (
|
||||
<View style={{ marginBottom: 10 }}>
|
||||
<View style={[mb && Styles.mb10]}>
|
||||
{
|
||||
label != undefined && (
|
||||
<Text style={[{ marginBottom: 5, textTransform: "capitalize" }, error && Styles.cError]}>
|
||||
@@ -42,7 +43,7 @@ export function InputForm({ label, value, placeholder, onChange, info, disable,
|
||||
round && Styles.round30,
|
||||
{ backgroundColor: bg && bg == 'white' ? 'white' : 'transparent' },
|
||||
error && { borderColor: "red" },
|
||||
Platform.OS == 'ios' && { paddingVertical: 10 },
|
||||
Platform.OS == 'ios' ? { paddingVertical: 10 } : { paddingVertical: 0 },
|
||||
]}>
|
||||
{itemRight != undefined ? itemRight : itemLeft}
|
||||
<TextInput
|
||||
@@ -52,7 +53,7 @@ export function InputForm({ label, value, placeholder, onChange, info, disable,
|
||||
keyboardType={type}
|
||||
onChangeText={onChange}
|
||||
placeholderTextColor={'gray'}
|
||||
style={[Styles.mh05, { width: width ? lebar * width / 100 : lebar * 0.78, color: 'black' }]}
|
||||
style={[Styles.mh05, { width: width ? lebar * width / 100 : lebar * 0.78, color: 'black' }, Platform.OS == 'ios' ? { paddingVertical: 1 } : { paddingVertical: 5 }]}
|
||||
/>
|
||||
</View>
|
||||
{error && (<Text style={[Styles.textInformation, Styles.cError, Styles.mt05]}>{errorText}</Text>)}
|
||||
@@ -78,7 +79,7 @@ export function InputForm({ label, value, placeholder, onChange, info, disable,
|
||||
placeholder={placeholder}
|
||||
keyboardType={type}
|
||||
editable={!disable}
|
||||
style={[Styles.inputRoundForm, error && { borderColor: "red" }, round && Styles.round30, { backgroundColor: bg && bg == 'white' ? 'white' : 'transparent' }, { color: 'black' }, multiline && { height: 150, textAlignVertical: 'top' }]}
|
||||
style={[Styles.inputRoundForm, Platform.OS == 'ios' ? { paddingVertical: 11 } : { paddingVertical: 6 }, error && { borderColor: "red" }, round && Styles.round30, { backgroundColor: bg && bg == 'white' ? 'white' : 'transparent' }, { color: 'black' }, multiline && { height: 150, textAlignVertical: 'top' }]}
|
||||
onChangeText={onChange}
|
||||
placeholderTextColor={'gray'}
|
||||
multiline={multiline}
|
||||
|
||||
@@ -12,6 +12,7 @@ export default function InputSearch({ onChange, width, value }: { onChange?: (va
|
||||
width={width}
|
||||
bg="white"
|
||||
value={value}
|
||||
mb={false}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -33,7 +33,7 @@ export default function ItemSectionTanggalTugas({ done, title, dateStart, dateEn
|
||||
|
||||
</View>
|
||||
<View style={[Styles.wrapPaper, Styles.mv10, Styles.p10]}>
|
||||
<View style={[Styles.rowItemsCenter]}>
|
||||
<View style={[Styles.rowItemsCenter, {alignItems:'flex-start'}]}>
|
||||
<MaterialCommunityIcons name="file-table-outline" size={25} color="black" style={[Styles.mr10]} />
|
||||
<View style={[Styles.w90]}>
|
||||
<Text style={[Styles.textDefault]}>{title}</Text>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { apiCreatePosition } from "@/lib/api"
|
||||
import { setUpdatePosition } from "@/lib/positionSlice"
|
||||
import { useAuthSession } from "@/providers/AuthProvider"
|
||||
import { AntDesign } from "@expo/vector-icons"
|
||||
import { useState } from "react"
|
||||
import { useEffect, useState } from "react"
|
||||
import { View } from "react-native"
|
||||
import Toast from "react-native-toast-message"
|
||||
import { useDispatch, useSelector } from "react-redux"
|
||||
@@ -26,6 +26,7 @@ export default function HeaderRightPositionList() {
|
||||
const [isFilter, setFilter] = useState(false)
|
||||
const [isSelect, setSelect] = useState(false)
|
||||
const [choose, setChoose] = useState({ val: '', label: '' })
|
||||
const [disable, setDisable] = useState(true)
|
||||
const [dataForm, setDataForm] = useState({
|
||||
name: "",
|
||||
idGroup: "",
|
||||
@@ -54,36 +55,32 @@ export default function HeaderRightPositionList() {
|
||||
}
|
||||
|
||||
function checkAll() {
|
||||
let nilai = true
|
||||
let nilai = false
|
||||
if (dataForm.name == "") {
|
||||
setError(error => ({ ...error, name: true }))
|
||||
nilai = false
|
||||
nilai = true
|
||||
}
|
||||
|
||||
if ((entityUser.role == "supadmin" || entityUser.role == "developer") && (dataForm.idGroup == "" || String(dataForm.idGroup) == "null")) {
|
||||
setError(error => ({ ...error, idGroup: true }))
|
||||
nilai = false
|
||||
nilai = true
|
||||
}
|
||||
|
||||
return nilai
|
||||
}
|
||||
|
||||
function onCheck() {
|
||||
const check = checkAll()
|
||||
if (!check)
|
||||
return false
|
||||
handleTambah()
|
||||
setDisable(nilai)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
checkAll()
|
||||
}, [dataForm])
|
||||
|
||||
async function handleTambah() {
|
||||
try {
|
||||
setDisable(true)
|
||||
const hasil = await decryptToken(String(token?.current))
|
||||
const response = await apiCreatePosition({ user: hasil, name: dataForm.name, idGroup: dataForm.idGroup })
|
||||
dispatch(setUpdatePosition(!update))
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
setDisable(false)
|
||||
setVisibleTambah(false)
|
||||
setVisible(false)
|
||||
Toast.show({ type: 'small', text1: 'Berhasil menambahkan data', })
|
||||
@@ -155,7 +152,10 @@ export default function HeaderRightPositionList() {
|
||||
/>
|
||||
</View>
|
||||
<View style={Styles.mb30}>
|
||||
<ButtonForm text="SIMPAN" onPress={() => { onCheck() }} />
|
||||
<ButtonForm
|
||||
text="SIMPAN"
|
||||
onPress={() => { handleTambah() }}
|
||||
disabled={disable} />
|
||||
</View>
|
||||
</View>
|
||||
</DrawerBottom>
|
||||
|
||||
@@ -34,9 +34,9 @@ export default function SelectForm({ label, value, placeholder, onPress, info, e
|
||||
<Feather name="chevron-right" size={20} color="grey" />
|
||||
{
|
||||
value ? (
|
||||
<Text style={[Styles.cBlack]}>{value}</Text>
|
||||
<Text numberOfLines={1} ellipsizeMode='tail' style={[Styles.cBlack, Styles.w90]}>{value}</Text>
|
||||
) : (
|
||||
<Text style={[Styles.cGray]}>{placeholder}</Text>
|
||||
<Text numberOfLines={1} ellipsizeMode='tail' style={[Styles.cGray, Styles.w90]}>{placeholder}</Text>
|
||||
)
|
||||
}
|
||||
</View>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import Styles from "@/constants/Styles"
|
||||
import { apiAddLinkTask, apiDeleteTask, apiGetDivisionOneFeature } from "@/lib/api"
|
||||
import { apiAddLinkTask, apiDeleteTask } from "@/lib/api"
|
||||
import { setUpdateTask } from "@/lib/taskUpdate"
|
||||
import { useAuthSession } from "@/providers/AuthProvider"
|
||||
import { AntDesign, Feather, Ionicons, MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons"
|
||||
import { router } from "expo-router"
|
||||
import { useEffect, useState } from "react"
|
||||
import { useState } from "react"
|
||||
import { View } from "react-native"
|
||||
import Toast from "react-native-toast-message"
|
||||
import { useDispatch, useSelector } from "react-redux"
|
||||
@@ -18,46 +18,19 @@ import ModalFloat from "../modalFloat"
|
||||
type Props = {
|
||||
id: string | string[]
|
||||
division: string
|
||||
status: number | undefined
|
||||
status: number | undefined,
|
||||
isAdminDivision: boolean
|
||||
}
|
||||
|
||||
export default function HeaderRightTaskDetail({ id, division, status }: Props) {
|
||||
export default function HeaderRightTaskDetail({ id, division, status, isAdminDivision }: Props) {
|
||||
const { token, decryptToken } = useAuthSession()
|
||||
const [isVisible, setVisible] = useState(false)
|
||||
const entityUser = useSelector((state: any) => state.user);
|
||||
const [isMemberDivision, setIsMemberDivision] = useState(false);
|
||||
const [isAdminDivision, setIsAdminDivision] = useState(false);
|
||||
const dispatch = useDispatch()
|
||||
const update = useSelector((state: any) => state.taskUpdate)
|
||||
const [isAddLink, setAddLink] = useState(false)
|
||||
const [link, setLink] = useState("")
|
||||
|
||||
async function handleCheckMember() {
|
||||
try {
|
||||
const hasil = await decryptToken(String(token?.current));
|
||||
const response = await apiGetDivisionOneFeature({
|
||||
id: division,
|
||||
user: hasil,
|
||||
cat: "check-member",
|
||||
});
|
||||
|
||||
setIsMemberDivision(response.data);
|
||||
|
||||
const response2 = await apiGetDivisionOneFeature({
|
||||
id: division,
|
||||
user: hasil,
|
||||
cat: "check-admin",
|
||||
});
|
||||
setIsAdminDivision(response2.data);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
handleCheckMember()
|
||||
}, [])
|
||||
|
||||
async function handleDelete() {
|
||||
try {
|
||||
const hasil = await decryptToken(String(token?.current))
|
||||
@@ -95,12 +68,7 @@ export default function HeaderRightTaskDetail({ id, division, status }: Props) {
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
(entityUser.role == "user" || entityUser.role == "coadmin") && !isMemberDivision
|
||||
? <></>
|
||||
:
|
||||
<ButtonMenuHeader onPress={() => { setVisible(true) }} />
|
||||
}
|
||||
<ButtonMenuHeader onPress={() => { setVisible(true) }} />
|
||||
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={setVisible} title="Menu" height={30}>
|
||||
<View style={Styles.rowItemsCenter}>
|
||||
<MenuItemRow
|
||||
|
||||
@@ -28,7 +28,7 @@ type Props = {
|
||||
idStorage: string
|
||||
}
|
||||
|
||||
export default function SectionFileTask({ refreshing }: { refreshing: boolean }) {
|
||||
export default function SectionFileTask({ refreshing, isMemberDivision }: { refreshing: boolean, isMemberDivision: boolean }) {
|
||||
const [isModal, setModal] = useState(false)
|
||||
const { token, decryptToken } = useAuthSession()
|
||||
const { detail } = useLocalSearchParams<{ detail: string }>()
|
||||
@@ -39,6 +39,7 @@ export default function SectionFileTask({ refreshing }: { refreshing: boolean })
|
||||
const arrSkeleton = Array.from({ length: 5 })
|
||||
const [selectFile, setSelectFile] = useState<Props | null>(null)
|
||||
const [loadingOpen, setLoadingOpen] = useState(false)
|
||||
const entityUser = useSelector((state: any) => state.user);
|
||||
|
||||
async function handleLoad(loading: boolean) {
|
||||
try {
|
||||
@@ -163,21 +164,28 @@ export default function SectionFileTask({ refreshing }: { refreshing: boolean })
|
||||
openFile()
|
||||
}}
|
||||
/>
|
||||
<MenuItemRow
|
||||
icon={<Ionicons name="trash" color="black" size={25} />}
|
||||
title="Hapus"
|
||||
onPress={() => {
|
||||
setModal(false)
|
||||
AlertKonfirmasi({
|
||||
title: 'Konfirmasi',
|
||||
desc: 'Apakah Anda yakin ingin menghapus file ini? File yang dihapus tidak dapat dikembalikan',
|
||||
onPress: () => {
|
||||
handleDelete()
|
||||
}
|
||||
})
|
||||
{
|
||||
(entityUser.role != "user" && entityUser.role != "coadmin") || isMemberDivision
|
||||
?
|
||||
<MenuItemRow
|
||||
icon={<Ionicons name="trash" color="black" size={25} />}
|
||||
title="Hapus"
|
||||
onPress={() => {
|
||||
setModal(false)
|
||||
AlertKonfirmasi({
|
||||
title: 'Konfirmasi',
|
||||
desc: 'Apakah Anda yakin ingin menghapus file ini? File yang dihapus tidak dapat dikembalikan',
|
||||
onPress: () => {
|
||||
handleDelete()
|
||||
}
|
||||
})
|
||||
|
||||
}}
|
||||
/>
|
||||
:
|
||||
<></>
|
||||
}
|
||||
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</DrawerBottom>
|
||||
</>
|
||||
|
||||
@@ -20,7 +20,7 @@ type Props = {
|
||||
link: string
|
||||
}
|
||||
|
||||
export default function SectionLinkTask({ refreshing }: { refreshing: boolean }) {
|
||||
export default function SectionLinkTask({ refreshing, isMemberDivision }: { refreshing: boolean, isMemberDivision: boolean }) {
|
||||
const [isModal, setModal] = useState(false)
|
||||
const { token, decryptToken } = useAuthSession()
|
||||
const { detail } = useLocalSearchParams<{ detail: string }>()
|
||||
@@ -28,6 +28,7 @@ export default function SectionLinkTask({ refreshing }: { refreshing: boolean })
|
||||
const update = useSelector((state: any) => state.taskUpdate)
|
||||
const dispatch = useDispatch()
|
||||
const [selectLink, setSelectLink] = useState<Props | null>(null)
|
||||
const entityUser = useSelector((state: any) => state.user);
|
||||
|
||||
async function handleLoad() {
|
||||
try {
|
||||
@@ -101,18 +102,25 @@ export default function SectionLinkTask({ refreshing }: { refreshing: boolean })
|
||||
Linking.openURL(urlCompleted(String(selectLink?.link)))
|
||||
}}
|
||||
/>
|
||||
<MenuItemRow
|
||||
icon={<Ionicons name="trash" color="black" size={25} />}
|
||||
title="Hapus"
|
||||
onPress={() => {
|
||||
setModal(false)
|
||||
AlertKonfirmasi({
|
||||
title: 'Konfirmasi',
|
||||
desc: 'Apakah Anda yakin ingin menghapus link ini? Link yang dihapus tidak dapat dikembalikan',
|
||||
onPress: () => { handleDelete() }
|
||||
})
|
||||
}}
|
||||
/>
|
||||
{
|
||||
(entityUser.role != "user" && entityUser.role != "coadmin") || isMemberDivision
|
||||
?
|
||||
<MenuItemRow
|
||||
icon={<Ionicons name="trash" color="black" size={25} />}
|
||||
title="Hapus"
|
||||
onPress={() => {
|
||||
setModal(false)
|
||||
AlertKonfirmasi({
|
||||
title: 'Konfirmasi',
|
||||
desc: 'Apakah Anda yakin ingin menghapus link ini? Link yang dihapus tidak dapat dikembalikan',
|
||||
onPress: () => { handleDelete() }
|
||||
})
|
||||
}}
|
||||
/>
|
||||
:
|
||||
<></>
|
||||
}
|
||||
|
||||
</View>
|
||||
</DrawerBottom>
|
||||
</>
|
||||
|
||||
@@ -26,8 +26,9 @@ type Props = {
|
||||
position: string;
|
||||
};
|
||||
|
||||
export default function SectionMemberTask({ refreshing }: { refreshing: boolean }) {
|
||||
export default function SectionMemberTask({ refreshing, isMemberDivision }: { refreshing: boolean, isMemberDivision: boolean }) {
|
||||
const [isModal, setModal] = useState(false);
|
||||
const entityUser = useSelector((state: any) => state.user);
|
||||
const { token, decryptToken } = useAuthSession();
|
||||
const { id, detail } = useLocalSearchParams<{ id: string; detail: string }>();
|
||||
const [data, setData] = useState<Props[]>([]);
|
||||
@@ -165,24 +166,31 @@ export default function SectionMemberTask({ refreshing }: { refreshing: boolean
|
||||
}}
|
||||
/>
|
||||
|
||||
<MenuItemRow
|
||||
icon={
|
||||
<MaterialCommunityIcons
|
||||
name="account-remove"
|
||||
color="black"
|
||||
size={25}
|
||||
|
||||
{
|
||||
(entityUser.role != "user" && entityUser.role != "coadmin") || isMemberDivision
|
||||
?
|
||||
<MenuItemRow
|
||||
icon={
|
||||
<MaterialCommunityIcons
|
||||
name="account-remove"
|
||||
color="black"
|
||||
size={25}
|
||||
/>
|
||||
}
|
||||
title="Keluarkan"
|
||||
onPress={() => {
|
||||
setModal(false)
|
||||
AlertKonfirmasi({
|
||||
title: "Konfirmasi",
|
||||
desc: "Apakah Anda yakin ingin mengeluarkan anggota?",
|
||||
onPress: () => { handleDeleteMember() },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
}
|
||||
title="Keluarkan"
|
||||
onPress={() => {
|
||||
setModal(false)
|
||||
AlertKonfirmasi({
|
||||
title: "Konfirmasi",
|
||||
desc: "Apakah Anda yakin ingin mengeluarkan anggota?",
|
||||
onPress: () => { handleDeleteMember() },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
:
|
||||
<></>
|
||||
}
|
||||
</View>
|
||||
</DrawerBottom>
|
||||
</>
|
||||
|
||||
@@ -26,8 +26,9 @@ type Props = {
|
||||
dateEnd: string;
|
||||
}
|
||||
|
||||
export default function SectionTanggalTugasTask({ refreshing }: { refreshing: boolean }) {
|
||||
export default function SectionTanggalTugasTask({ refreshing, isMemberDivision }: { refreshing: boolean, isMemberDivision: boolean }) {
|
||||
const dispatch = useDispatch()
|
||||
const entityUser = useSelector((state: any) => state.user);
|
||||
const update = useSelector((state: any) => state.taskUpdate)
|
||||
const [isModal, setModal] = useState(false)
|
||||
const [isSelect, setSelect] = useState(false)
|
||||
@@ -155,24 +156,6 @@ export default function SectionTanggalTugasTask({ refreshing }: { refreshing: bo
|
||||
|
||||
<DrawerBottom animation="slide" isVisible={isModal} setVisible={setModal} title="Menu">
|
||||
<View style={Styles.rowItemsCenter}>
|
||||
<MenuItemRow
|
||||
icon={<MaterialCommunityIcons name="list-status" color="black" size={25} />}
|
||||
title="Update Status"
|
||||
onPress={() => {
|
||||
setModal(false)
|
||||
setTimeout(() => {
|
||||
setSelect(true)
|
||||
}, 600);
|
||||
}}
|
||||
/>
|
||||
<MenuItemRow
|
||||
icon={<MaterialCommunityIcons name="pencil-outline" color="black" size={25} />}
|
||||
title="Edit Tugas"
|
||||
onPress={() => {
|
||||
setModal(false)
|
||||
router.push(`./update/${tugas.id}`)
|
||||
}}
|
||||
/>
|
||||
<MenuItemRow
|
||||
icon={
|
||||
<MaterialCommunityIcons
|
||||
@@ -189,24 +172,57 @@ export default function SectionTanggalTugasTask({ refreshing }: { refreshing: bo
|
||||
}, 600)
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<View style={[Styles.rowItemsCenter, Styles.mt15]}>
|
||||
<MenuItemRow
|
||||
icon={<Ionicons name="trash" color="black" size={25} />}
|
||||
title="Hapus Tugas"
|
||||
onPress={() => {
|
||||
setModal(false)
|
||||
AlertKonfirmasi({
|
||||
title: 'Konfirmasi',
|
||||
desc: 'Apakah anda yakin ingin menghapus data ini?',
|
||||
onPress: () => {
|
||||
handleDelete()
|
||||
}
|
||||
})
|
||||
{
|
||||
(entityUser.role != "user" && entityUser.role != "coadmin") || isMemberDivision
|
||||
?
|
||||
<>
|
||||
<MenuItemRow
|
||||
icon={<MaterialCommunityIcons name="list-status" color="black" size={25} />}
|
||||
title="Update Status"
|
||||
onPress={() => {
|
||||
setModal(false)
|
||||
setTimeout(() => {
|
||||
setSelect(true)
|
||||
}, 600);
|
||||
}}
|
||||
/>
|
||||
<MenuItemRow
|
||||
icon={<MaterialCommunityIcons name="pencil-outline" color="black" size={25} />}
|
||||
title="Edit Tugas"
|
||||
onPress={() => {
|
||||
setModal(false)
|
||||
router.push(`./update/${tugas.id}`)
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
:
|
||||
<></>
|
||||
}
|
||||
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
{
|
||||
(entityUser.role != "user" && entityUser.role != "coadmin") || isMemberDivision
|
||||
?
|
||||
<View style={[Styles.rowItemsCenter, Styles.mt15]}>
|
||||
<MenuItemRow
|
||||
icon={<Ionicons name="trash" color="black" size={25} />}
|
||||
title="Hapus Tugas"
|
||||
onPress={() => {
|
||||
setModal(false)
|
||||
AlertKonfirmasi({
|
||||
title: 'Konfirmasi',
|
||||
desc: 'Apakah anda yakin ingin menghapus data ini?',
|
||||
onPress: () => {
|
||||
handleDelete()
|
||||
}
|
||||
})
|
||||
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
:
|
||||
<></>
|
||||
}
|
||||
</DrawerBottom>
|
||||
|
||||
<ModalSelect
|
||||
|
||||
@@ -3,9 +3,9 @@ import { View } from "react-native";
|
||||
import Toast from "react-native-toast-message";
|
||||
import Text from "./Text";
|
||||
|
||||
export default function ToastCustom() {
|
||||
export default function ToastCustom({ position }: { position?: 'top' | 'bottom' }) {
|
||||
return (
|
||||
<Toast autoHide onPress={() => Toast.hide()} visibilityTime={1500} position="bottom" config={{
|
||||
<Toast autoHide onPress={() => Toast.hide()} visibilityTime={1500} position={position || 'bottom'} config={{
|
||||
small: ({ text1 }) => (
|
||||
<View style={[Styles.toastContainer]}>
|
||||
<Text style={{ fontSize: 12 }}>{text1}</Text>
|
||||
|
||||
@@ -515,7 +515,7 @@ const Styles = StyleSheet.create({
|
||||
wrapBtnTab: {
|
||||
justifyContent: 'space-between',
|
||||
flexDirection: 'row',
|
||||
marginBottom: 15,
|
||||
marginBottom: 10,
|
||||
borderRadius: 20,
|
||||
padding: 5,
|
||||
backgroundColor: 'white',
|
||||
|
||||
@@ -138,12 +138,8 @@ export const apiDeletePosition = async (data: { user: string, isActive: boolean
|
||||
};
|
||||
|
||||
export const apiEditPosition = async (data: { user: string, name: string, idGroup: string }, id: string) => {
|
||||
await api.put(`mobile/position/${id}`, data).then(response => {
|
||||
return response.data;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
const response = await api.put(`mobile/position/${id}`, data)
|
||||
return response.data
|
||||
};
|
||||
|
||||
export const apiGetUser = async ({ user, active, search, group, page }: { user: string, active: string, search: string, group?: string, page?: number }) => {
|
||||
|
||||
@@ -7,7 +7,9 @@ const divisionCreate = createSlice({
|
||||
idGroup: "",
|
||||
name: "",
|
||||
desc: "",
|
||||
}, member: [], admin: [],
|
||||
},
|
||||
member: [],
|
||||
admin: [],
|
||||
},
|
||||
reducers: {
|
||||
setFormCreateDivision: (state, action) => {
|
||||
|
||||
Reference in New Issue
Block a user