request leaves days

parent 165dde72
......@@ -3,11 +3,19 @@ import {Text} from 'react-native-paper';
import {fonts} from '../../assets/fonts/fonts';
import colors from '../../values/colors';
const FONT_FAMILY = fonts.beProLight;
const FONT_FAMILY_BASE = fonts.beProLight;
const AppText = ({variant, children, style, onPress, color, isSubText}) => {
const AppText = ({
variant,
children,
style,
onPress,
color,
isSubText,
isBold,
}) => {
const defaultStyle = {
fontFamily: FONT_FAMILY,
fontFamily: FONT_FAMILY_BASE,
fontSize: isSubText ? 12 : 14,
color: color ?? colors.textColor,
};
......
......@@ -16,14 +16,24 @@ const data = [
{label: 'Item 8', value: '8'},
];
const SelectDropdownComponent = ({selectData = [], value, setValue}) => {
const SelectDropdownComponent = ({
selectData = [],
value,
setValue,
width,
height,
}) => {
// const [value, setValue] = useState(null);
const [isFocus, setIsFocus] = useState(false);
return (
<View style={styles.container}>
<Dropdown
style={[styles.dropdown, isFocus && {borderColor: 'blue'}]}
style={[
styles.dropdown,
{width: width ?? 100, height: height ?? 40},
isFocus && {borderColor: 'blue'},
]}
itemTextStyle={{color: colors.textColor}}
placeholderStyle={styles.placeholderStyle}
selectedTextStyle={styles.selectedTextStyle}
......@@ -56,12 +66,9 @@ export default SelectDropdownComponent;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
},
dropdown: {
width: 100,
height: 40,
borderColor: 'gray',
borderWidth: 0.5,
borderRadius: 8,
......
......@@ -123,7 +123,7 @@ const stylesTextInput = StyleSheet.create({
marginTop: 5,
paddingHorizontal: 8,
paddingRight: 12,
borderBottomWidth: 0.2,
borderBottomWidth: 0.5,
},
icon: {
width: 20,
......
......@@ -9,4 +9,7 @@ export default {
axiosClient.get(
`myLeaveDayApprovalRequests?Filters=${filter}&Sorts=${sort}&Page=${page}&PageSize=${pageSize}`,
),
requestGetLeaveCategory: () => axiosClient.get('leaveCategories'),
requestGetDirectManagers: () => axiosClient.get('myDirectManagers'),
requestPostLeaveRequest: (payload) => axiosClient.post('leaveDays', payload),
};
......@@ -16,9 +16,17 @@ import {
getUserLeavesDay,
getApproveRequestLeavesDays,
getUserRestDay,
getLeaveCategory,
getDirectManagers,
handleSelectManagersLeaveRequest,
postLeaveRequest,
} from './onLeaveSlice';
import OnLeaveMainView from './template/OnLeaveMainView';
import onLeavePropsProvider from './onLeavePropsProvider';
import {launchImageLibrary} from 'react-native-image-picker';
import {ToastMessage} from '../../utils/MessageUtil';
import moment from 'moment';
import Utils from '../../utils';
const initPayloadApprove = {
type: 'Tất cả',
......@@ -35,12 +43,11 @@ const OnLeaveContainer = props => {
userRestDayList,
userInfo,
approveRequestLeavesDaysList,
leaveCategory,
directManagersList,
} = props;
const dispatch = useDispatch();
// const userLeaveDaysPending = useSelector(
// state => state.UserLeavesPending.userLeavesPending,
// );
const dispatch = useDispatch();
const [dataChart, setDataChart] = useState();
// get api with payload
......@@ -49,7 +56,6 @@ const OnLeaveContainer = props => {
const [payloadLeaves, setPayloadLeaves] = useState(initPayloadApprove);
const [leaveRequestList, setLeaveRequestList] = useState([]);
const [leaveApproveReqList, setLeaveApproveReqList] = useState([]);
const [showAlert, setShowAlert] = useState({
isError: false,
......@@ -69,6 +75,24 @@ const OnLeaveContainer = props => {
const [modalContent, setModalContent] = useState(null);
const [leavesDaysModal, setLeavesDaysModal] = useState(null);
const [openTimePicker, setOpenTimePicker] = useState({
startDate: false,
finishDate: false,
startTime: false,
finishTime: false,
});
const [timeRequestLeave, setTimeRequestLeave] = useState({
startDate: new Date(),
finishDate: new Date(),
startTime: new Date(),
finishTime: new Date(),
});
const [leaveRequestImage, setLeaveRequestImage] = useState([]);
const [leaveRequestTicket, setLeaveRequestTicket] = useState({
leaveCategory: '',
reason: '',
});
// open the modal
const onOpenDetailModal = detailItem => {
setModalContent(
......@@ -141,72 +165,6 @@ const OnLeaveContainer = props => {
isRefresh: false,
}));
};
const checkVisibleLoadMore = () => {
// console.log(
// leaveApproveReqList.length == totalArr.totalApproveReqLeaves,
// leaveApproveReqList.length,
// totalArr.totalApproveReqLeaves,
// );
if (
leaveApproveReqList.length > 0 &&
leaveApproveReqList.length == totalArr.totalApproveReqLeaves
) {
setDisableLoadMore(prev => ({
...prev,
approveReqBtn: true,
}));
} else if (
leaveApproveReqList.length > 0 &&
leaveApproveReqList.length < totalArr.totalApproveReqLeaves
) {
setDisableLoadMore(prev => ({
...prev,
approveReqBtn: false,
}));
} else if (
leaveRequestList.length > 0 &&
leaveRequestList.length == totalArr.totalLeaveList
) {
//.log('checkVisibleLoadMore');
setDisableLoadMore(prev => ({
...prev,
leaveBtn: true,
}));
} else if (
leaveRequestList.length > 0 &&
leaveRequestList.length < totalArr.totalLeaveList
) {
//.log('checkVisibleLoadMore');
setDisableLoadMore(prev => ({
...prev,
leaveBtn: false,
}));
}
};
const loadLeavesTicketsFromApi = async () => {
const response = await dispatch(
getUserLeavesDay({
filter: payloadLeaves.filter,
sort: payloadLeaves.sort,
page: payloadLeaves.page,
pageSize: payloadLeaves.pageSize,
}),
);
if (response.success) {
const {collection, total} = response.data;
if (!collection || collection.length === 0) {
return;
}
//console.log('loadLeavesTicketsFromApi', collection);
if (payloadLeaves.isRefresh) {
setTotalArr(prev => ({...prev, totalLeaveList: total}));
return;
}
setTotalArr(prev => ({...prev, totalLeaveList: total}));
}
};
// refresh onClick event
const onRefreshLeaveList = () => {
setPayloadLeaves({
......@@ -330,19 +288,109 @@ const OnLeaveContainer = props => {
const fetchLeavesRestDays = () => {
dispatch(getUserRestDay());
};
const fetchLeaveCategory = () => {
dispatch(getLeaveCategory());
};
const fetchDirectManagers = () => {
dispatch(getDirectManagers());
};
//============================== ADD NEW LEAVES =============================//
const openCreateNewLeaveDay = async () => {
const objectClone = JSON.parse(JSON.stringify(userDirectManagersList));
let obj = [];
objectClone.forEach(element => {
element.checked = false;
obj.push(element);
});
setUserManagerList(obj);
getRangeTimeLeave();
const openGallery = () => {
launchImageLibrary(
{
mediaType: 'photo',
includeBase64: true,
},
response => {
if (!response.didCancel) {
//console.log('AAA');
const {assets} = response;
setLeaveRequestImage(prev => [...prev, ...assets]);
//console.log(response.assets[0].uri)
}
},
);
};
const onDeleteLeaveRequestImage = index => {
const clone = [...leaveRequestImage];
clone.splice(index, 1);
setLeaveRequestImage([...clone]);
};
const onSubmitLeaveRequest = () => {
if (handleSubmitLeaveRequest()) {
const selectLeaveCategory = leaveCategory.filter(item =>
item.name === leaveRequestTicket.leaveCategory.length
? leaveRequestTicket.leaveCategory
: leaveCategory[0].name,
);
const approver = directManagersList.filter(item => item.isChecked);
const payload = {
start: timeRequestLeave.startDate,
finish: timeRequestLeave.finishDate,
leave_category_id:
selectLeaveCategory.length > 0 ? selectLeaveCategory[0].id : null,
approver_id: approver.length > 0 ? approver[0].id : null,
reason: leaveRequestTicket.reason,
};
dispatch(postLeaveRequest(payload)).then(response => {
const {success, message} = Utils.getValues(response, 'payload', false);
ToastMessage({
title: 'Hệ thống',
message: success ? 'Đã gửi yêu cầu nghỉ phép thành công' : message,
type: success ? 'success' : 'error',
});
onCloseModal();
});
}
};
const handleSubmitLeaveRequest = () => {
if (directManagersList?.length === 0) {
return false;
}
const isSelectedManager = directManagersList.filter(item => item.isChecked);
if (leaveRequestTicket.reason.length === 0) {
ToastMessage({
title: 'Hệ thống',
message: 'Vui lòng nhập lý do nghỉ',
type: 'error',
});
return false;
} else if (
moment(timeRequestLeave.startDate) > moment(timeRequestLeave.finishDate)
) {
ToastMessage({
title: 'Hệ thống',
message: 'Vui lòng chọn ngày bắt đầu nghỉ nhỏ hơn ngày kết thúc',
type: 'error',
timeVisible: 5000,
});
return false;
} else if (
moment(timeRequestLeave.startTime) > moment(timeRequestLeave.finishTime)
) {
ToastMessage({
title: 'Hệ thống',
message: 'Vui lòng chọn giờ bắt đầu nghỉ nhỏ hơn giờ kết thúc',
type: 'error',
timeVisible: 5000,
});
return false;
} else if (isSelectedManager.length === 0) {
ToastMessage({
title: 'Hệ thống',
message: 'Vui lòng chọn người duyệt!!!',
type: 'error',
timeVisible: 5000,
});
return false;
} else {
return true;
}
};
const onSelectManagerLeaveRequest = (index, value) => {
dispatch(handleSelectManagersLeaveRequest({index, value}));
};
// useEffect
useEffect(() => {
usersLeavesDayList && formatLeaveLstFromApi();
......@@ -350,6 +398,8 @@ const OnLeaveContainer = props => {
useEffect(() => {
fetchLeavesRestDays();
fetchLeaveCategory();
fetchDirectManagers();
}, []);
useEffect(() => {
......@@ -363,10 +413,6 @@ const OnLeaveContainer = props => {
payloadApproveRequestLeavesDays && fetchApproveRequestLeavesDays();
}, [payloadApproveRequestLeavesDays]);
useEffect(() => {
checkVisibleLoadMore();
}, [leaveRequestList, leaveApproveReqList, totalArr]);
useEffect(() => {
if (props?.route?.params) {
const {refId} = props?.route?.params;
......@@ -385,11 +431,22 @@ const OnLeaveContainer = props => {
totalArr,
isDisableLoadMore,
leaveRequestList,
leaveApproveReqList,
modalContent,
payloadApproveRequestLeavesDays,
approveRequestLeavesDaysList,
leavesDaysModal,
leaveCategory,
directManagersList,
openTimePicker,
timeRequestLeave,
leaveRequestImage,
leaveRequestTicket,
setLeaveRequestTicket,
openGallery,
onDeleteLeaveRequestImage,
setLeaveRequestImage,
setTimeRequestLeave,
setOpenTimePicker,
onLoadMoreLeavesApproveReqTicket,
onRefreshLeaveList,
onRefreshLeaveApproveReqList,
......@@ -403,6 +460,8 @@ const OnLeaveContainer = props => {
onCloseModal,
onChangeSelectFilter,
minutesToHours,
onSubmitLeaveRequest,
onSelectManagerLeaveRequest,
};
return <OnLeaveMainView {...onLeavePropsProvider(leaveProps)} />;
};
......
......@@ -11,6 +11,8 @@ export default function OnLeaveScreen() {
usersLeavesDayList = [],
userRestDayList = [],
approveRequestLeavesDaysList = [],
leaveCategory = [],
directManagersList = [],
} = onLeaveSelect;
const {userInfo} = authSelect;
const onLeaveScreenProps = {
......@@ -18,6 +20,8 @@ export default function OnLeaveScreen() {
usersLeavesDayList,
userRestDayList,
approveRequestLeavesDaysList,
leaveCategory,
directManagersList,
};
return <OnLeaveContainer {...onLeaveScreenProps} />;
}
......@@ -25,6 +25,19 @@ export default function onLeavePropsProvider(props) {
onChangeSelectFilter,
minutesToHours,
leavesDaysModal,
leaveCategory,
directManagersList,
openTimePicker,
setOpenTimePicker,
timeRequestLeave,
setTimeRequestLeave,
leaveRequestImage,
openGallery,
onDeleteLeaveRequestImage,
leaveRequestTicket,
setLeaveRequestTicket,
onSubmitLeaveRequest,
onSelectManagerLeaveRequest
} = props;
return {
leavesDaysModal,
......@@ -59,5 +72,22 @@ export default function onLeavePropsProvider(props) {
userInfo,
onOpenDetailModal,
},
leaveRequestModalProps: {
leaveCategory,
userInfo,
onCloseModal,
directManagersList,
openTimePicker,
setOpenTimePicker,
timeRequestLeave,
setTimeRequestLeave,
leaveRequestImage,
openGallery,
onDeleteLeaveRequestImage,
leaveRequestTicket,
setLeaveRequestTicket,
onSubmitLeaveRequest,
onSelectManagerLeaveRequest
},
};
}
......@@ -6,9 +6,7 @@ import onLeaveApi from '../../network/api/onLeaveApi';
import Utils from '../../utils';
const initialHome = {
quotationList: [],
news: [],
birthdayListInMonth: [],
directManagersList: [],
};
export const getUserLeavesDay = createAsyncThunk(
......@@ -50,11 +48,58 @@ export const getApproveRequestLeavesDays = createAsyncThunk(
});
},
);
export const getLeaveCategory = createAsyncThunk(
'onLeave/getLeaveCategory',
async (data, thunkAPI) => {
return serviceRequest({
dispatch: thunkAPI.dispatch,
serviceMethod: onLeaveApi.requestGetLeaveCategory,
payload: data,
options: {
skipLoader: false,
},
});
},
);
export const getDirectManagers = createAsyncThunk(
'onLeave/getDirectManagers',
async (data, thunkAPI) => {
return serviceRequest({
dispatch: thunkAPI.dispatch,
serviceMethod: onLeaveApi.requestGetDirectManagers,
payload: data,
options: {
skipLoader: false,
},
});
},
);
export const postLeaveRequest = createAsyncThunk(
'onLeave/postLeaveRequest',
async (data, thunkAPI) => {
return serviceRequest({
dispatch: thunkAPI.dispatch,
serviceMethod: onLeaveApi.requestPostLeaveRequest,
payload: data,
options: {
skipLoader: false,
},
});
},
);
const onLeaveSlice = createSlice({
name: 'onLeave',
initialState: initialHome,
reducers: {},
reducers: {
handleSelectManagersLeaveRequest: (state, payload) => {
const {index, value} = payload.payload;
let managers = JSON.parse(JSON.stringify(state.directManagersList));
if (managers.length > 0) {
managers[index].isChecked = value;
state.directManagersList = [...managers]
}
},
},
extraReducers: builder => {
builder.addCase(getUserLeavesDay.fulfilled, (state, action) => {
const {success} = Utils.getValues(action, 'payload', false);
......@@ -86,8 +131,28 @@ const onLeaveSlice = createSlice({
);
}
});
builder.addCase(getLeaveCategory.fulfilled, (state, action) => {
const {success} = Utils.getValues(action, 'payload', false);
if (success) {
state.leaveCategory = Utils.getValues(action, 'payload.data', []);
}
});
builder.addCase(getDirectManagers.fulfilled, (state, action) => {
const {success} = Utils.getValues(action, 'payload', false);
if (success) {
const managers = Utils.getValues(action, 'payload.data', []);
const addKeySelect = managers.map(item => {
return {
...item,
isChecked: false,
};
});
state.directManagersList = [...addKeySelect];
}
});
},
});
const {reducer} = onLeaveSlice;
const {reducer, actions} = onLeaveSlice;
export const {handleSelectManagersLeaveRequest} = actions;
export default reducer;
......@@ -402,5 +402,139 @@ const styles = StyleSheet.create({
alignItems: 'center',
},
});
export const leavesModalStyles = StyleSheet.create({
container: {
flex: 1,
},
whiteTxt: {
color: colors.white,
fontWeight: '500',
},
blueTxt: {
color: '#5d78ff',
fontWeight: '500',
},
modalView: {
backgroundColor: 'white',
borderRadius: 20,
paddingHorizontal: 10,
shadowColor: colors.black1,
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 4,
elevation: 5,
marginTop: 80,
height: windowHeight,
width: '100%',
},
button: {
borderRadius: 20,
padding: 10,
elevation: 2,
},
modalTitle: {
fontWeight: 'bold',
fontSize: 16,
},
rowView: {
flexDirection: 'row',
marginTop: 10,
justifyContent: 'space-between',
alignItems: 'center',
},
inputText: {
backgroundColor: colors.white,
width: 200,
},
addLeaveRequestImageBtn: {
borderColor: colors.primary_blue,
borderStyle: 'dotted',
borderWidth: 2,
justifyContent: 'center',
alignItems: 'center',
height: 50,
padding: 10,
width: 50,
},
btnSubmit: {
backgroundColor: '#5d78ff',
justifyContent: 'center',
alignItems: 'center',
height: 40,
borderRadius: 8,
width: 100,
},
btnCancel: {
backgroundColor: colors.white,
justifyContent: 'center',
alignItems: 'center',
height: 40,
borderRadius: 8,
width: 100,
},
ImgAvatar: {
width: 50,
height: 50,
borderRadius: 30,
},
imgUpload: {
resizeMode: 'contain',
height: 50,
width: 50,
marginRight: 10,
borderRadius: 5,
},
reason: {
width: windowWidth / 2 - 25,
textAlign: 'right',
},
checkbox: {
alignSelf: 'center',
height: 16,
width: 16,
marginRight: 4,
},
avatarApprove: {
width: 32,
height: 32,
borderRadius: 4,
},
takeTimeStyle: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-end',
borderBottomColor: '#444',
borderBottomWidth: 0.2,
height: 24,
},
btnClose: {
width: 20,
height: 20,
position: 'absolute',
top: -5,
right: 0,
zIndex: 10,
},
chooseTimeSection: {
alignItems: 'flex-end',
flexDirection: 'row',
justifyContent: 'space-between',
borderBottomWidth: 0.5,
height: 35,
width: 200,
borderColor: colors.grey444,
},
});
export default styles;
......@@ -156,6 +156,7 @@ const ApproveRequestLeavesDays = React.memo(
</View>
</View>
{approveRequestLeavesDaysList.length > 0 &&
userInfo &&
approveRequestLeavesDaysList[0].approver_id === userInfo.id &&
approveRequestLeavesDaysList.map((item, index) => (
<TouchableOpacity
......@@ -316,6 +317,7 @@ const OnLeaveMainView = ({
leaveRequestList,
onCloseModal,
leavesDaysModal,
leaveRequestModalProps,
}) => {
return (
<SafeAreaView>
......@@ -335,9 +337,7 @@ const OnLeaveMainView = ({
onOpenDetailModal={onOpenDetailModal}
/>
</ScrollView>
{leavesDaysModal && (
<RequestLeavesDays userInfo={userInfo} onClose={onCloseModal} />
)}
{leavesDaysModal && <RequestLeavesDays {...leaveRequestModalProps} />}
</SafeAreaView>
);
};
......
......@@ -23,6 +23,7 @@ const colors = {
greenE0: '#e0f7f0',
lightGray: '#E5E5E5',
grey: '#CACACA',
grey444: '#444',
royal_blue: '#057DCD',
grayC4: '#C4C4C4',
white: '#fff',
......
......@@ -268,6 +268,7 @@ export const IMAGES = {
IcMore,
IcOutlineSend,
IcAvatarDefault,
IcLeaveNoti,
};
export const BgIntroduce = {
BgStep1,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment