upd: task division

Deskripsi:
- tambah task division
- hapus task division yg telah dibatalkan
- akses user sesuai dengan role

No Issuese
This commit is contained in:
amel
2025-05-27 12:20:47 +08:00
parent bc74be122d
commit 42f6257d03
9 changed files with 672 additions and 64 deletions

View File

@@ -14,7 +14,7 @@ export default function TaskDivisionCancel() {
const { id, detail } = useLocalSearchParams<{ id: string; detail: string }>();
const { token, decryptToken } = useAuthSession();
const dispatch = useDispatch();
const update = useSelector((state: any) => state.projectUpdate);
const update = useSelector((state: any) => state.taskUpdate);
const [reason, setReason] = useState("");
const [error, setError] = useState(false);
const [disable, setDisable] = useState(false);

View File

@@ -50,7 +50,6 @@ export default function DetailTaskDivision() {
handleLoad()
}, [update.progress, update.data])
return (
<SafeAreaView>
<Stack.Screen
@@ -58,7 +57,7 @@ export default function DetailTaskDivision() {
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
headerTitle: loading ? 'Loading...' : data?.title,
headerTitleAlign: 'center',
headerRight: () => <HeaderRightTaskDetail id={detail} />,
headerRight: () => <HeaderRightTaskDetail id={detail} division={id} status={data?.status}/>,
}}
/>
<ScrollView>

View File

