Merge pull request 'amalia/01-agustus-25' (#11) from amalia/01-agustus-25 into join

Reviewed-on: bip/mobile-darmasaba#11
This commit is contained in:
2025-08-01 17:41:33 +08:00
17 changed files with 163 additions and 136 deletions

View File

@@ -42,6 +42,7 @@
} }
], ],
"expo-font", "expo-font",
"expo-image-picker",
"expo-web-browser", "expo-web-browser",
[ [
"@react-native-firebase/app", "@react-native-firebase/app",

View File

@@ -34,7 +34,7 @@ export default function EditBanner() {
const pickImageAsync = async () => { const pickImageAsync = async () => {
let result = await ImagePicker.launchImageLibraryAsync({ let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ["images"], mediaTypes: ["images"],
allowsEditing: true, allowsEditing: false,
quality: 1, quality: 1,
aspect: [1535, 450], aspect: [1535, 450],
}); });

View File

@@ -33,7 +33,7 @@ export default function CreateBanner() {
const pickImageAsync = async () => { const pickImageAsync = async () => {
let result = await ImagePicker.launchImageLibraryAsync({ let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ["images"], mediaTypes: ["images"],
allowsEditing: true, allowsEditing: false,
quality: 1, quality: 1,
aspect: [1535, 450], aspect: [1535, 450],
}); });

View File

@@ -84,6 +84,9 @@ export default function CreateDiscussionGeneral() {
checkForm(); checkForm();
}, [error, dataForm]); }, [error, dataForm]);
useEffect(() => {
dispatch(setMemberChoose([]))
}, [])
function handleBack() { function handleBack() {
dispatch(setMemberChoose([])) dispatch(setMemberChoose([]))
@@ -101,7 +104,7 @@ export default function CreateDiscussionGeneral() {
dispatch(setUpdateDiscussionGeneralDetail(!update)) dispatch(setUpdateDiscussionGeneralDetail(!update))
Toast.show({ type: 'small', text1: 'Berhasil menambahkan data', }) Toast.show({ type: 'small', text1: 'Berhasil menambahkan data', })
router.back() router.back()
}else{ } else {
Toast.show({ type: 'small', text1: response.message, }) Toast.show({ type: 'small', text1: response.message, })
} }
} catch (error) { } catch (error) {
@@ -171,6 +174,7 @@ export default function CreateDiscussionGeneral() {
error={error.desc} error={error.desc}
errorText="Diskusi tidak boleh kosong" errorText="Diskusi tidak boleh kosong"
onChange={(val) => { validationForm("desc", val) }} onChange={(val) => { validationForm("desc", val) }}
multiline
/> />
<ButtonSelect <ButtonSelect
value="Pilih Anggota" value="Pilih Anggota"

View File

@@ -135,6 +135,7 @@ export default function EditDiscussionGeneral() {
value={dataForm.desc} value={dataForm.desc}
errorText="Diskusi tidak boleh kosong" errorText="Diskusi tidak boleh kosong"
onChange={(val) => validationForm("desc", val)} onChange={(val) => validationForm("desc", val)}
multiline
/> />
</View> </View>
</ScrollView> </ScrollView>

View File

@@ -10,6 +10,8 @@ import { stringToDateTime } from "@/lib/fun_stringToDate";
import { Stack, router, useLocalSearchParams } from "expo-router"; import { Stack, router, useLocalSearchParams } from "expo-router";
import { useState } from "react"; import { useState } from "react";
import { import {
KeyboardAvoidingView,
Platform,
SafeAreaView, SafeAreaView,
ScrollView, ScrollView,
View View
@@ -141,94 +143,99 @@ export default function CalendarDivisionCreate() {
), ),
}} }}
/> />
<ScrollView> <KeyboardAvoidingView
<View style={[Styles.p15, Styles.mb100]}> behavior={Platform.OS === 'ios' ? 'padding' : undefined}
<InputForm keyboardVerticalOffset={110}
label="Nama Acara" >
type="default" <ScrollView>
placeholder="Nama Acara" <View style={[Styles.p15]}>
required <InputForm
bg="white" label="Nama Acara"
value={data.title} type="default"
onChange={(val) => validationForm("title", val)} placeholder="Nama Acara"
error={error.title} required
errorText="Nama acara tidak boleh kosong" bg="white"
/> value={data.title}
<InputDate onChange={(val) => validationForm("title", val)}
onChange={(val) => validationForm("dateStart", val)} error={error.title}
mode="date" errorText="Nama acara tidak boleh kosong"
value={data.dateStart} />
label="Tanggal Acara" <InputDate
required onChange={(val) => validationForm("dateStart", val)}
error={error.dateStart} mode="date"
errorText="Tanggal acara tidak boleh kosong" value={data.dateStart}
placeholder="Pilih Tanggal Acara" label="Tanggal Acara"
/> required
<View style={[Styles.rowSpaceBetween, Styles.mv10]}> error={error.dateStart}
<View style={[{ width: "48%" }]}> errorText="Tanggal acara tidak boleh kosong"
<InputDate placeholder="Pilih Tanggal Acara"
onChange={(val) => validationForm("timeStart", val)} />
mode="time" <View style={[Styles.rowSpaceBetween, Styles.mv10]}>
value={data.timeStart} <View style={[{ width: "48%" }]}>
label="Waktu Awal" <InputDate
required onChange={(val) => validationForm("timeStart", val)}
error={error.timeStart} mode="time"
errorText="Waktu awal tidak valid" value={data.timeStart}
placeholder="--:--" label="Waktu Awal"
/> required
</View> error={error.timeStart}
<View style={[{ width: "48%" }]}> errorText="Waktu awal tidak valid"
<InputDate placeholder="--:--"
onChange={(val) => validationForm("timeEnd", val)} />
mode="time" </View>
value={data.timeEnd} <View style={[{ width: "48%" }]}>
label="Waktu Akhir" <InputDate
required onChange={(val) => validationForm("timeEnd", val)}
error={error.timeEnd} mode="time"
errorText="Waktu akhir tidak valid" value={data.timeEnd}
placeholder="--:--" label="Waktu Akhir"
/> required
error={error.timeEnd}
errorText="Waktu akhir tidak valid"
placeholder="--:--"
/>
</View>
</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> </View>
<InputForm </ScrollView>
label="Link Meet" </KeyboardAvoidingView>
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>
<ModalSelect <ModalSelect
category={"type-event-repeat"} category={"type-event-repeat"}

View File

@@ -110,10 +110,6 @@ export default function DocumentDivision() {
} }
} }
useEffect(() => {
handleLoad(true);
}, [path]);
const handleCheckboxChange = (index: number) => { const handleCheckboxChange = (index: number) => {
setDariSelectAll(false); setDariSelectAll(false);
if (selectedFiles.some((i: any) => i.id == data[index].id)) { if (selectedFiles.some((i: any) => i.id == data[index].id)) {
@@ -308,6 +304,10 @@ export default function DocumentDivision() {
setRefreshing(false) setRefreshing(false)
}; };
useEffect(() => {
handleLoad(true);
}, [path]);
return ( return (
<SafeAreaView> <SafeAreaView>
<Stack.Screen <Stack.Screen
@@ -550,9 +550,7 @@ export default function DocumentDivision() {
title="Ganti Nama" title="Ganti Nama"
isVisible={isRename} isVisible={isRename}
setVisible={() => { setRename(false) }} setVisible={() => { setRename(false) }}
onSubmit={() => { onSubmit={() => { handleRename() }}
handleRename();
}}
disableSubmit={bodyRename.name == ""} disableSubmit={bodyRename.name == ""}
> >
<View> <View>

View File

@@ -36,16 +36,18 @@ export default function TaskDivisionAddFile() {
const pickDocumentAsync = async () => { const pickDocumentAsync = async () => {
let result = await DocumentPicker.getDocumentAsync({ let result = await DocumentPicker.getDocumentAsync({
type: ["*/*"], type: ["*/*"],
multiple: false, multiple: true,
}); });
if (!result.canceled) { if (!result.canceled) {
if (result.assets?.[0].uri) { for (let i = 0; i < result.assets?.length; i++) {
const check = await handleCheckFile(result.assets?.[0]); if (result.assets?.[i].uri) {
if (check) { const check = await handleCheckFile(result.assets?.[i]);
setFileForm([...fileForm, result.assets?.[0]]); if (check) {
setListFile([...listFile, result.assets?.[0].name]); setFileForm((prev) => [...prev, result.assets?.[i]]);
} else { setListFile((prev) => [...prev, result.assets?.[i].name]);
Toast.show({ type: 'small', text1: 'File sudah ada', }) } else {
Toast.show({ type: 'small', text1: 'File sudah ada', })
}
} }
} }
} }

View File

@@ -52,11 +52,13 @@ export default function CreateTaskDivision() {
const pickDocumentAsync = async () => { const pickDocumentAsync = async () => {
let result = await DocumentPicker.getDocumentAsync({ let result = await DocumentPicker.getDocumentAsync({
type: ["*/*"], type: ["*/*"],
multiple: false multiple: true
}); });
if (!result.canceled) { if (!result.canceled) {
if (result.assets[0].uri) { for (let i = 0; i < result.assets?.length; i++) {
setFileForm([...fileForm, result.assets[0]]) if (result.assets[i].uri) {
setFileForm((prev) => [...prev, result.assets[i]])
}
} }
} }
}; };

View File

@@ -187,7 +187,7 @@ export default function EditProfile() {
const pickImageAsync = async () => { const pickImageAsync = async () => {
let result = await ImagePicker.launchImageLibraryAsync({ let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ["images"], mediaTypes: ["images"],
allowsEditing: true, allowsEditing: false,
quality: 1, quality: 1,
aspect: [1, 1], aspect: [1, 1],
}); });

View File

@@ -36,6 +36,7 @@ export default function CreateMember() {
const [chooseGender, setChooseGender] = useState({ val: "", label: "" }); const [chooseGender, setChooseGender] = useState({ val: "", label: "" });
const [selectedImage, setSelectedImage] = useState<string | undefined>(undefined); const [selectedImage, setSelectedImage] = useState<string | undefined>(undefined);
const entityUser = useSelector((state: any) => state.user); const entityUser = useSelector((state: any) => state.user);
const entities = useSelector((state: any) => state.entities)
const [isSelect, setSelect] = useState(false); const [isSelect, setSelect] = useState(false);
const [disableBtn, setDisableBtn] = useState(true) const [disableBtn, setDisableBtn] = useState(true)
const [valChoose, setValChoose] = useState("") const [valChoose, setValChoose] = useState("")
@@ -142,6 +143,12 @@ export default function CreateMember() {
checkForm() checkForm()
}, [error, dataForm]) }, [error, dataForm])
useEffect(() => {
if(entityUser.role !="supadmin" && entityUser.role != "developer"){
validationForm("group", entities.idGroup, entities.group)
}
}, [])
async function handleCreate() { async function handleCreate() {
try { try {
@@ -162,7 +169,7 @@ export default function CreateMember() {
fd.append("file", "undefined") fd.append("file", "undefined")
} }
const response = await apiCreateUser(fd) const response = await apiCreateUser({data: fd})
if (response.success) { if (response.success) {
Toast.show({ type: 'small', text1: 'Berhasil menambahkan data', }) Toast.show({ type: 'small', text1: 'Berhasil menambahkan data', })
dispatch(setUpdateMember(!update)) dispatch(setUpdateMember(!update))
@@ -179,7 +186,7 @@ export default function CreateMember() {
const pickImageAsync = async () => { const pickImageAsync = async () => {
let result = await ImagePicker.launchImageLibraryAsync({ let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ["images"], mediaTypes: ["images"],
allowsEditing: true, allowsEditing: false,
quality: 1, quality: 1,
aspect: [1, 1], aspect: [1, 1],
}); });

View File

@@ -212,7 +212,7 @@ export default function EditMember() {
const pickImageAsync = async () => { const pickImageAsync = async () => {
let result = await ImagePicker.launchImageLibraryAsync({ let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ["images"], mediaTypes: ["images"],
allowsEditing: true, allowsEditing: false,
quality: 1, quality: 1,
aspect: [1, 1], aspect: [1, 1],
}); });

View File

@@ -30,16 +30,19 @@ export default function ProjectAddFile() {
const pickDocumentAsync = async () => { const pickDocumentAsync = async () => {
let result = await DocumentPicker.getDocumentAsync({ let result = await DocumentPicker.getDocumentAsync({
type: ["*/*"], type: ["*/*"],
multiple: false multiple: true
}); });
if (!result.canceled) { if (!result.canceled) {
if (result.assets?.[0].uri) { for (let i = 0; i < result.assets?.length; i++) {
const check = await handleCheckFile(result.assets?.[0]) if (result.assets?.[i].uri) {
if (check) { const check = await handleCheckFile(result.assets?.[i])
setFileForm([...fileForm, result.assets?.[0]]) if (check) {
setListFile([...listFile, result.assets?.[0].name]) setFileForm((prev) => [...prev, result.assets?.[i]])
} else { setListFile((prev) => [...prev, result.assets?.[i].name])
Toast.show({ type: 'small', text1: 'File sudah ada', }) } else {
Toast.show({ type: 'small', text1: 'File yg telah terupload tidak bisa diupload ulang', })
}
} }
} }
} }

View File

@@ -146,11 +146,13 @@ export default function CreateProject() {
const pickDocumentAsync = async () => { const pickDocumentAsync = async () => {
let result = await DocumentPicker.getDocumentAsync({ let result = await DocumentPicker.getDocumentAsync({
type: ["*/*"], type: ["*/*"],
multiple: false multiple: true
}); });
if (!result.canceled) { if (!result.canceled) {
if (result.assets[0].uri) { for (let i = 0; i < result.assets?.length; i++) {
setFileForm([...fileForm, result.assets[0]]) if (result.assets[i].uri) {
setFileForm((prev) => [...prev, result.assets[i]])
}
} }
} }
}; };

View File

@@ -28,7 +28,7 @@ export default function HeaderRightDocument({ path }: { path: string }) {
async function handleCreateFolder() { async function handleCreateFolder() {
try { try {
const hasil = await decryptToken(String(token?.current)) const hasil = await decryptToken(String(token?.current))
const response = await apiCreateFolderDocument({ user: hasil, name, path, idDivision: id }) const response = await apiCreateFolderDocument({ data: { user: hasil, name, path, idDivision: id } })
if (response.success) { if (response.success) {
Toast.show({ type: 'small', text1: 'Berhasil membuat folder baru', }) Toast.show({ type: 'small', text1: 'Berhasil membuat folder baru', })
dispatch(setUpdateDokumen(!update)) dispatch(setUpdateDokumen(!update))

View File

@@ -27,7 +27,7 @@ type Props = {
export function InputDate({ label, value, placeholder, onChange, info, disable, error, errorText, required, mode, round, width, }: Props) { export function InputDate({ label, value, placeholder, onChange, info, disable, error, errorText, required, mode, round, width, }: Props) {
const [modal, setModal] = useState(false); const [modal, setModal] = useState(false);
const onChangeDate = ({ type }: { type: string }, selectedDate: any) => { const onChangeDate = (type: string, selectedDate: any) => {
if (type === "set") { if (type === "set") {
if (mode == "date") { if (mode == "date") {
onChange(dayjs(selectedDate).format("DD-MM-YYYY")) onChange(dayjs(selectedDate).format("DD-MM-YYYY"))
@@ -60,10 +60,10 @@ export function InputDate({ label, value, placeholder, onChange, info, disable,
{ {
modal && ( modal && (
<DateTimePicker <DateTimePicker
value={value ? stringToDate(value) : new Date()} value={new Date()}
mode={mode} mode={mode}
display="default" display="default"
onChange={onChangeDate} onChange={(event, date) => { onChangeDate(event.type, date) }}
onTouchCancel={() => setModal(false)} onTouchCancel={() => setModal(false)}
/> />
) )

View File

@@ -2,8 +2,8 @@ import axios from 'axios';
const api = axios.create({ const api = axios.create({
// baseURL: 'http://10.0.2.2:3000/api', // baseURL: 'http://10.0.2.2:3000/api',
baseURL: 'https://stg-darmasaba.wibudev.com/api', // baseURL: 'https://stg-darmasaba.wibudev.com/api',
// baseURL: 'http://192.168.1.135:3000/api', baseURL: 'http://192.168.1.89:3000/api',
}); });
export const apiCheckPhoneLogin = async (body: { phone: string }) => { export const apiCheckPhoneLogin = async (body: { phone: string }) => {
@@ -150,7 +150,7 @@ export const apiGetUser = async ({ user, active, search, group, page }: { user:
}; };
export const apiCreateUser = async (data: FormData) => { export const apiCreateUser = async ({data}: {data: FormData}) => {
const response = await api.post('/mobile/user', data, { const response = await api.post('/mobile/user', data, {
headers: { headers: {
'Content-Type': 'multipart/form-data', 'Content-Type': 'multipart/form-data',
@@ -219,7 +219,7 @@ export const apiEditDiscussionGeneral = async (data: { user: string, title: stri
}; };
export const apiCreateDiscussionGeneral = async ({ data }: { data: { idGroup: string, title: string, desc: string, user: string, member: [] } }) => { export const apiCreateDiscussionGeneral = async ({ data }: { data: { idGroup: string, title: string, desc: string, user: string, member: [] } }) => {
const response = await api.post(`/mobile/discussion-general/`, data) const response = await api.post(`/mobile/discussion-general`, data)
return response.data; return response.data;
}; };
@@ -604,7 +604,7 @@ export const apiGetDocumentInformasi = async ({ user, item, cat }: { user: strin
}; };
export const apiDocumentRename = async (data: { name: string, user: string, id: string, path: string, idDivision: string, extension: string }) => { export const apiDocumentRename = async (data: { name: string, user: string, id: string, path: string, idDivision: string, extension: string }) => {
const response = await api.put(`/mobile/document/`, data) const response = await api.put(`/mobile/document`, data)
return response.data; return response.data;
}; };
@@ -613,8 +613,8 @@ export const apiDocumentDelete = async (data: { user: string, data: any[] }) =>
return response.data return response.data
}; };
export const apiCreateFolderDocument = async (data: { name: string, path: string, idDivision: string, user: string }) => { export const apiCreateFolderDocument = async ({ data }: { data: { name: string, path: string, idDivision: string, user: string } }) => {
const response = await api.post(`/mobile/document/`, data) const response = await api.post(`/mobile/document`, data)
return response.data; return response.data;
}; };
@@ -646,12 +646,12 @@ export const apiShareDocument = async (data: { dataDivision: any[], dataItem: an
}; };
export const apiRegisteredToken = async (data: { user: string, token: string }) => { export const apiRegisteredToken = async (data: { user: string, token: string }) => {
const response = await api.post(`/mobile/auth-token/`, data) const response = await api.post(`/mobile/auth-token`, data)
return response.data; return response.data;
}; };
export const apiUnregisteredToken = async (data: { user: string, token: string }) => { export const apiUnregisteredToken = async (data: { user: string, token: string }) => {
const response = await api.put(`/mobile/auth-token/`, data) const response = await api.put(`/mobile/auth-token`, data)
return response.data; return response.data;
}; };
@@ -661,6 +661,6 @@ export const apiGetNotification = async ({ user, page }: { user: string, page?:
}; };
export const apiReadOneNotification = async (data: { user: string, id: string }) => { export const apiReadOneNotification = async (data: { user: string, id: string }) => {
const response = await api.put(`/mobile/home/notification/`, data) const response = await api.put(`/mobile/home/notification`, data)
return response.data; return response.data;
}; };