Commit 7e09ce25 by tungnq

TODO: Đã hoàn thiện giao diện danh sách công việc

parent 3804c1b7
import React, { useState } from 'react'; import React, {useState} from 'react';
import {Text, View, StyleSheet} from 'react-native'; import {useNavigation} from '@react-navigation/native';
import ListWorkView from './view'; import ListWorkView from './view';
import * as ScreenName from '../../routers/ScreenNames';
/**
* Container component quản lý logic nghiệp vụ cho màn hình danh sách công việc
* Chứa tất cả state và business logic, truyền xuống view component thông qua props
*/
const ListWork = props => { const ListWork = props => {
const {searchQuery, setSearchQuery} = props; const {searchQuery, setSearchQuery} = props;
const navigation = useNavigation();
// ==================== STATE MANAGEMENT ====================
// Trạng thái hiển thị modal thêm công việc
const [modalVisible, setModalVisible] = useState(false);
// Danh sách công việc mẫu với các trạng thái khác nhau
const [dataList, setDataList] = useState([ const [dataList, setDataList] = useState([
{ {
id: 1, id: 1,
...@@ -11,14 +24,8 @@ const ListWork = props => { ...@@ -11,14 +24,8 @@ const ListWork = props => {
status: 'Đang thực hiện', status: 'Đang thực hiện',
deadline: '2025-09-04', deadline: '2025-09-04',
supervisor: [ supervisor: [
{ {id: 1, name: 'Trần Văn Hùng'},
id: 1, {id: 2, name: 'Nguyễn Văn A'},
name: 'Trần Văn Hùng',
},
{
id: 2,
name: 'Nguyễn Văn A',
},
], ],
document: 'BM255, Nguyễn Minh Đức', document: 'BM255, Nguyễn Minh Đức',
}, },
...@@ -28,14 +35,8 @@ const ListWork = props => { ...@@ -28,14 +35,8 @@ const ListWork = props => {
status: 'Cần chỉnh sửa', status: 'Cần chỉnh sửa',
deadline: '2025-09-04', deadline: '2025-09-04',
supervisor: [ supervisor: [
{ {id: 1, name: 'Trần Văn Hùng'},
id: 1, {id: 2, name: 'Nguyễn Văn A'},
name: 'Trần Văn Hùng',
},
{
id: 2,
name: 'Nguyễn Văn A',
},
], ],
document: 'BM255, Nguyễn Minh Đức', document: 'BM255, Nguyễn Minh Đức',
}, },
...@@ -45,14 +46,8 @@ const ListWork = props => { ...@@ -45,14 +46,8 @@ const ListWork = props => {
status: 'Chờ duyệt', status: 'Chờ duyệt',
deadline: '2025-09-04', deadline: '2025-09-04',
supervisor: [ supervisor: [
{ {id: 1, name: 'Trần Văn Hùng'},
id: 1, {id: 2, name: 'Nguyễn Văn A'},
name: 'Trần Văn Hùng',
},
{
id: 2,
name: 'Nguyễn Văn A',
},
], ],
document: 'BM255, Nguyễn Minh Đức', document: 'BM255, Nguyễn Minh Đức',
}, },
...@@ -62,14 +57,8 @@ const ListWork = props => { ...@@ -62,14 +57,8 @@ const ListWork = props => {
status: 'Đợi báo cáo', status: 'Đợi báo cáo',
deadline: '2025-09-04', deadline: '2025-09-04',
supervisor: [ supervisor: [
{ {id: 1, name: 'Trần Văn Hùng'},
id: 1, {id: 2, name: 'Nguyễn Văn A'},
name: 'Trần Văn Hùng',
},
{
id: 2,
name: 'Nguyễn Văn A',
},
], ],
document: 'BM255, Nguyễn Minh Đức', document: 'BM255, Nguyễn Minh Đức',
}, },
...@@ -79,19 +68,156 @@ const ListWork = props => { ...@@ -79,19 +68,156 @@ const ListWork = props => {
status: 'Đã hoàn thành', status: 'Đã hoàn thành',
deadline: '2025-09-04', deadline: '2025-09-04',
supervisor: [ supervisor: [
{id: 1, name: 'Trần Văn Hùng'},
{id: 2, name: 'Nguyễn Văn A'},
],
document: 'Văn bản thông báo lịch nộp thời khóa biểu của học kỳ 2 năm 2025',
},
]);
// ==================== MODAL HANDLERS ====================
// Mở modal thêm công việc mới
const handleAddWork = () => {
setModalVisible(true);
};
// Đóng modal thêm công việc
const handleCloseModal = () => {
setModalVisible(false);
};
// Xử lý lưu công việc mới
const handleSaveWork = workData => {
console.log('Đang lưu công việc:', workData);
// TODO: Thêm logic lưu công việc vào database
setModalVisible(false);
};
// ==================== FILTER & SEARCH HANDLERS ====================
// Xử lý thay đổi bộ lọc tab
const handleFilterChange = item => {
console.log('Bộ lọc đã thay đổi:', item);
// TODO: Thêm logic lọc danh sách theo tab được chọn
};
// ==================== NAVIGATION HANDLERS ====================
// Điều hướng đến màn hình chi tiết công việc
const handleViewDetail = item => {
navigation.navigate(ScreenName.DETAILWORK, {workItem: item});
};
// ==================== ACTION HANDLERS ====================
// Xử lý các hành động báo cáo (báo cáo, yêu cầu báo cáo)
const handleReportAction = (item, action) => {
console.log(`Thực hiện hành động ${action} cho công việc:`, item.id);
// TODO: Thêm logic xử lý các hành động báo cáo
switch (action) {
case 'report':
// Xử lý báo cáo công việc
break;
default:
break;
}
};
// Xử lý các hành động phê duyệt (phê duyệt, yêu cầu chỉnh sửa)
const handleApprovalAction = (item, action) => {
console.log(`Thực hiện hành động ${action} cho công việc:`, item.id);
// TODO: Thêm logic xử lý phê duyệt
switch (action) {
case 'approve':
// Xử lý phê duyệt công việc
break;
case 'needsEdit':
// Xử lý yêu cầu chỉnh sửa
break;
default:
break;
}
};
// ==================== UTILITY FUNCTIONS ====================
// Lấy màu sắc theo trạng thái công việc
const getStatusColor = status => {
switch (status) {
case 'Đang thực hiện':
return '#FF9500'; // Cam
case 'Chờ duyệt':
return '#007AFF'; // Xanh dương
case 'Cần chỉnh sửa':
return '#FF9500'; // Cam
case 'Đã hoàn thành':
return '#34C759'; // Xanh lá
case 'Đợi báo cáo':
return '#007AFF'; // Xanh dương
default:
return '#8E8E93'; // Xám
}
};
// Lấy danh sách button theo trạng thái công việc
const getButtonsForStatus = status => {
// Ẩn button cho các trạng thái: hoàn thành, cần chỉnh sửa, đợi báo cáo
if (['Đã hoàn thành', 'Cần chỉnh sửa', 'Đợi báo cáo'].includes(status)) {
return [];
}
// Trường hợp đặc biệt cho "Chờ duyệt" - hiển thị 2 button
if (status === 'Chờ duyệt') {
return [
{ {
id: 1, title: 'Cần chỉnh sửa',
name: 'Trần Văn Hùng', backgroundColor: '#FF9500',
action: 'needsEdit',
}, },
{ {
id: 2, title: 'Phê duyệt',
name: 'Nguyễn Văn A', backgroundColor: '#007AFF',
action: 'approve',
}, },
], ];
document: 'Văn bản thông báo lịch nộp thời khóa biểu của học kỳ 2 năm 2025 ', }
// Button mặc định cho các trạng thái khác
const buttonTitle = status === 'Đang thực hiện' ? 'Yêu cầu báo cáo' : 'Báo cáo';
return [
{
title: buttonTitle,
backgroundColor: '#FF9500',
action: 'report',
}, },
]); ];
return <ListWorkView searchQuery={searchQuery} setSearchQuery={setSearchQuery} dataList={dataList} />; };
// ==================== RENDER ====================
return (
<ListWorkView
// Props dữ liệu
searchQuery={searchQuery}
setSearchQuery={setSearchQuery}
dataList={dataList}
modalVisible={modalVisible}
// Props xử lý sự kiện
onFilterChange={handleFilterChange}
onAddWork={handleAddWork}
onSaveWork={handleSaveWork}
onCloseModal={handleCloseModal}
onViewDetail={handleViewDetail}
onReportAction={handleReportAction}
onApprovalAction={handleApprovalAction}
// Props utility functions
getStatusColor={getStatusColor}
getButtonsForStatus={getButtonsForStatus}
/>
);
}; };
export default ListWork; export default ListWork;
...@@ -61,8 +61,8 @@ const styles = StyleSheet.create({ ...@@ -61,8 +61,8 @@ const styles = StyleSheet.create({
}, },
containerCard:{ containerCard:{
backgroundColor: R.colors.white, backgroundColor: R.colors.white,
padding: 10,
borderBottomLeftRadius:15, borderBottomLeftRadius:15,
paddingBottom:10,
borderBottomRightRadius:15, borderBottomRightRadius:15,
shadowColor: R.colors.black, shadowColor: R.colors.black,
shadowOffset: {width: 0.5, height: 2}, shadowOffset: {width: 0.5, height: 2},
......
import React, {useState} from 'react'; import React from 'react';
import { import {
Text, Text,
View, View,
TouchableOpacity, TouchableOpacity,
StyleSheet,
Image, Image,
TextInput, TextInput,
FlatList, FlatList,
...@@ -17,49 +16,25 @@ import R from '../../assets/R'; ...@@ -17,49 +16,25 @@ import R from '../../assets/R';
import TabViewComponent from '../../components/TabView'; import TabViewComponent from '../../components/TabView';
import AddWorkModal from '../list_work/modal_add/index'; import AddWorkModal from '../list_work/modal_add/index';
import Button from '../../components/Button'; import Button from '../../components/Button';
import * as ScreenName from '../../routers/ScreenNames';
import {useNavigation} from '@react-navigation/native';
const ListWorkView = props => { const ListWorkView = props => {
const {searchQuery, setSearchQuery, dataList} = props; const {
searchQuery,
const navigation = useNavigation(); setSearchQuery,
dataList,
const [modalVisible, setModalVisible] = useState(false); modalVisible,
onFilterChange,
const handleFilterChange = item => { onAddWork,
console.log(item); onSaveWork,
}; onCloseModal,
onViewDetail,
const handleAddWork = () => { onReportAction,
setModalVisible(true); onApprovalAction,
}; getStatusColor,
getButtonsForStatus,
const handleSaveWork = workData => { } = props;
console.log('Saving work:', workData);
}; const renderTabView = () => {
const handleCloseModal = () => {
setModalVisible(false);
};
const getColor = (status) => {
switch (status) {
case 'Đang thực hiện':
return R.colors.orange;
case 'Chờ duyệt':
return R.colors.blue;
case 'Cần chỉnh sửa':
return R.colors.orange;
case 'Đã hoàn thành':
return R.colors.green;
case 'Đợi báo cáo':
return R.colors.blue;
default:
return R.colors.gray;
}
};
const renderTabView = ( ) => {
return ( return (
<TabViewComponent <TabViewComponent
data={[ data={[
...@@ -93,109 +68,93 @@ const ListWorkView = props => { ...@@ -93,109 +68,93 @@ const ListWorkView = props => {
fontSize: R.fontsize.fontSizeContent, fontSize: R.fontsize.fontSizeContent,
}} }}
showActiveIndicator={false} showActiveIndicator={false}
onFilterChange={handleFilterChange} onFilterChange={onFilterChange}
/> />
); );
}; };
const renderReportButton = (item) => { const renderActionButtons = item => {
// Hide report button for completed, needs editing, and waiting for report status const buttons = getButtonsForStatus(item.status);
if (item.status === 'Đã hoàn thành' || item.status === 'Cần chỉnh sửa' || item.status === 'Đợi báo cáo') {
return null;
}
// Special case for "Chờ duyệt" - show two buttons return buttons.map((button, index) => (
if (item.status === 'Chờ duyệt') {
return (
<>
<Button
title="Cần chỉnh sửa"
onPress={() => {}}
backgroundColor={R.colors.orange}
textColor={R.colors.white}
fontSize={R.fontsize.fontSizeContent}
height={35}
width={100}
containerStyle={{marginRight: 10, borderRadius: 20}}
/>
<Button <Button
title="Phê duyệt" key={index}
onPress={() => {}} title={button.title}
backgroundColor={R.colors.green} onPress={() => {
textColor={R.colors.white} if (button.action === 'approve' || button.action === 'needsEdit') {
fontSize={R.fontsize.fontSizeContent} onApprovalAction(item, button.action);
height={35} } else {
width={100} onReportAction(item, button.action);
containerStyle={{marginRight: 10, borderRadius: 20}}
/>
</>
);
} }
}}
let buttonTitle = 'Báo cáo'; backgroundColor={button.backgroundColor}
switch (item.status) {
case 'Đang thực hiện':
buttonTitle = 'Yêu cầu báo cáo';
break;
default:
buttonTitle = 'Báo cáo';
break;
}
return (
<Button
title={buttonTitle}
onPress={() => {}}
backgroundColor={R.colors.orange}
textColor={R.colors.white} textColor={R.colors.white}
fontSize={R.fontsize.fontSizeContent} fontSize={R.fontsize.fontSizeContent}
height={35} height={35}
width={120} width={120}
containerStyle={{marginRight: 10, borderRadius: 20}} containerStyle={{marginRight: 10, borderRadius: 20}}
/> />
); ));
}; };
const renderListView = ( {item} ) =>{ const renderListView = ({item}) => {
return( return (
<View style={{ marginHorizontal:15, marginVertical:10}}> <TouchableOpacity
<View style ={{backgroundColor: getColor(item.status),borderTopLeftRadius:15, borderTopRightRadius:15}}> style={{marginHorizontal: 15, marginVertical: 10}}
<Text style={[styles.subText , {marginHorizontal:15, fontFamily: R.fonts.fontMedium, fontWeight: '600', color: R.colors.white,}]}>{item.status}</Text> onPress={() => onViewDetail(item)}
activeOpacity={0.7}
>
<View
style={{
backgroundColor: getStatusColor(item.status),
borderTopLeftRadius: 15,
borderTopRightRadius: 15,
}}>
<Text
style={[
styles.subText,
{
marginHorizontal: 15,
fontFamily: R.fonts.fontMedium,
fontWeight: '600',
color: R.colors.white,
},
]}>
{item.status}
</Text>
</View> </View>
<View style={styles.containerCard}> <View style={styles.containerCard}>
<View style ={{paddingHorizontal:15, paddingTop:10}}>
<Text style={styles.text }>{item.title}</Text> <Text style={styles.text}>{item.title}</Text>
<View style={{flexDirection: 'row', justifyContent: 'space-between' }}> <View style={{flexDirection: 'row', justifyContent: 'space-between'}}>
<Text style={styles.text}>Ngày đến hn: <Text style={styles.text}>
Ngày đến hn:
<Text style={styles.subText}>{item.deadline}</Text> <Text style={styles.subText}>{item.deadline}</Text>
</Text> </Text>
</View> </View>
<Text style={styles.text}> <Text style={styles.text}>
Người giám sát: Người giám sát:
<Text style={styles.subText}>{item.supervisor.map((item) => item.name).join(', ')}</Text> <Text style={styles.subText}>
{item.supervisor.map(item => item.name).join(', ')}
</Text>
</Text> </Text>
<Text style={styles.text}> <Text style={styles.text}>
Thuc văn bn: Thuc văn bn:
<Text style={styles.subText}>{item.document}</Text> <Text style={styles.subText}>{item.document}</Text>
</Text> </Text>
<View style={{flexDirection: 'row', justifyContent: 'flex-end', marginTop:10}}>
{renderReportButton(item)}
<Button
title="Chi tiết"
onPress={() => navigation.navigate(ScreenName.DETAILWORK)}
backgroundColor={R.colors.blue}
textColor={R.colors.white}
fontSize={R.fontsize.fontSizeContent}
height={35}
width={100}
containerStyle={{borderRadius: 20}}
/>
</View> </View>
<View
style={{
flexDirection: 'row',
justifyContent: 'flex-end',
marginTop: 10,
}}>
{renderActionButtons(item)}
</View> </View>
</View> </View>
) </TouchableOpacity>
);
}; };
return ( return (
...@@ -204,7 +163,7 @@ const ListWorkView = props => { ...@@ -204,7 +163,7 @@ const ListWorkView = props => {
<View style={styles.body}> <View style={styles.body}>
{renderTabView()} {renderTabView()}
<View style={{marginBottom: 15, flex:1}}> <View style={{marginBottom: 15, flex: 1}}>
<View style={styles.card}> <View style={styles.card}>
<TouchableOpacity style={styles.btnCard}> <TouchableOpacity style={styles.btnCard}>
<Text style={styles.text}>Hc k 2, Năm 2025</Text> <Text style={styles.text}>Hc k 2, Năm 2025</Text>
...@@ -228,21 +187,20 @@ const ListWorkView = props => { ...@@ -228,21 +187,20 @@ const ListWorkView = props => {
</View> </View>
<View style={{flex: 0.1}}></View> <View style={{flex: 0.1}}></View>
<View style={{flex:1}}> <View style={{flex: 1}}>
<Dropdown title={'Tìm kiếm'} height={40} /> <Dropdown title={'Tìm kiếm'} height={40} />
</View> </View>
</View> </View>
<FlatList <FlatList
data={dataList} data={dataList}
renderItem={renderListView} renderItem={renderListView}
keyExtractor={item => item.id.toString()} keyExtractor={item => item.id.toString()}
/> />
</View> </View>
</View> </View>
<FAB> <FAB>
<SubButton <SubButton
onPress={handleAddWork} onPress={onAddWork}
label="Tạo công việc" label="Tạo công việc"
images={R.images.icMenuEdit} images={R.images.icMenuEdit}
backgroundColor={R.colors.blue} backgroundColor={R.colors.blue}
...@@ -251,8 +209,8 @@ const ListWorkView = props => { ...@@ -251,8 +209,8 @@ const ListWorkView = props => {
<AddWorkModal <AddWorkModal
visible={modalVisible} visible={modalVisible}
onClose={handleCloseModal} onClose={onCloseModal}
onSave={handleSaveWork} onSave={onSaveWork}
/> />
</View> </View>
); );
......
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