@@ -1,47 +1,220 @@
import BorderBottomItem from "@/components/borderBottomItem";
import ButtonBackHeader from "@/components/buttonBackHeader";
import ButtonSaveHeader from "@/components/buttonSaveHeader";
import ButtonSelect from "@/components/buttonSelect";
import DrawerBottom from "@/components/drawerBottom";
import ImageUser from "@/components/imageNew";
import { InputForm } from "@/components/inputForm";
import MenuItemRow from "@/components/menuItemRow";
import ModalSelect from "@/components/modalSelect";
import SectionListAddTask from "@/components/project/sectionListAddTask";
import Styles from "@/constants/Styles";
import { apiCreateTask } from "@/lib/api";
import { setMemberChoose } from "@/lib/memberChoose";
import { setTaskCreate } from "@/lib/taskCreate";
import { setUpdateTask } from "@/lib/taskUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons";
import * as DocumentPicker from "expo-document-picker";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { SafeAreaView, ScrollView, ToastAndroid, View } from "react-native";
import { useEffect, useState } from "react";
import { SafeAreaView, ScrollView, Text, ToastAndroid, View } from "react-native";
import { useDispatch, useSelector } from "react-redux";
export default function CreateTaskDivision() {
const { id } = useLocalSearchParams()
const { id } = useLocalSearchParams();
const { token, decryptToken } = useAuthSession();
const dispatch = useDispatch();
const [isSelect, setSelect] = useState(false);
const [valChoose, setValChoose] = useState("");
const entitiesMember = useSelector((state: any) => state.memberChoose);
const taskCreate = useSelector((state: any) => state.taskCreate);
const update = useSelector((state: any) => state.taskUpdate)
const [fileForm, setFileForm] = useState<any[]>([])
const [indexDelFile, setIndexDelFile] = useState<number>(0)
const [title, setTitle] = useState('')
const [error, setError] = useState(false);
const [isModal, setModal] = useState(false)
let hitung = 0;
useEffect(() => {
if (hitung == 0) {
dispatch(setTaskCreate([]));
dispatch(setMemberChoose([]));
}
hitung++;
}, []);
const pickDocumentAsync = async () => {
let result = await DocumentPicker.getDocumentAsync({
type: ["*/*"],
multiple: false
});
if (!result.canceled) {
if (result.assets[0].uri) {
setFileForm([...fileForm, result.assets[0]])
}
}
};
function deleteFile(index: number) {
setFileForm([...fileForm.filter((val, i) => i !== index)])
setModal(false)
}
function handleBack() {
dispatch(setTaskCreate([]));
dispatch(setMemberChoose([]));
router.back();
}
async function handleCreate() {
try {
const hasil = await decryptToken(String(token?.current))
const fd = new FormData()
for (let i = 0; i < fileForm.length; i++) {
fd.append(`file${i}`, {
uri: fileForm[i].uri,
type: 'application/octet-stream',
name: fileForm[i].name,
} as any);
}
fd.append("data", JSON.stringify(
{ user: hasil, task: taskCreate, member: entitiesMember, title, idDivision: id }
))
const response = await apiCreateTask(fd)
if (response.success) {
dispatch(setUpdateTask({ ...update, data: !update.data }))
ToastAndroid.show('Berhasil menambahkan data', ToastAndroid.SHORT)
handleBack()
} else {
ToastAndroid.show(response.message, ToastAndroid.SHORT)
}
} catch (error) {
console.error(error)
}
}
return (
<SafeAreaView>
<Stack.Screen
options={{
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
headerLeft: () => (
<ButtonBackHeader
onPress={() => {
handleBack();
}}
/>
),
headerTitle: `Tambah Tugas`,
headerTitleAlign: 'center',
headerRight: () => <ButtonSaveHeader category="create" onPress={() => {
ToastAndroid.show('Berhasil menambah data', ToastAndroid.SHORT)
router.push('../task?status=0')
}} />
headerTitleAlign: "center",
headerRight: () => (
<ButtonSaveHeader
disable={title == "" || entitiesMember.length == 0 || taskCreate.length == 0}
category="create"
onPress={() => { handleCreate() }}
/>
),
}}
/>
<ScrollView>
<View style={[Styles.p15, Styles.mb100]}>
<InputForm label="Judul Tugas" type="default" placeholder="Judul Tugas" required />
<ButtonSelect value="Tambah Tanggal & Tugas" />
<ButtonSelect value="Upload File" />
<ButtonSelect value="Tambah Anggota" />
{/* <ButtonForm
text="SIMPAN"
onPress={() => {
AlertKonfirmasi({
title: 'Konfirmasi',
desc: 'Apakah anda yakin ingin menambahkan data?',
onPress: () => {
ToastAndroid.show('Berhasil menambahkan data', ToastAndroid.SHORT)
router.push('../task?status=0')
}
})
}} /> */}
<InputForm
label="Judul Tugas"
type="default"
placeholder="Judul Tugas"
required
value={title}
onChange={(val) => {
setTitle(val);
val == "" || val == "null" ? setError(true) : setError(false);
}}
error={error}
errorText="Judul Tugas tidak boleh kosong"
/>
<ButtonSelect value="Tambah Tanggal & Tugas" onPress={() => { router.push(`/division/${id}/task/create/task`); }} />
<ButtonSelect value="Upload File" onPress={pickDocumentAsync} />
<ButtonSelect value="Tambah Anggota" onPress={() => { router.push(`/division/${id}/task/create/member`); }} />
<SectionListAddTask />
{
fileForm.length > 0 && (
<View style={[Styles.mb15]}>
<Text style={[Styles.textDefaultSemiBold, Styles.mv05]}>File</Text>
<View style={[Styles.wrapPaper]}>
{
fileForm.map((item, index) => (
<BorderBottomItem
key={index}
borderType="all"
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
title={item.name}
titleWeight="normal"
onPress={() => { setIndexDelFile(index); setModal(true) }}
/>
))
}
</View>
</View>
)
}
{entitiesMember.length > 0 && (
<View>
<View style={[Styles.rowSpaceBetween, Styles.mv05]}>
<Text>Anggota</Text>
<Text>Total {entitiesMember.length} Anggota</Text>
</View>
<View style={[Styles.borderAll, Styles.round10, Styles.p10]}>
{entitiesMember.map(
(item: { img: any; name: any }, index: any) => {
return (
<BorderBottomItem
key={index}
borderType="bottom"
icon={
<ImageUser
src={`https://wibu-storage.wibudev.com/api/files/${item.img}`}
size="sm"
/>
}
title={item.name}
/>
);
}
)}
</View>
</View>
)}
</View>
</ScrollView>
<DrawerBottom animation="slide" isVisible={isModal} setVisible={setModal} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<Ionicons name="trash" color="black" size={25} />}
title="Hapus"
onPress={() => { deleteFile(indexDelFile) }}
/>
</View>
</DrawerBottom>
<ModalSelect
category={"member"}
close={setSelect}
onSelect={(value) => { }}
title={"Pilih Anggota"}
open={isSelect}
idParent={''}
valChoose={valChoose}
/>
</SafeAreaView>
)
}
);
}

View File

@@ -0,0 +1,139 @@
import ButtonBackHeader from "@/components/buttonBackHeader";
import ButtonSaveHeader from "@/components/buttonSaveHeader";
import ImageUser from "@/components/imageNew";
import ImageWithLabel from "@/components/imageWithLabel";
import InputSearch from "@/components/inputSearch";
import Styles from "@/constants/Styles";
import { apiGetDivisionMember } from "@/lib/api";
import { setMemberChoose } from "@/lib/memberChoose";
import { useAuthSession } from "@/providers/AuthProvider";
import { AntDesign } from "@expo/vector-icons";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
import { Pressable, SafeAreaView, ScrollView, Text, ToastAndroid, View } from "react-native";
import { useDispatch, useSelector } from "react-redux";
type Props = {
idUser: string,
name: string,
img: string
}
export default function AddMemberCreateTask() {
const dispatch = useDispatch()
const { token, decryptToken } = useAuthSession()
const { id } = useLocalSearchParams<{ id: string, detail: string }>()
const [dataOld, setDataOld] = useState<Props[]>([])
const [data, setData] = useState<Props[]>([])
const [selectMember, setSelectMember] = useState<any[]>([])
const [search, setSearch] = useState('')
const entitiesMember = useSelector((state: any) => state.memberChoose)
async function handleLoadMemberDivision() {
const hasil = await decryptToken(String(token?.current))
const responMemberDivision = await apiGetDivisionMember({ id: id, user: hasil, search: search })
setData(responMemberDivision.data)
if (entitiesMember.length > 0) {
setSelectMember(entitiesMember)
}
}
useEffect(() => {
handleLoadMemberDivision()
}, [search]);
function onChoose(val: string, label: string, img?: string) {
if (selectMember.some((i: any) => i.idUser == val)) {
setSelectMember(selectMember.filter((i: any) => i.idUser != val))
} else {
setSelectMember([...selectMember, { idUser: val, name: label, img }])
}
}
async function handleAddMember() {
try {
dispatch(setMemberChoose(selectMember))
router.back()
} catch (error) {
console.error(error)
ToastAndroid.show('Gagal menambahkan anggota', ToastAndroid.SHORT)
}
}
return (
<SafeAreaView>
<Stack.Screen
options={{
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
headerTitle: 'Pilih Anggota',
headerTitleAlign: 'center',
headerRight: () => (
<ButtonSaveHeader
category="create"
disable={selectMember.length > 0 ? false : true}
onPress={() => {
handleAddMember()
}}
/>
)
}}
/>
<View style={[Styles.p15]}>
<InputSearch onChange={(val) => setSearch(val)} value={search} />
{
selectMember.length > 0
?
<View>
<ScrollView horizontal style={[Styles.mb10, Styles.pv10]}>
{
selectMember.map((item: any, index: any) => (
<ImageWithLabel
key={index}
label={item.name}
src={`https://wibu-storage.wibudev.com/api/files/${item.img}`}
onClick={() => onChoose(item.idUser, item.name, item.img)}
/>
))
}
</ScrollView>
</View>
:
<Text style={[Styles.textDefault, Styles.cGray, Styles.pv05, { textAlign: 'center' }]}>Tidak ada member yang dipilih</Text>
}
<ScrollView>
{
data.length > 0 ?
data.map((item: any, index: any) => {
return (
<Pressable
key={index}
style={[Styles.itemSelectModal]}
onPress={() => {
onChoose(item.idUser, item.name, item.img)
}}
>
<View style={[Styles.rowItemsCenter]}>
<ImageUser src={`https://wibu-storage.wibudev.com/api/files/${item.img}`} border />
<View style={[Styles.ml10]}>
<Text style={[Styles.textDefault]}>{item.name}</Text>
</View>
</View>
{
selectMember.some((i: any) => i.idUser == item.idUser) && <AntDesign name="check" size={20} />
}
</Pressable>
)
}
)
:
<Text style={[Styles.textDefault, { textAlign: 'center' }]}>Tidak ada data</Text>
}
</ScrollView>
</View>
</SafeAreaView>
)
}

