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" />
|
||||
<View style={[Styles.mb15]}>
|
||||
<Text style={[Styles.textDefaultSemiBold, Styles.mv05]}>File</Text>
|
||||
<View style={[Styles.wrapPaper]}>
|
||||
<BorderBottomItem
|
||||
borderType="all"
|
||||
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
|
||||
title="image_pertama.jpg"
|
||||
titleWeight="normal"
|
||||
/>
|
||||
<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('./')
|
||||
}
|
||||
})
|
||||
}} /> */}
|
||||
<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={item}
|
||||
titleWeight="normal"
|
||||
onPress={() => { setIndexDelFile(index); setModal(true) }}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</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.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 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" />
|
||||
{/* <ButtonForm
|
||||
text="SIMPAN"
|
||||
onPress={() => {
|
||||
AlertKonfirmasi({
|
||||
title: 'Konfirmasi',
|
||||
desc: 'Apakah anda yakin ingin menambahkan data?',
|
||||
onPress: () => {
|
||||
ToastAndroid.show('Berhasil menambahkan data', ToastAndroid.SHORT)
|
||||
router.push('./')
|
||||
}
|
||||
})
|
||||
}} /> */}
|
||||
<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
|
||||
?
|
||||
<View>
|
||||
{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}/>
|
||||
))}
|
||||
</View>
|
||||
) : (
|
||||
<View>
|
||||
{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" />
|
||||
<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>
|
||||
<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>
|
||||
|
||||
}
|
||||
))}
|
||||
</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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user