upd: task division
> > Deskripsi: > - list task divisi > - pencarian task divisi > - detail task divisi > - update status tugas task divisi > - detail tugas task divisi > - edit tugas task divisi > - hapus tugas task divisi > - hapus file task divisi > - hapus member > - tambah tugas task divisi > - check file task divisi > - tambah file task divisi > - edit task divisi > - cancel task divisi > - tambah member task divisi > > No Issues
This commit is contained in:
@@ -2,60 +2,184 @@ 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 MenuItemRow from "@/components/menuItemRow";
|
||||
import Styles from "@/constants/Styles";
|
||||
import { MaterialCommunityIcons } from "@expo/vector-icons";
|
||||
import { apiAddFileTask, apiCheckFileTask } from "@/lib/api";
|
||||
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, Text, ToastAndroid, View } from "react-native";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
ActivityIndicator,
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
Text,
|
||||
ToastAndroid,
|
||||
View,
|
||||
} from "react-native";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
export default function TaskDivisionAddFile() {
|
||||
const { id, detail } = useLocalSearchParams()
|
||||
const { id, detail } = useLocalSearchParams<{ id: string; detail: string }>();
|
||||
const [fileForm, setFileForm] = useState<any[]>([]);
|
||||
const [listFile, setListFile] = useState<any[]>([]);
|
||||
const [indexDelFile, setIndexDelFile] = useState<number>(0);
|
||||
const [isModal, setModal] = useState(false);
|
||||
const { token, decryptToken } = useAuthSession();
|
||||
const [loadingCheck, setLoadingCheck] = useState(false);
|
||||
const dispatch = useDispatch();
|
||||
const update = useSelector((state: any) => state.taskUpdate);
|
||||
|
||||
const pickDocumentAsync = async () => {
|
||||
let result = await DocumentPicker.getDocumentAsync({
|
||||
type: ["*/*"],
|
||||
multiple: false,
|
||||
});
|
||||
if (!result.canceled) {
|
||||
if (result.assets?.[0].uri) {
|
||||
const check = await handleCheckFile(result.assets?.[0]);
|
||||
if (check) {
|
||||
setFileForm([...fileForm, result.assets?.[0]]);
|
||||
setListFile([...listFile, result.assets?.[0].name]);
|
||||
} else {
|
||||
ToastAndroid.show("File sudah ada", ToastAndroid.SHORT);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function deleteFile(index: number) {
|
||||
setListFile([...listFile.filter((val, i) => i !== index)]);
|
||||
setFileForm([...fileForm.filter((val, i) => i !== index)]);
|
||||
setModal(false);
|
||||
}
|
||||
|
||||
async function handleCheckFile(val: any) {
|
||||
try {
|
||||
setLoadingCheck(true);
|
||||
const hasil = await decryptToken(String(token?.current));
|
||||
const fd = new FormData();
|
||||
|
||||
fd.append("file", {
|
||||
uri: val.uri,
|
||||
type: "application/octet-stream",
|
||||
name: val.name,
|
||||
} as any);
|
||||
|
||||
fd.append(
|
||||
"data",
|
||||
JSON.stringify({
|
||||
user: hasil,
|
||||
})
|
||||
);
|
||||
|
||||
const response = await apiCheckFileTask({ data: fd, id: detail });
|
||||
return response.success;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return false;
|
||||
} finally {
|
||||
setLoadingCheck(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleAddFile() {
|
||||
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,
|
||||
})
|
||||
);
|
||||
|
||||
const response = await apiAddFileTask({ data: fd, id: detail });
|
||||
if (response.success) {
|
||||
ToastAndroid.show("Berhasil menambahkan file", ToastAndroid.SHORT);
|
||||
dispatch(setUpdateTask({ ...update, file: !update.file }));
|
||||
router.back();
|
||||
} else {
|
||||
ToastAndroid.show(response.message, ToastAndroid.SHORT);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
ToastAndroid.show("Terjadi kesalahan", ToastAndroid.SHORT);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Tambah File',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <ButtonSaveHeader category="create" onPress={() => {
|
||||
ToastAndroid.show('Berhasil menambah data', ToastAndroid.SHORT)
|
||||
router.push('./')
|
||||
}} />
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
headerTitle: "Tambah File",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
category="create"
|
||||
disable={fileForm.length == 0 ? true : false}
|
||||
onPress={() => { handleAddFile() }}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<ScrollView>
|
||||
<View style={[Styles.p15, Styles.mb100]}>
|
||||
<ButtonSelect value="Upload File" />
|
||||
<ButtonSelect value="Upload File" onPress={pickDocumentAsync} />
|
||||
{
|
||||
listFile.length > 0 && (
|
||||
<View style={[Styles.mb15]}>
|
||||
<Text style={[Styles.textDefaultSemiBold, Styles.mv05]}>File</Text>
|
||||
<View style={[Styles.wrapPaper]}>
|
||||
{
|
||||
listFile.map((item, index) => (
|
||||
<BorderBottomItem
|
||||
key={index}
|
||||
borderType="all"
|
||||
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
|
||||
title="image_pertama.jpg"
|
||||
title={item}
|
||||
titleWeight="normal"
|
||||
onPress={() => { setIndexDelFile(index); setModal(true) }}
|
||||
/>
|
||||
<BorderBottomItem
|
||||
borderType="all"
|
||||
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
|
||||
title="file_kedua.pdf"
|
||||
titleWeight="normal"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
{/* <ButtonForm
|
||||
text="SIMPAN"
|
||||
onPress={() => {
|
||||
AlertKonfirmasi({
|
||||
title: 'Konfirmasi',
|
||||
desc: 'Apakah anda yakin ingin menambahkan data?',
|
||||
onPress: () => {
|
||||
ToastAndroid.show('Berhasil menambahkan data', ToastAndroid.SHORT)
|
||||
router.push('./')
|
||||
))
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
{
|
||||
loadingCheck && <ActivityIndicator size="small" />
|
||||
}
|
||||
})
|
||||
}} /> */}
|
||||
</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>
|
||||
</SafeAreaView>
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
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 { apiAddMemberTask, apiGetDivisionMember, apiGetTaskOne } from "@/lib/api";
|
||||
import { setUpdateTask } from "@/lib/taskUpdate";
|
||||
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 AddMemberTask() {
|
||||
const dispatch = useDispatch()
|
||||
const update = useSelector((state: any) => state.projectUpdate)
|
||||
const { token, decryptToken } = useAuthSession()
|
||||
const { id, detail } = useLocalSearchParams<{ id: string, detail: string }>()
|
||||
const [dataOld, setDataOld] = useState<Props[]>([])
|
||||
const [data, setData] = useState<Props[]>([])
|
||||
const [selectMember, setSelectMember] = useState<any[]>([])
|
||||
const [search, setSearch] = useState('')
|
||||
|
||||
async function handleLoadOldMember() {
|
||||
try {
|
||||
const hasil = await decryptToken(String(token?.current));
|
||||
const response = await apiGetTaskOne({
|
||||
user: hasil,
|
||||
id: detail,
|
||||
cat: 'member',
|
||||
});
|
||||
setDataOld(response.data)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function handleLoadMemberDivision() {
|
||||
const hasil = await decryptToken(String(token?.current))
|
||||
const responMemberDivision = await apiGetDivisionMember({ id: id, user: hasil, search: search })
|
||||
setData(responMemberDivision.data)
|
||||
}
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
handleLoadOldMember()
|
||||
}, []);
|
||||
|
||||
|
||||
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 {
|
||||
const hasil = await decryptToken(String(token?.current))
|
||||
const response = await apiAddMemberTask({ id: detail, data: { user: hasil, member: selectMember, idDivision: id } })
|
||||
if (response.success) {
|
||||
ToastAndroid.show('Berhasil menambahkan anggota', ToastAndroid.SHORT)
|
||||
dispatch(setUpdateTask({ ...update, member: !update.member }))
|
||||
router.back()
|
||||
} else {
|
||||
ToastAndroid.show(response.message, ToastAndroid.SHORT)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
ToastAndroid.show('Gagal menambahkan anggota', ToastAndroid.SHORT)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Tambah Anggota Kegiatan',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
category="update"
|
||||
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) => {
|
||||
const found = dataOld.some((i: any) => i.idUser == item.idUser)
|
||||
return (
|
||||
<Pressable
|
||||
key={index}
|
||||
style={[Styles.itemSelectModal]}
|
||||
onPress={() => {
|
||||
!found && 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>
|
||||
{
|
||||
found && <Text style={[Styles.textInformation, Styles.cGray]}>sudah menjadi anggota</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>
|
||||
)
|
||||
}
|
||||
@@ -2,34 +2,123 @@ import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import Styles from "@/constants/Styles";
|
||||
import { apiCreateTaskTugas } from "@/lib/api";
|
||||
import { setUpdateTask } from "@/lib/taskUpdate";
|
||||
import { useAuthSession } from "@/providers/AuthProvider";
|
||||
import dayjs from "dayjs";
|
||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import { SafeAreaView, ScrollView, Text, ToastAndroid, View } from "react-native";
|
||||
import DateTimePicker, { DateType, getDefaultStyles } from "react-native-ui-datepicker";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
Text,
|
||||
ToastAndroid,
|
||||
View,
|
||||
} from "react-native";
|
||||
import DateTimePicker, { DateType } from "react-native-ui-datepicker";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
export default function TaskDivisionAddTask() {
|
||||
const { id, detail } = useLocalSearchParams()
|
||||
const [range, setRange] = useState<{ startDate: DateType; endDate: DateType; }>({ startDate: undefined, endDate: undefined });
|
||||
const defaultStyles = getDefaultStyles()
|
||||
const { token, decryptToken } = useAuthSession();
|
||||
const dispatch = useDispatch();
|
||||
const update = useSelector((state: any) => state.taskUpdate);
|
||||
const { id, detail } = useLocalSearchParams<{ id: string; detail: string }>();
|
||||
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 from = range.startDate
|
||||
? dayjs(range.startDate).format('MMM DD, YYYY')
|
||||
: '';
|
||||
const to = range.endDate ? dayjs(range.endDate).format('MMM DD, YYYY') : '';
|
||||
? 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 {
|
||||
const hasil = await decryptToken(String(token?.current));
|
||||
const response = await apiCreateTaskTugas({
|
||||
data: {
|
||||
title,
|
||||
dateStart: dayjs(range.startDate).format("YYYY-MM-DD"),
|
||||
dateEnd: dayjs(range.endDate).format("YYYY-MM-DD"),
|
||||
user: hasil,
|
||||
idDivision: id,
|
||||
},
|
||||
id: detail,
|
||||
});
|
||||
if (response.success) {
|
||||
dispatch(setUpdateTask({ ...update, task: !update.task, progress: !update.progress }));
|
||||
ToastAndroid.show("Berhasil menambah data", ToastAndroid.SHORT);
|
||||
router.back();
|
||||
} else {
|
||||
ToastAndroid.show(response.message, ToastAndroid.SHORT);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
ToastAndroid.show("Gagal menambah data", ToastAndroid.SHORT);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Tambah Tugas',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <ButtonSaveHeader category="create" onPress={() => {
|
||||
ToastAndroid.show('Berhasil menambah data', ToastAndroid.SHORT)
|
||||
router.push('./')
|
||||
}} />
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
headerTitle: "Tambah Tugas",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
category="create"
|
||||
disable={disable}
|
||||
onPress={() => {
|
||||
handleCreate();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<ScrollView>
|
||||
@@ -40,43 +129,51 @@ export default function TaskDivisionAddTask() {
|
||||
startDate={range.startDate}
|
||||
endDate={range.endDate}
|
||||
onChange={(param) => setRange(param)}
|
||||
// styles={defaultStyles}
|
||||
styles={{
|
||||
selected: Styles.selectedDate,
|
||||
selected_label:Styles.cWhite,
|
||||
selected_label: Styles.cWhite,
|
||||
range_fill: Styles.selectRangeDate,
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<View style={[Styles.rowSpaceBetween, Styles.mv10]}>
|
||||
<View style={[{ width: '48%' }]}>
|
||||
<Text style={[Styles.mb05]}>Tanggal Mulai <Text style={Styles.cError}>*</Text></Text>
|
||||
<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>
|
||||
<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={[{ 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>
|
||||
<Text style={{ textAlign: "center" }}>{to}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<InputForm label="Judul Tugas" type="default" placeholder="Judul Tugas" required bg="white" />
|
||||
{/* <ButtonForm
|
||||
text="SIMPAN"
|
||||
onPress={() => {
|
||||
AlertKonfirmasi({
|
||||
title: 'Konfirmasi',
|
||||
desc: 'Apakah anda yakin ingin menambahkan data?',
|
||||
onPress: () => {
|
||||
ToastAndroid.show('Berhasil menambahkan data', ToastAndroid.SHORT)
|
||||
router.push('./')
|
||||
{
|
||||
(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>
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,42 +1,106 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader"
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader"
|
||||
import { InputForm } from "@/components/inputForm"
|
||||
import Styles from "@/constants/Styles"
|
||||
import { router, Stack, useLocalSearchParams } from "expo-router"
|
||||
import { SafeAreaView, ScrollView, ToastAndroid, View } from "react-native"
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import Styles from "@/constants/Styles";
|
||||
import { apiCancelTask } from "@/lib/api";
|
||||
import { setUpdateTask } from "@/lib/taskUpdate";
|
||||
import { useAuthSession } from "@/providers/AuthProvider";
|
||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { SafeAreaView, ScrollView, ToastAndroid, View } from "react-native";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
export default function TaskDivisionCancel() {
|
||||
const { id, detail } = useLocalSearchParams()
|
||||
const { id, detail } = useLocalSearchParams<{ id: string; detail: string }>();
|
||||
const { token, decryptToken } = useAuthSession();
|
||||
const dispatch = useDispatch();
|
||||
const update = useSelector((state: any) => state.projectUpdate);
|
||||
const [reason, setReason] = useState("");
|
||||
const [error, setError] = useState(false);
|
||||
const [disable, setDisable] = useState(false);
|
||||
|
||||
function onValidation(val: string) {
|
||||
setReason(val);
|
||||
if (val == "" || val == "null") {
|
||||
setError(true);
|
||||
} else {
|
||||
setError(false);
|
||||
}
|
||||
}
|
||||
|
||||
function checkAll() {
|
||||
if (reason == "" || reason == "null" || error) {
|
||||
setDisable(true);
|
||||
} else {
|
||||
setDisable(false);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
checkAll();
|
||||
}, [reason, error]);
|
||||
|
||||
async function handleCancel() {
|
||||
try {
|
||||
const hasil = await decryptToken(String(token?.current));
|
||||
const response = await apiCancelTask(
|
||||
{
|
||||
reason: reason,
|
||||
user: hasil,
|
||||
},
|
||||
detail
|
||||
);
|
||||
if (response.success) {
|
||||
dispatch(setUpdateTask({ ...update, data: !update.data }));
|
||||
ToastAndroid.show("Berhasil membatalkan kegiatan", ToastAndroid.SHORT);
|
||||
router.back();
|
||||
} else {
|
||||
ToastAndroid.show(response.message, ToastAndroid.SHORT);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
ToastAndroid.show("Gagal membatalkan kegiatan", ToastAndroid.SHORT);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Pembatalan Tugas',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <ButtonSaveHeader category="cancel" onPress={() => {
|
||||
ToastAndroid.show('Berhasil mengubah data', ToastAndroid.SHORT)
|
||||
router.push('./')
|
||||
}} />
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
headerTitle: "Pembatalan Tugas",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={disable}
|
||||
category="cancel"
|
||||
onPress={() => {
|
||||
handleCancel();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<ScrollView>
|
||||
<View style={[Styles.p15, Styles.mb100]}>
|
||||
<InputForm label="Alasan Pembatalan" type="default" placeholder="Alasan Pembatalan" required bg="white" />
|
||||
{/* <ButtonForm
|
||||
text="SIMPAN"
|
||||
onPress={() => {
|
||||
AlertKonfirmasi({
|
||||
title: 'Konfirmasi',
|
||||
desc: 'Apakah anda yakin ingin membatalkan tugas? Pembatalan bersifat permanen',
|
||||
onPress: () => {
|
||||
ToastAndroid.show('Berhasil mengubah data', ToastAndroid.SHORT)
|
||||
router.push('./')
|
||||
}
|
||||
})
|
||||
}} /> */}
|
||||
<InputForm
|
||||
label="Alasan Pembatalan"
|
||||
type="default"
|
||||
placeholder="Alasan Pembatalan"
|
||||
required
|
||||
bg="white"
|
||||
error={error}
|
||||
errorText="Alasan pembatalan harus diisi"
|
||||
onChange={(val) => onValidation(val)}
|
||||
/>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -2,41 +2,122 @@ import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import Styles from "@/constants/Styles";
|
||||
import { apiEditTask, apiGetTaskOne } from "@/lib/api";
|
||||
import { setUpdateTask } from "@/lib/taskUpdate";
|
||||
import { useAuthSession } from "@/providers/AuthProvider";
|
||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { SafeAreaView, ScrollView, ToastAndroid, View } from "react-native";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
export default function TaskDivisionEdit() {
|
||||
const { id, detail } = useLocalSearchParams()
|
||||
const { id, detail } = useLocalSearchParams<{ id: string; detail: string }>();
|
||||
const { token, decryptToken } = useAuthSession();
|
||||
const [judul, setJudul] = useState("");
|
||||
const [error, setError] = useState(false);
|
||||
const [disable, setDisable] = useState(false);
|
||||
const dispatch = useDispatch();
|
||||
const update = useSelector((state: any) => state.taskUpdate);
|
||||
|
||||
async function handleLoad() {
|
||||
try {
|
||||
const hasil = await decryptToken(String(token?.current));
|
||||
const response = await apiGetTaskOne({
|
||||
user: hasil,
|
||||
cat: "data",
|
||||
id: detail,
|
||||
});
|
||||
setJudul(response.data.title);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
handleLoad();
|
||||
}, []);
|
||||
|
||||
function onValidation(val: string) {
|
||||
setJudul(val);
|
||||
if (val == "" || val == "null") {
|
||||
setError(true);
|
||||
}else{
|
||||
setError(false);
|
||||
}
|
||||
}
|
||||
|
||||
function checkAll() {
|
||||
if (judul == "" || judul == "null" || error) {
|
||||
setDisable(true);
|
||||
} else {
|
||||
setDisable(false);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
checkAll();
|
||||
}, [judul, error]);
|
||||
|
||||
async function handleUpdate() {
|
||||
try {
|
||||
const hasil = await decryptToken(String(token?.current));
|
||||
const response = await apiEditTask(
|
||||
{
|
||||
title: judul,
|
||||
user: hasil,
|
||||
},
|
||||
detail
|
||||
);
|
||||
if (response.success) {
|
||||
dispatch(setUpdateTask({ ...update, data: !update.data }));
|
||||
ToastAndroid.show("Berhasil mengubah data", ToastAndroid.SHORT);
|
||||
router.back();
|
||||
} else {
|
||||
ToastAndroid.show(response.message, ToastAndroid.SHORT);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
ToastAndroid.show("Terjadi kesalahan", ToastAndroid.SHORT);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Edit Judul Tugas',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <ButtonSaveHeader category="update" onPress={() => {
|
||||
ToastAndroid.show('Berhasil mengubah data', ToastAndroid.SHORT)
|
||||
router.push('./')
|
||||
}} />
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
headerTitle: "Edit Judul",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
category="update"
|
||||
disable={disable}
|
||||
onPress={() => { handleUpdate() }}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<ScrollView>
|
||||
<View style={[Styles.p15, Styles.mb100]}>
|
||||
<InputForm label="Judul Kegiatan" type="default" placeholder="Judul Kegiatan" required bg="white" />
|
||||
{/* <ButtonForm
|
||||
text="SIMPAN"
|
||||
onPress={() => {
|
||||
AlertKonfirmasi({
|
||||
title: 'Konfirmasi',
|
||||
desc: 'Apakah anda yakin ingin mengubah data?',
|
||||
onPress: () => {
|
||||
ToastAndroid.show('Berhasil mengubah data', ToastAndroid.SHORT)
|
||||
router.push('./')
|
||||
}
|
||||
})
|
||||
}} /> */}
|
||||
<InputForm
|
||||
label="Judul Kegiatan"
|
||||
type="default"
|
||||
placeholder="Judul Kegiatan"
|
||||
required
|
||||
bg="white"
|
||||
value={judul}
|
||||
onChange={(val) => { onValidation(val) }}
|
||||
error={error}
|
||||
errorText="Judul Kegiatan harus diisi"
|
||||
/>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,15 +1,54 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import SectionCancel from "@/components/sectionCancel";
|
||||
import SectionProgress from "@/components/sectionProgress";
|
||||
import HeaderRightTaskDetail from "@/components/task/headerTaskDetail";
|
||||
import SectionFileTask from "@/components/task/sectionFileTask";
|
||||
import SectionMemberTask from "@/components/task/sectionMemberTask";
|
||||
import SectionTanggalTugasTask from "@/components/task/sectionTanggalTugasTask";
|
||||
import Styles from "@/constants/Styles";
|
||||
import { apiGetTaskOne } from "@/lib/api";
|
||||
import { useAuthSession } from "@/providers/AuthProvider";
|
||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { SafeAreaView, ScrollView, View } from "react-native";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
type Props = {
|
||||
id: string
|
||||
title: string
|
||||
desc: string
|
||||
reason: string
|
||||
status: number
|
||||
isActive: boolean
|
||||
}
|
||||
|
||||
export default function DetailTaskDivision() {
|
||||
const { id, detail } = useLocalSearchParams()
|
||||
const { id, detail } = useLocalSearchParams<{ id: string, detail: string }>();
|
||||
const { token, decryptToken } = useAuthSession()
|
||||
const [data, setData] = useState<Props>()
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [progress, setProgress] = useState(0)
|
||||
const update = useSelector((state: any) => state.taskUpdate)
|
||||
|
||||
|
||||
async function handleLoad() {
|
||||
try {
|
||||
setLoading(true)
|
||||
const hasil = await decryptToken(String(token?.current))
|
||||
const response = await apiGetTaskOne({ id: detail, user: hasil, cat: 'data' })
|
||||
setData(response.data)
|
||||
const responseProgress = await apiGetTaskOne({ id: detail, user: hasil, cat: 'progress' })
|
||||
setProgress(responseProgress.data.progress)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
handleLoad()
|
||||
}, [update.progress, update.data])
|
||||
|
||||
|
||||
return (
|
||||
@@ -17,14 +56,17 @@ export default function DetailTaskDivision() {
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Judul Tugas Divisi',
|
||||
headerTitle: loading ? 'Loading...' : data?.title,
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <HeaderRightTaskDetail id={detail} />,
|
||||
}}
|
||||
/>
|
||||
<ScrollView>
|
||||
<View style={[Styles.p15, Styles.mb100]}>
|
||||
<SectionProgress text="Kemajuan Kegiatan 50%" progress={50} />
|
||||
{
|
||||
data?.reason != null && data?.reason != "" && <SectionCancel text={data?.reason} />
|
||||
}
|
||||
<SectionProgress text={`Kemajuan Kegiatan ${progress}%`} progress={progress} />
|
||||
<SectionTanggalTugasTask />
|
||||
<SectionFileTask />
|
||||
<SectionMemberTask />
|
||||
|
||||
@@ -6,14 +6,51 @@ import PaperGridContent from "@/components/paperGridContent";
|
||||
import ProgressBar from "@/components/progressBar";
|
||||
import { ColorsStatus } from "@/constants/ColorsStatus";
|
||||
import Styles from "@/constants/Styles";
|
||||
import { AntDesign, Ionicons, MaterialCommunityIcons } from "@expo/vector-icons";
|
||||
import { apiGetTask } from "@/lib/api";
|
||||
import { useAuthSession } from "@/providers/AuthProvider";
|
||||
import {
|
||||
AntDesign,
|
||||
Ionicons,
|
||||
MaterialCommunityIcons,
|
||||
} from "@expo/vector-icons";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Pressable, SafeAreaView, ScrollView, Text, View } from "react-native";
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
title: string;
|
||||
desc: string;
|
||||
status: number;
|
||||
progress: number;
|
||||
member: number;
|
||||
};
|
||||
|
||||
export default function ListTask() {
|
||||
const { status } = useLocalSearchParams<{ status: string }>()
|
||||
const [isList, setList] = useState(false)
|
||||
const { id, status } = useLocalSearchParams<{ id: string; status: string }>();
|
||||
const [isList, setList] = useState(false);
|
||||
const { token, decryptToken } = useAuthSession();
|
||||
const [data, setData] = useState<Props[]>([]);
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
async function handleLoad() {
|
||||
try {
|
||||
const hasil = await decryptToken(String(token?.current));
|
||||
const response = await apiGetTask({
|
||||
user: hasil,
|
||||
division: id,
|
||||
status,
|
||||
search,
|
||||
});
|
||||
setData(response.data);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
handleLoad();
|
||||
}, [status, search]);
|
||||
|
||||
return (
|
||||
<SafeAreaView>
|
||||
@@ -23,112 +60,152 @@ export default function ListTask() {
|
||||
<ButtonTab
|
||||
active={status}
|
||||
value="0"
|
||||
onPress={() => { router.push('./task?status=0') }}
|
||||
onPress={() => {
|
||||
router.replace("./task?status=0");
|
||||
}}
|
||||
label="Segera"
|
||||
icon={<MaterialCommunityIcons name="clock-alert-outline" color={status == "0" ? 'white' : 'black'} size={20} />}
|
||||
n={4} />
|
||||
icon={
|
||||
<MaterialCommunityIcons
|
||||
name="clock-alert-outline"
|
||||
color={status == "0" ? "white" : "black"}
|
||||
size={20}
|
||||
/>
|
||||
}
|
||||
n={4}
|
||||
/>
|
||||
<ButtonTab
|
||||
active={status}
|
||||
value="1"
|
||||
onPress={() => { router.push('./task?status=1') }}
|
||||
onPress={() => {
|
||||
router.replace("./task?status=1");
|
||||
}}
|
||||
label="Dikerjakan"
|
||||
icon={<MaterialCommunityIcons name="progress-check" color={status == "1" ? 'white' : 'black'} size={20} />}
|
||||
n={4} />
|
||||
icon={
|
||||
<MaterialCommunityIcons
|
||||
name="progress-check"
|
||||
color={status == "1" ? "white" : "black"}
|
||||
size={20}
|
||||
/>
|
||||
}
|
||||
n={4}
|
||||
/>
|
||||
<ButtonTab
|
||||
active={status}
|
||||
value="2"
|
||||
onPress={() => { router.push('./task?status=2') }}
|
||||
onPress={() => {
|
||||
router.replace("./task?status=2");
|
||||
}}
|
||||
label="Selesai"
|
||||
icon={<Ionicons name="checkmark-done-circle-outline" color={status == "2" ? 'white' : 'black'} size={20} />}
|
||||
n={4} />
|
||||
icon={
|
||||
<Ionicons
|
||||
name="checkmark-done-circle-outline"
|
||||
color={status == "2" ? "white" : "black"}
|
||||
size={20}
|
||||
/>
|
||||
}
|
||||
n={4}
|
||||
/>
|
||||
<ButtonTab
|
||||
active={status}
|
||||
value="3"
|
||||
onPress={() => { router.push('./task?status=3') }}
|
||||
onPress={() => {
|
||||
router.replace("./task?status=3");
|
||||
}}
|
||||
label="Batal"
|
||||
icon={<AntDesign name="closecircleo" color={status == "3" ? 'white' : 'black'} size={20} />}
|
||||
n={4} />
|
||||
icon={
|
||||
<AntDesign
|
||||
name="closecircleo"
|
||||
color={status == "3" ? "white" : "black"}
|
||||
size={20}
|
||||
/>
|
||||
}
|
||||
n={4}
|
||||
/>
|
||||
</ScrollView>
|
||||
<View style={[Styles.rowSpaceBetween]}>
|
||||
<InputSearch width={68} />
|
||||
<Pressable onPress={() => { setList(!isList) }}>
|
||||
<MaterialCommunityIcons name={isList ? 'format-list-bulleted' : 'view-grid'} color={"black"} size={30} />
|
||||
<InputSearch width={68} onChange={setSearch} />
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
setList(!isList);
|
||||
}}
|
||||
>
|
||||
<MaterialCommunityIcons
|
||||
name={isList ? "format-list-bulleted" : "view-grid"}
|
||||
color={"black"}
|
||||
size={30}
|
||||
/>
|
||||
</Pressable>
|
||||
</View>
|
||||
{
|
||||
isList
|
||||
?
|
||||
{data.length > 0 ? (
|
||||
<></>
|
||||
) : (
|
||||
<Text
|
||||
style={[
|
||||
Styles.textDefault,
|
||||
Styles.cGray,
|
||||
{ textAlign: "center" },
|
||||
]}
|
||||
>
|
||||
Tidak ada data
|
||||
</Text>
|
||||
)}
|
||||
{isList ? (
|
||||
<View>
|
||||
{data.map((item, index) => (
|
||||
<BorderBottomItem
|
||||
onPress={() => { }}
|
||||
key={index}
|
||||
onPress={() => {
|
||||
router.push(`./task/${item.id}`);
|
||||
}}
|
||||
borderType="bottom"
|
||||
icon={
|
||||
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
|
||||
<AntDesign name="areachart" size={25} color={'#384288'} />
|
||||
<AntDesign name="areachart" size={25} color={"#384288"} />
|
||||
</View>
|
||||
}
|
||||
title="Pembangunan Jembatan"
|
||||
title={item.title}
|
||||
/>
|
||||
<BorderBottomItem
|
||||
onPress={() => { }}
|
||||
borderType="bottom"
|
||||
icon={
|
||||
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
|
||||
<AntDesign name="areachart" size={25} color={'#384288'} />
|
||||
))}
|
||||
</View>
|
||||
}
|
||||
title="Pembangunan Jembatan"
|
||||
/>
|
||||
<BorderBottomItem
|
||||
onPress={() => { }}
|
||||
borderType="bottom"
|
||||
icon={
|
||||
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
|
||||
<AntDesign name="areachart" size={25} color={'#384288'} />
|
||||
</View>
|
||||
}
|
||||
title="Pembangunan Jembatan"
|
||||
/>
|
||||
<BorderBottomItem
|
||||
onPress={() => { }}
|
||||
borderType="bottom"
|
||||
icon={
|
||||
<View style={[Styles.iconContent, ColorsStatus.lightGreen]}>
|
||||
<AntDesign name="areachart" size={25} color={'#384288'} />
|
||||
</View>
|
||||
}
|
||||
title="Pembangunan Jembatan"
|
||||
/>
|
||||
</View>
|
||||
:
|
||||
|
||||
) : (
|
||||
<View>
|
||||
<PaperGridContent onPress={() => { router.push('./task/321') }} content="page" title="Pembangunan Jembatan" headerColor="primary">
|
||||
<ProgressBar category="page" value={0}/>
|
||||
{data.map((item, index) => (
|
||||
<PaperGridContent
|
||||
key={index}
|
||||
onPress={() => {
|
||||
router.push(`./task/${item.id}`);
|
||||
}}
|
||||
content="page"
|
||||
title={item.title}
|
||||
headerColor="primary"
|
||||
>
|
||||
<ProgressBar category="page" value={item.progress} />
|
||||
<View style={[Styles.rowSpaceBetween]}>
|
||||
<Text style={[Styles.textDefault, Styles.cGray]}>13 Februari 2025</Text>
|
||||
<LabelStatus size="default" category="primary" text="SEGERA" />
|
||||
</View>
|
||||
</PaperGridContent>
|
||||
<PaperGridContent content="page" title="Pembangunan Jembatan" headerColor="primary">
|
||||
<ProgressBar category="page" value={0}/>
|
||||
<View style={[Styles.rowSpaceBetween]}>
|
||||
<Text style={[Styles.textDefault, Styles.cGray]}>13 Februari 2025</Text>
|
||||
<LabelStatus size="default" category="primary" text="SEGERA" />
|
||||
</View>
|
||||
</PaperGridContent>
|
||||
<PaperGridContent content="page" title="Pembangunan Jembatan" headerColor="primary">
|
||||
<ProgressBar category="page" value={0}/>
|
||||
<View style={[Styles.rowSpaceBetween]}>
|
||||
<Text style={[Styles.textDefault, Styles.cGray]}>13 Februari 2025</Text>
|
||||
<LabelStatus size="default" category="primary" text="SEGERA" />
|
||||
</View>
|
||||
</PaperGridContent>
|
||||
</View>
|
||||
|
||||
<Text></Text>
|
||||
<LabelStatus
|
||||
size="default"
|
||||
category={
|
||||
item.status === 0 ? 'primary' :
|
||||
item.status === 1 ? 'warning' :
|
||||
item.status === 2 ? 'success' :
|
||||
item.status === 3 ? 'error' :
|
||||
'primary'
|
||||
}
|
||||
text={
|
||||
item.status === 0 ? 'SEGERA' :
|
||||
item.status === 1 ? 'DIKERJAKAN' :
|
||||
item.status === 2 ? 'SELESAI' :
|
||||
item.status === 3 ? 'DIBATALKAN' :
|
||||
'SEGERA'
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
</PaperGridContent>
|
||||
))}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import Styles from "@/constants/Styles";
|
||||
import { apiEditTaskTugas, apiGetTaskTugas } from "@/lib/api";
|
||||
import { setUpdateTask } from "@/lib/taskUpdate";
|
||||
import { useAuthSession } from "@/providers/AuthProvider";
|
||||
import dayjs from "dayjs";
|
||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
Text,
|
||||
ToastAndroid,
|
||||
View,
|
||||
} from "react-native";
|
||||
import DateTimePicker, { DateType } from "react-native-ui-datepicker";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
export default function UpdateProjectTaskDivision() {
|
||||
const { detail } = useLocalSearchParams<{ detail: string }>();
|
||||
const dispatch = useDispatch();
|
||||
const update = useSelector((state: any) => state.taskUpdate);
|
||||
const { token, decryptToken } = useAuthSession();
|
||||
const [range, setRange] = useState<{
|
||||
startDate: DateType;
|
||||
endDate: DateType;
|
||||
}>({ startDate: undefined, endDate: undefined });
|
||||
const [month, setMonth] = useState<any>();
|
||||
const [year, setYear] = useState<any>();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [disableBtn, setDisableBtn] = useState(false);
|
||||
const [title, setTitle] = useState("");
|
||||
const [error, setError] = useState({
|
||||
startDate: false,
|
||||
endDate: false,
|
||||
title: false,
|
||||
});
|
||||
|
||||
const from = range.startDate
|
||||
? dayjs(range.startDate).format("MMM DD, YYYY")
|
||||
: "";
|
||||
const to = range.endDate ? dayjs(range.endDate).format("MMM DD, YYYY") : "";
|
||||
|
||||
async function handleLoad() {
|
||||
try {
|
||||
setLoading(true);
|
||||
const hasil = await decryptToken(String(token?.current));
|
||||
const response = await apiGetTaskTugas({
|
||||
user: hasil,
|
||||
id: detail,
|
||||
});
|
||||
setTitle(response.data.title);
|
||||
setRange({
|
||||
startDate: new Date(response.data.dateStart),
|
||||
endDate: new Date(response.data.dateEnd),
|
||||
});
|
||||
setMonth(new Date(response.data.dateStart).getMonth());
|
||||
setYear(new Date(response.data.dateStart).getFullYear());
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
handleLoad();
|
||||
}, []);
|
||||
|
||||
async function handleEdit() {
|
||||
try {
|
||||
const hasil = await decryptToken(String(token?.current));
|
||||
const response = await apiEditTaskTugas({ data: { title, dateStart: dayjs(range.startDate).format("YYYY-MM-DD"), dateEnd: dayjs(range.endDate).format("YYYY-MM-DD"), user: hasil }, id: detail });
|
||||
if (response.success) {
|
||||
dispatch(setUpdateTask({ ...update, task: !update.task }))
|
||||
ToastAndroid.show("Berhasil mengubah data", ToastAndroid.SHORT);
|
||||
router.back();
|
||||
} else {
|
||||
ToastAndroid.show(response.message, ToastAndroid.SHORT);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
ToastAndroid.show("Gagal mengubah data", ToastAndroid.SHORT);
|
||||
}
|
||||
}
|
||||
|
||||
function checkAll() {
|
||||
if (
|
||||
from == "" ||
|
||||
to == "" ||
|
||||
title == "" ||
|
||||
title == "null" ||
|
||||
error.startDate ||
|
||||
error.endDate ||
|
||||
error.title
|
||||
) {
|
||||
setDisableBtn(true);
|
||||
} else {
|
||||
setDisableBtn(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]);
|
||||
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<ButtonBackHeader
|
||||
onPress={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
),
|
||||
headerTitle: "Edit Tanggal dan Tugas",
|
||||
headerTitleAlign: "center",
|
||||
headerRight: () => (
|
||||
<ButtonSaveHeader
|
||||
disable={disableBtn}
|
||||
category="update"
|
||||
onPress={() => {
|
||||
handleEdit()
|
||||
}}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<ScrollView>
|
||||
<View style={[Styles.p15, Styles.mb100]}>
|
||||
<View style={[Styles.wrapPaper, Styles.p10]}>
|
||||
{!loading && (
|
||||
<DateTimePicker
|
||||
mode="range"
|
||||
startDate={range.startDate}
|
||||
endDate={range.endDate}
|
||||
onChange={(param) => setRange(param)}
|
||||
month={month}
|
||||
year={year}
|
||||
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>
|
||||
);
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
import ButtonBackHeader from "@/components/buttonBackHeader";
|
||||
import ButtonSaveHeader from "@/components/buttonSaveHeader";
|
||||
import { InputForm } from "@/components/inputForm";
|
||||
import Styles from "@/constants/Styles";
|
||||
import dayjs from "dayjs";
|
||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import { SafeAreaView, ScrollView, Text, ToastAndroid, View } from "react-native";
|
||||
import DateTimePicker, { DateType, getDefaultStyles } from "react-native-ui-datepicker";
|
||||
|
||||
export default function UpdateProjectTaskDivision() {
|
||||
const { id } = useLocalSearchParams()
|
||||
const [range, setRange] = useState<{ startDate: DateType; endDate: DateType; }>({ startDate: undefined, endDate: undefined });
|
||||
const defaultStyles = getDefaultStyles()
|
||||
|
||||
const from = range.startDate
|
||||
? dayjs(range.startDate).format('MMM DD, YYYY')
|
||||
: '';
|
||||
const to = range.endDate ? dayjs(range.endDate).format('MMM DD, YYYY') : '';
|
||||
|
||||
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerLeft: () => <ButtonBackHeader onPress={() => { router.back() }} />,
|
||||
headerTitle: 'Edit Tanggal dan Tugas Divisi',
|
||||
headerTitleAlign: 'center',
|
||||
headerRight: () => <ButtonSaveHeader category="update" onPress={() => {
|
||||
ToastAndroid.show('Berhasil mengubah data', ToastAndroid.SHORT)
|
||||
router.push('../4324')
|
||||
}} />
|
||||
}}
|
||||
/>
|
||||
<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={defaultStyles}
|
||||
styles={{
|
||||
selected: Styles.selectedDate,
|
||||
selected_label: Styles.cWhite,
|
||||
range_fill: Styles.selectRangeDate,
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<View style={[Styles.rowSpaceBetween, Styles.mv10]}>
|
||||
<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>
|
||||
<InputForm label="Judul Tugas" type="default" placeholder="Judul Tugas" required bg="white" />
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
)
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import Styles from "@/constants/Styles"
|
||||
import { AntDesign, MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons"
|
||||
import { router } from "expo-router"
|
||||
import { useState } from "react"
|
||||
import { View } from "react-native"
|
||||
import ButtonMenuHeader from "../buttonMenuHeader"
|
||||
import DrawerBottom from "../drawerBottom"
|
||||
import MenuItemRow from "../menuItemRow"
|
||||
import { router } from "expo-router"
|
||||
|
||||
type Props = {
|
||||
id: string | string[]
|
||||
@@ -40,8 +40,8 @@ export default function HeaderRightTaskDetail({ id }: Props) {
|
||||
icon={<MaterialIcons name="groups" color="black" size={25} />}
|
||||
title="Tambah Anggota"
|
||||
onPress={() => {
|
||||
// setVisible(false)
|
||||
|
||||
setVisible(false)
|
||||
router.push(`./${id}/add-member`)
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
@@ -1,34 +1,87 @@
|
||||
import Styles from "@/constants/Styles";
|
||||
import { apiDeleteFileTask, apiGetTaskOne } from "@/lib/api";
|
||||
import { setUpdateTask } from "@/lib/taskUpdate";
|
||||
import { useAuthSession } from "@/providers/AuthProvider";
|
||||
import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons";
|
||||
import { useState } from "react";
|
||||
import { useLocalSearchParams } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Text, ToastAndroid, View } from "react-native";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import AlertKonfirmasi from "../alertKonfirmasi";
|
||||
import BorderBottomItem from "../borderBottomItem";
|
||||
import DrawerBottom from "../drawerBottom";
|
||||
import MenuItemRow from "../menuItemRow";
|
||||
|
||||
type Props = {
|
||||
id: string
|
||||
name: string
|
||||
extension: string
|
||||
idStorage: string
|
||||
}
|
||||
|
||||
export default function SectionFileTask() {
|
||||
const [isModal, setModal] = useState(false)
|
||||
const { token, decryptToken } = useAuthSession()
|
||||
const { detail } = useLocalSearchParams<{ detail: string }>();
|
||||
const [data, setData] = useState<Props[]>([])
|
||||
const [idSelect, setIdSelect] = useState('')
|
||||
const update = useSelector((state: any) => state.taskUpdate)
|
||||
const dispatch = useDispatch()
|
||||
|
||||
async function handleLoad() {
|
||||
try {
|
||||
const hasil = await decryptToken(String(token?.current))
|
||||
const response = await apiGetTaskOne({ id: detail, user: hasil, cat: 'file' })
|
||||
setData(response.data)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
handleLoad()
|
||||
}, [update.file])
|
||||
|
||||
async function handleDelete() {
|
||||
try {
|
||||
const hasil = await decryptToken(String(token?.current));
|
||||
const response = await apiDeleteFileTask({ user: hasil }, idSelect);
|
||||
if (response.success) {
|
||||
ToastAndroid.show('Berhasil menghapus file', ToastAndroid.SHORT)
|
||||
dispatch(setUpdateTask({ ...update, file: !update.file }))
|
||||
} else {
|
||||
ToastAndroid.show(response.message, ToastAndroid.SHORT)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
ToastAndroid.show('Terjadi kesalahan', ToastAndroid.SHORT)
|
||||
} finally {
|
||||
setModal(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<View style={[Styles.mb15]}>
|
||||
<Text style={[Styles.textDefaultSemiBold, Styles.mv05]}>File</Text>
|
||||
<View style={[Styles.wrapPaper]}>
|
||||
{
|
||||
data.length > 0 ?
|
||||
data.map((item, index) => {
|
||||
return (
|
||||
<BorderBottomItem
|
||||
key={index}
|
||||
borderType="all"
|
||||
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
|
||||
title="image_pertama.jpg"
|
||||
title={item.name + '.' + item.extension}
|
||||
titleWeight="normal"
|
||||
onPress={() => { setModal(true) }}
|
||||
/>
|
||||
<BorderBottomItem
|
||||
borderType="all"
|
||||
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
|
||||
title="file_kedua.pdf"
|
||||
titleWeight="normal"
|
||||
onPress={() => { setModal(true) }}
|
||||
onPress={() => { setIdSelect(item.id); setModal(true) }}
|
||||
/>
|
||||
)
|
||||
})
|
||||
:
|
||||
<Text style={[Styles.textDefault, Styles.cGray, { textAlign: 'center' }]}>Tidak ada file</Text>
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -57,8 +110,7 @@ export default function SectionFileTask() {
|
||||
title: 'Konfirmasi',
|
||||
desc: 'Apakah Anda yakin ingin menghapus file ini? File yang dihapus tidak dapat dikembalikan',
|
||||
onPress: () => {
|
||||
setModal(false)
|
||||
ToastAndroid.show('Berhasil menghapus data', ToastAndroid.SHORT)
|
||||
handleDelete()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -1,67 +1,165 @@
|
||||
import Styles from "@/constants/Styles"
|
||||
import { MaterialCommunityIcons } from "@expo/vector-icons"
|
||||
import { router } from "expo-router"
|
||||
import { useState } from "react"
|
||||
import { Image, Text, ToastAndroid, View } from "react-native"
|
||||
import AlertKonfirmasi from "../alertKonfirmasi"
|
||||
import BorderBottomItem from "../borderBottomItem"
|
||||
import DrawerBottom from "../drawerBottom"
|
||||
import MenuItemRow from "../menuItemRow"
|
||||
import Styles from "@/constants/Styles";
|
||||
import { apiDeleteTaskMember, apiGetTaskOne } from "@/lib/api";
|
||||
import { setUpdateTask } from "@/lib/taskUpdate";
|
||||
import { useAuthSession } from "@/providers/AuthProvider";
|
||||
import { MaterialCommunityIcons } from "@expo/vector-icons";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Text, ToastAndroid, View } from "react-native";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import AlertKonfirmasi from "../alertKonfirmasi";
|
||||
import BorderBottomItem from "../borderBottomItem";
|
||||
import DrawerBottom from "../drawerBottom";
|
||||
import ImageUser from "../imageNew";
|
||||
import MenuItemRow from "../menuItemRow";
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
idUser: string;
|
||||
name: string;
|
||||
email: string;
|
||||
img: string;
|
||||
position: string;
|
||||
};
|
||||
|
||||
export default function SectionMemberTask() {
|
||||
const [isModal, setModal] = useState(false)
|
||||
const [isModal, setModal] = useState(false);
|
||||
const { token, decryptToken } = useAuthSession();
|
||||
const { id, detail } = useLocalSearchParams<{ id: string; detail: string }>();
|
||||
const [data, setData] = useState<Props[]>([]);
|
||||
const dispatch = useDispatch();
|
||||
const update = useSelector((state: any) => state.taskUpdate);
|
||||
const [memberChoose, setMemberChoose] = useState({
|
||||
id: "",
|
||||
name: "",
|
||||
});
|
||||
|
||||
async function handleLoad() {
|
||||
try {
|
||||
const hasil = await decryptToken(String(token?.current));
|
||||
const response = await apiGetTaskOne({
|
||||
id: detail,
|
||||
user: hasil,
|
||||
cat: "member",
|
||||
});
|
||||
setData(response.data);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
handleLoad();
|
||||
}, [update.member]);
|
||||
|
||||
|
||||
async function handleDeleteMember() {
|
||||
try {
|
||||
const hasil = await decryptToken(String(token?.current));
|
||||
const response = await apiDeleteTaskMember({
|
||||
user: hasil,
|
||||
idUser: memberChoose.id,
|
||||
}, detail)
|
||||
if (response.success) {
|
||||
ToastAndroid.show("Berhasil menghapus anggota", ToastAndroid.SHORT);
|
||||
dispatch(setUpdateTask({ ...update, member: !update.progress }))
|
||||
} else {
|
||||
ToastAndroid.show(response.message, ToastAndroid.SHORT);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
ToastAndroid.show("Gagal menghapus anggota", ToastAndroid.SHORT);
|
||||
} finally {
|
||||
setModal(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<View style={[Styles.mb15]}>
|
||||
<View style={[Styles.rowSpaceBetween, Styles.mv05]}>
|
||||
<Text style={[Styles.textDefaultSemiBold]}>Anggota</Text>
|
||||
<Text style={[Styles.textDefault]}>Total 5 Anggota</Text>
|
||||
<Text style={[Styles.textDefault]}>Total {data.length} Anggota</Text>
|
||||
</View>
|
||||
|
||||
<View style={[Styles.wrapPaper]}>
|
||||
{data.length > 0 ? (
|
||||
data.map((item, index) => {
|
||||
return (
|
||||
<BorderBottomItem
|
||||
key={index}
|
||||
borderType="bottom"
|
||||
icon={
|
||||
<></>
|
||||
}
|
||||
title="Amalia Dwi"
|
||||
subtitle="Dinas - Bendahara"
|
||||
rightTopInfo="Anggota"
|
||||
onPress={() => { setModal(true) }}
|
||||
<ImageUser
|
||||
src={`https://wibu-storage.wibudev.com/api/files/${item.img}`}
|
||||
/>
|
||||
}
|
||||
title={item.name}
|
||||
onPress={() => {
|
||||
setMemberChoose({
|
||||
id: item.idUser,
|
||||
name: item.name,
|
||||
});
|
||||
setModal(true);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<Text
|
||||
style={[
|
||||
Styles.textDefault,
|
||||
Styles.cGray,
|
||||
{ textAlign: "center" },
|
||||
]}
|
||||
>
|
||||
Tidak ada anggota
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<DrawerBottom animation="slide" isVisible={isModal} setVisible={setModal} title="Menu">
|
||||
<DrawerBottom
|
||||
animation="slide"
|
||||
isVisible={isModal}
|
||||
setVisible={setModal}
|
||||
title={memberChoose.name}
|
||||
>
|
||||
<View style={Styles.rowItemsCenter}>
|
||||
<MenuItemRow
|
||||
icon={<MaterialCommunityIcons name="account-eye" color="black" size={25} />}
|
||||
icon={
|
||||
<MaterialCommunityIcons
|
||||
name="account-eye"
|
||||
color="black"
|
||||
size={25}
|
||||
/>
|
||||
}
|
||||
title="Lihat Profil"
|
||||
onPress={() => {
|
||||
setModal(false)
|
||||
router.push('/member/123')
|
||||
setModal(false);
|
||||
router.push(`/member/${memberChoose.id}`);
|
||||
}}
|
||||
/>
|
||||
|
||||
<MenuItemRow
|
||||
icon={<MaterialCommunityIcons name="account-remove" color="black" size={25} />}
|
||||
icon={
|
||||
<MaterialCommunityIcons
|
||||
name="account-remove"
|
||||
color="black"
|
||||
size={25}
|
||||
/>
|
||||
}
|
||||
title="Keluarkan"
|
||||
onPress={() => {
|
||||
AlertKonfirmasi({
|
||||
title: 'Konfirmasi',
|
||||
desc: 'Apakah Anda yakin ingin mengeluarkan anggota?',
|
||||
onPress: () => {
|
||||
setModal(false)
|
||||
ToastAndroid.show('Berhasil mengeluarkan anggota', ToastAndroid.SHORT)
|
||||
}
|
||||
})
|
||||
|
||||
title: "Konfirmasi",
|
||||
desc: "Apakah Anda yakin ingin mengeluarkan anggota?",
|
||||
onPress: () => { handleDeleteMember() },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</DrawerBottom>
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,27 +1,128 @@
|
||||
import Styles from "@/constants/Styles";
|
||||
import { apiDeleteTaskTugas, apiGetTaskOne, apiUpdateStatusTaskDivision } from "@/lib/api";
|
||||
import { setUpdateTask } from "@/lib/taskUpdate";
|
||||
import { useAuthSession } from "@/providers/AuthProvider";
|
||||
import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons";
|
||||
import { router } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Text, ToastAndroid, View } from "react-native";
|
||||
import ItemSectionTanggalTugas from "../itemSectionTanggalTugas";
|
||||
import DrawerBottom from "../drawerBottom";
|
||||
import MenuItemRow from "../menuItemRow";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import AlertKonfirmasi from "../alertKonfirmasi";
|
||||
import DrawerBottom from "../drawerBottom";
|
||||
import ItemSectionTanggalTugas from "../itemSectionTanggalTugas";
|
||||
import MenuItemRow from "../menuItemRow";
|
||||
import ModalSelect from "../modalSelect";
|
||||
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
title: string;
|
||||
status: number;
|
||||
dateStart: string;
|
||||
dateEnd: string;
|
||||
}
|
||||
|
||||
export default function SectionTanggalTugasTask() {
|
||||
const dispatch = useDispatch()
|
||||
const update = useSelector((state: any) => state.taskUpdate)
|
||||
const [isModal, setModal] = useState(false)
|
||||
const [isSelect, setSelect] = useState(false)
|
||||
const [choose, setChoose] = useState({ val: '', label: '' })
|
||||
const { token, decryptToken } = useAuthSession()
|
||||
const { id, detail } = useLocalSearchParams<{ id: string, detail: string }>();
|
||||
const [data, setData] = useState<Props[]>([])
|
||||
const [tugas, setTugas] = useState({
|
||||
id: '',
|
||||
status: 0,
|
||||
})
|
||||
|
||||
async function handleLoad() {
|
||||
try {
|
||||
const hasil = await decryptToken(String(token?.current))
|
||||
const response = await apiGetTaskOne({ id: detail, user: hasil, cat: 'task' })
|
||||
setData(response.data)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
async function handleUpdate(status: number) {
|
||||
try {
|
||||
const hasil = await decryptToken(String(token?.current));
|
||||
const response = await apiUpdateStatusTaskDivision({
|
||||
user: hasil,
|
||||
idProject: detail,
|
||||
status: status,
|
||||
}, tugas.id);
|
||||
if (response.success) {
|
||||
dispatch(setUpdateTask({ ...update, progress: !update.progress, task: !update.task }))
|
||||
ToastAndroid.show("Berhasil mengubah data", ToastAndroid.SHORT);
|
||||
} else {
|
||||
ToastAndroid.show(response.message, ToastAndroid.SHORT);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
ToastAndroid.show("Gagal mengubah data", ToastAndroid.SHORT);
|
||||
} finally {
|
||||
setSelect(false)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
handleLoad()
|
||||
}, [update.task])
|
||||
|
||||
|
||||
async function handleDelete() {
|
||||
try {
|
||||
const hasil = await decryptToken(String(token?.current));
|
||||
const response = await apiDeleteTaskTugas({
|
||||
user: hasil,
|
||||
idProject: detail,
|
||||
}, tugas.id);
|
||||
if (response.success) {
|
||||
dispatch(setUpdateTask({ ...update, progress: !update.progress, task: !update.task }))
|
||||
ToastAndroid.show("Berhasil menghapus data", ToastAndroid.SHORT);
|
||||
} else {
|
||||
ToastAndroid.show(response.message, ToastAndroid.SHORT);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
ToastAndroid.show("Gagal menghapus data", ToastAndroid.SHORT);
|
||||
} finally {
|
||||
setModal(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<View style={[Styles.mb15, Styles.mt10]}>
|
||||
<Text style={[Styles.textDefaultSemiBold, Styles.mv05]}>Tanggal & Tugas</Text>
|
||||
<View style={[Styles.wrapPaper]}>
|
||||
<ItemSectionTanggalTugas done={false} title="Pertama" dateStart="12-03-2023" dateEnd="15-03-2023" onPress={() => { setModal(true) }} />
|
||||
<ItemSectionTanggalTugas done={true} title="Kedua" dateStart="15-03-2023" dateEnd="20-03-2023" onPress={() => { setModal(true) }} />
|
||||
{
|
||||
data.length > 0
|
||||
?
|
||||
data.map((item, index) => {
|
||||
return (
|
||||
<ItemSectionTanggalTugas
|
||||
key={index}
|
||||
done={item.status === 1}
|
||||
title={item.title}
|
||||
dateStart={item.dateStart}
|
||||
dateEnd={item.dateEnd}
|
||||
onPress={() => {
|
||||
setTugas({
|
||||
id: item.id,
|
||||
status: item.status
|
||||
})
|
||||
setModal(true)
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})
|
||||
:
|
||||
<Text style={[Styles.textDefault, Styles.cGray, { textAlign: 'center' }]}>Tidak ada tugas</Text>
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -40,7 +141,7 @@ export default function SectionTanggalTugasTask() {
|
||||
title="Edit Tugas"
|
||||
onPress={() => {
|
||||
setModal(false)
|
||||
router.push(`./update/124`)
|
||||
router.push(`./update/${tugas.id}`)
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -52,8 +153,7 @@ export default function SectionTanggalTugasTask() {
|
||||
title: 'Konfirmasi',
|
||||
desc: 'Apakah anda yakin ingin menghapus data ini?',
|
||||
onPress: () => {
|
||||
setModal(false)
|
||||
ToastAndroid.show('Berhasil menghapus data', ToastAndroid.SHORT)
|
||||
handleDelete()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -66,12 +166,11 @@ export default function SectionTanggalTugasTask() {
|
||||
category="status-task"
|
||||
close={setSelect}
|
||||
onSelect={(value) => {
|
||||
setChoose(value)
|
||||
setSelect(false)
|
||||
ToastAndroid.show('Berhasil mengubah data', ToastAndroid.SHORT)
|
||||
handleUpdate(Number(value.val))
|
||||
}}
|
||||
title="Status"
|
||||
open={isSelect}
|
||||
valChoose={String(tugas.status)}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
||||
82
lib/api.ts
82
lib/api.ts
@@ -468,3 +468,85 @@ export const apiGetCalendarHistory = async ({ user, search, division }: { user:
|
||||
const response = await api.get(`mobile/calendar/history?user=${user}&search=${search}&division=${division}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const apiGetTask = async ({ user, status, search, division }: { user: string, status: string, search: string, division: string }) => {
|
||||
const response = await api.get(`mobile/task?user=${user}&status=${status}&division=${division}&search=${search}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const apiGetTaskOne = async ({ user, cat, id }: { user: string, cat: 'data' | 'progress' | 'task' | 'file' | 'member', id: string }) => {
|
||||
const response = await api.get(`mobile/task/${id}?user=${user}&cat=${cat}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const apiUpdateStatusTaskDivision = async (data: { user: string, status: number, idProject: string }, id: string) => {
|
||||
const response = await api.put(`mobile/task/detail/${id}`, data)
|
||||
return response.data
|
||||
};
|
||||
|
||||
export const apiGetTaskTugas = async ({ user, id }: { user: string, id: string }) => {
|
||||
const response = await api.get(`mobile/task/detail/${id}?user=${user}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const apiEditTaskTugas = async ({ data, id }: { data: { title: string, dateStart: string, user: string, dateEnd: string }, id: string }) => {
|
||||
const response = await api.post(`/mobile/task/detail/${id}`, data)
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const apiDeleteTaskTugas = async (data: { user: string, idProject: string }, id: string) => {
|
||||
const response = await api.delete(`mobile/task/detail/${id}`, { data })
|
||||
return response.data
|
||||
};
|
||||
|
||||
export const apiDeleteFileTask = async (data: { user: string }, id: string) => {
|
||||
const response = await api.delete(`/mobile/task/file/${id}`, { data })
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const apiDeleteTaskMember = async (data: { user: string, idUser: string }, id: string) => {
|
||||
const response = await api.delete(`mobile/task/${id}/member`, { data })
|
||||
return response.data
|
||||
};
|
||||
|
||||
export const apiCreateTaskTugas = async ({ data, id }: { data: { title: string, dateStart: string, user: string, dateEnd: string, idDivision: string }, id: string }) => {
|
||||
const response = await api.post(`/mobile/task/${id}`, data)
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const apiCheckFileTask = async ({ data, id }: { data: FormData, id: string }) => {
|
||||
const response = await api.put(`/mobile/task/file/${id}`, data,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
}
|
||||
)
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const apiAddFileTask = async ({ data, id }: { data: FormData, id: string }) => {
|
||||
const response = await api.post(`/mobile/task/file/${id}`, data,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
}
|
||||
)
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const apiEditTask = async (data: { title: string, user: string }, id: string) => {
|
||||
const response = await api.put(`/mobile/task/${id}`, data)
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const apiCancelTask = async (data: { user: string, reason: string }, id: string) => {
|
||||
const response = await api.delete(`mobile/task/${id}`, { data })
|
||||
return response.data
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
@@ -13,6 +13,7 @@ import memberUpdate from './memberSlice';
|
||||
import positionUpdate from './positionSlice';
|
||||
import projectUpdate from './projectUpdate';
|
||||
import taskCreate from './taskCreate';
|
||||
import taskUpdate from './taskUpdate';
|
||||
import userReducer from './userSlice';
|
||||
|
||||
const store = configureStore({
|
||||
@@ -32,6 +33,7 @@ const store = configureStore({
|
||||
divisionUpdate: divisionUpdate,
|
||||
discussionUpdate: discussionUpdate,
|
||||
calendarUpdate: calendarUpdate,
|
||||
taskUpdate: taskUpdate,
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
20
lib/taskUpdate.ts
Normal file
20
lib/taskUpdate.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
const taskUpdate = createSlice({
|
||||
name: 'taskUpdate',
|
||||
initialState: {
|
||||
data: false,
|
||||
progress: false,
|
||||
task: false,
|
||||
file: false,
|
||||
member: false
|
||||
},
|
||||
reducers: {
|
||||
setUpdateTask: (state, action) => {
|
||||
return action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { setUpdateTask } = taskUpdate.actions;
|
||||
export default taskUpdate.reducer;
|
||||
Reference in New Issue
Block a user