View File

@@ -0,0 +1,155 @@
import ButtonBackHeader from "@/components/buttonBackHeader";
import ButtonSaveHeader from "@/components/buttonSaveHeader";
import { InputForm } from "@/components/inputForm";
import Styles from "@/constants/Styles";
import { setTaskCreate } from "@/lib/taskCreate";
import dayjs from "dayjs";
import { router, Stack } from "expo-router";
import { useEffect, useState } from "react";
import {
SafeAreaView,
ScrollView,
Text,
View
} from "react-native";
import DateTimePicker, {
DateType
} from "react-native-ui-datepicker";
import { useDispatch, useSelector } from "react-redux";
export default function CreateTaskAddTugas() {
const dispatch = useDispatch()
const [disable, setDisable] = useState(true);
const [range, setRange] = useState<{
startDate: DateType;
endDate: DateType;
}>({ startDate: undefined, endDate: undefined });
const [error, setError] = useState({
startDate: false,
endDate: false,
title: false,
})
const [title, setTitle] = useState('');
const taskCreate = useSelector((state: any) => state.taskCreate)
const from = range.startDate
? dayjs(range.startDate).format("DD-MM-YYYY")
: "";
const to = range.endDate ? dayjs(range.endDate).format("DD-MM-YYYY") : "";
function checkAll() {
if (from == "" || to == "" || title == "" || title == "null" || error.startDate || error.endDate || error.title) {
setDisable(true)
} else {
setDisable(false)
}
}
function onValidation(cat: string, val: string) {
if (cat == "title") {
setTitle(val)
if (val == "" || val == "null") {
setError(error => ({ ...error, title: true }))
} else {
setError(error => ({ ...error, title: false }))
}
}
}
useEffect(() => {
checkAll()
}, [from, to, title, error])
async function handleCreate() {
try {
dispatch(setTaskCreate([...taskCreate, {
title: title,
dateStart: from,
dateEnd: to,
dateStartFix: dayjs(range.startDate).format("YYYY-MM-DD"),
dateEndFix: dayjs(range.endDate).format("YYYY-MM-DD"),
}]))
router.back();
} catch (error) {
console.error(error);
}
}
return (
<SafeAreaView>
<Stack.Screen
options={{
headerLeft: () => (
<ButtonBackHeader
onPress={() => {
router.back();
}}
/>
),
headerTitle: "Tambah Tugas",
headerTitleAlign: "center",
headerRight: () => (
<ButtonSaveHeader
disable={disable}
category="create"
onPress={() => { handleCreate() }}
/>
),
}}
/>
<ScrollView>
<View style={[Styles.p15, Styles.mb100]}>
<View style={[Styles.wrapPaper, Styles.p10]}>
<DateTimePicker
mode="range"
startDate={range.startDate}
endDate={range.endDate}
onChange={(param) => setRange(param)}
styles={{
selected: Styles.selectedDate,
selected_label: Styles.cWhite,
range_fill: Styles.selectRangeDate,
}}
/>
</View>
<View style={[Styles.mv10]}>
<View style={[Styles.rowSpaceBetween]}>
<View style={[{ width: "48%" }]}>
<Text style={[Styles.mb05]}>
Tanggal Mulai <Text style={Styles.cError}>*</Text>
</Text>
<View style={[Styles.wrapPaper, Styles.p10]}>
<Text style={{ textAlign: "center" }}>{from}</Text>
</View>
</View>
<View style={[{ width: "48%" }]}>
<Text style={[Styles.mb05]}>
Tanggal Berakhir <Text style={Styles.cError}>*</Text>
</Text>
<View style={[Styles.wrapPaper, Styles.p10]}>
<Text style={{ textAlign: "center" }}>{to}</Text>
</View>
</View>
</View>
{
(error.endDate || error.startDate) && <Text style={[Styles.textInformation, Styles.cError, Styles.mt05]}>Tanggal tidak boleh kosong</Text>
}
</View>
<InputForm
label="Judul Tugas"
type="default"
placeholder="Judul Tugas"
required
bg="white"
value={title}
error={error.title}
errorText="Judul tidak boleh kosong"
onChange={(e) => {
onValidation("title", e)
}}
/>
</View>
</ScrollView>
</SafeAreaView>
);
}

View File

@@ -16,6 +16,7 @@ import {
import { router, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
import { Pressable, SafeAreaView, ScrollView, Text, View } from "react-native";
import { useSelector } from "react-redux";
type Props = {
id: string;
@@ -32,6 +33,7 @@ export default function ListTask() {
const { token, decryptToken } = useAuthSession();
const [data, setData] = useState<Props[]>([]);
const [search, setSearch] = useState("");
const update = useSelector((state: any) => state.taskUpdate)
async function handleLoad() {
try {
@@ -50,7 +52,7 @@ export default function ListTask() {
useEffect(() => {
handleLoad();
}, [status, search]);
}, [status, search, update.data]);
return (
<SafeAreaView>

View File

@@ -1,69 +1,165 @@
import Styles from "@/constants/Styles"
import { AntDesign, MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons"
import { apiDeleteTask, apiGetDivisionOneFeature } from "@/lib/api"
import { setUpdateTask } from "@/lib/taskUpdate"
import { useAuthSession } from "@/providers/AuthProvider"
import { AntDesign, Ionicons, MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons"
import { router } from "expo-router"
import { useState } from "react"
import { View } from "react-native"
import { useEffect, useState } from "react"
import { ToastAndroid, View } from "react-native"
import { useDispatch, useSelector } from "react-redux"
import AlertKonfirmasi from "../alertKonfirmasi"
import ButtonMenuHeader from "../buttonMenuHeader"
import DrawerBottom from "../drawerBottom"
import MenuItemRow from "../menuItemRow"
type Props = {
id: string | string[]
division: string
status: number | undefined
}
export default function HeaderRightTaskDetail({ id }: Props) {
export default function HeaderRightTaskDetail({ id, division, status }: 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)
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))
const response = await apiDeleteTask({ user: hasil }, String(id))
if (response.success) {
dispatch(setUpdateTask({ ...update, data: !update.data }))
ToastAndroid.show('Berhasil menghapus tugas', ToastAndroid.SHORT)
router.back()
} else {
ToastAndroid.show(response.message, ToastAndroid.SHORT)
}
} catch (error) {
console.error(error)
} finally {
setVisible(false)
}
}
return (
<>
<ButtonMenuHeader onPress={() => { setVisible(true) }} />
{
(entityUser.role == "user" || entityUser.role == "coadmin") && !isMemberDivision
? <></>
:
<ButtonMenuHeader onPress={() => { setVisible(true) }} />
}
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={setVisible} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<AntDesign name="pluscircle" color="black" size={25} />}
title="Tambah Tugas"
onPress={() => {
if (status == 3) return
setVisible(false)
router.push(`./${id}/add-task`)
}}
disabled={status == 3}
/>
<MenuItemRow
icon={<MaterialCommunityIcons name="file-plus" color="black" size={25} />}
title="Tambah File"
onPress={() => {
if (status == 3) return
setVisible(false)
router.push(`./${id}/add-file`)
}}
disabled={status == 3}
/>
{
( (entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision)
&&
<MenuItemRow
icon={<MaterialIcons name="groups" color="black" size={25} />}
title="Tambah Anggota"
onPress={() => {
if (status == 3) return
setVisible(false)
router.push(`./${id}/add-member`)
}}
disabled={status == 3}
/>
<MenuItemRow
icon={<MaterialIcons name="groups" color="black" size={25} />}
title="Tambah Anggota"
onPress={() => {
setVisible(false)
router.push(`./${id}/add-member`)
}}
/>
}
</View>
<View style={[Styles.rowItemsCenter, Styles.mt15]}>
<MenuItemRow
icon={<MaterialCommunityIcons name="pencil-outline" color="black" size={25} />}
title="Edit"
onPress={() => {
setVisible(false)
router.push(`./${id}/edit`)
}}
/>
<MenuItemRow
icon={<MaterialIcons name="close" color="black" size={25} />}
title="Batal"
onPress={() => {
setVisible(false)
router.push(`./${id}/cancel`)
}}
/>
</View>
{
( (entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision )
&&
<View style={[Styles.rowItemsCenter, Styles.mt15]}>
<MenuItemRow
icon={<MaterialCommunityIcons name="pencil-outline" color="black" size={25} />}
title="Edit"
onPress={() => {
if (status == 3) return
setVisible(false)
router.push(`./${id}/edit`)
}}
disabled={status == 3}
/>
{
status == 3
?
<MenuItemRow
icon={<Ionicons name="trash" color="black" size={25} />}
title="Hapus"
onPress={() => {
AlertKonfirmasi({
title: 'Konfirmasi',
desc: 'Apakah Anda yakin ingin menghapus tugas ini? Tugas yang dihapus tidak dapat dikembalikan',
onPress: () => { handleDelete() }
})
}}
/>
:
<MenuItemRow
icon={<MaterialIcons name="close" color="black" size={25} />}
title="Batal"
onPress={() => {
setVisible(false)
router.push(`./${id}/cancel`)
}}
/>
}
</View>
}
</DrawerBottom>
</>
)

View File

@@ -1,17 +1,47 @@
import Styles from "@/constants/Styles"
import { apiGetDivisionOneFeature } from "@/lib/api"
import { useAuthSession } from "@/providers/AuthProvider"
import { AntDesign } from "@expo/vector-icons"
import { useState } from "react"
import { router, useLocalSearchParams } from "expo-router"
import { useEffect, useState } from "react"
import { View } from "react-native"
import { useSelector } from "react-redux"
import ButtonMenuHeader from "../buttonMenuHeader"
import DrawerBottom from "../drawerBottom"
import MenuItemRow from "../menuItemRow"
import { router } from "expo-router"
export default function HeaderRightTaskList() {
const [isVisible, setVisible] = useState(false)
const [isAdminDivision, setIsAdminDivision] = useState(false);
const { token, decryptToken } = useAuthSession()
const { id } = useLocalSearchParams<{ id: string }>();
const entityUser = useSelector((state: any) => state.user);
async function handleCheckAdmin() {
try {
const hasil = await decryptToken(String(token?.current));
const response = await apiGetDivisionOneFeature({
id,
user: hasil,
cat: "check-admin",
});
setIsAdminDivision(response.data);
} catch (error) {
console.error(error);
}
}
useEffect(() => {
handleCheckAdmin()
}, [])
return (
<>
<ButtonMenuHeader onPress={() => { setVisible(true) }} />
{
(entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision
? <ButtonMenuHeader onPress={() => { setVisible(true) }} /> : <></>
}
<DrawerBottom animation="slide" isVisible={isVisible} setVisible={setVisible} title="Menu">
<View style={Styles.rowItemsCenter}>
<MenuItemRow

View File

@@ -549,4 +549,18 @@ export const apiCancelTask = async (data: { user: string, reason: string }, id:
export const apiAddMemberTask = async ({ data, id }: { data: { user: string, member: any[], idDivision: string }, id: string }) => {
const response = await api.post(`/mobile/task/${id}/member`, data)
return response.data;
};
export const apiCreateTask = async (data: FormData) => {
const response = await api.post(`/mobile/task`, data, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
return response.data;
};
export const apiDeleteTask = async (data: { user: string }, id: string) => {
const response = await api.delete(`/mobile/task/${id}/lainnya`, { data })
return response.data;
};