Commit fb8e80c7 by tungnq

IMPORTANT: Bổ sung thư viện json- server và tái cấu trúc một số file

parent 5fe2ad7c
{}
\ No newline at end of file
......@@ -7,7 +7,8 @@
"ios": "react-native run-ios",
"lint": "eslint .",
"start": "react-native start",
"test": "jest"
"test": "jest",
"server": "json-server --watch db/database.json --port 3000"
},
"dependencies": {
"@react-native-community/async-storage": "^1.12.1",
......@@ -85,6 +86,7 @@
"babel-jest": "^29.6.3",
"eslint": "^8.19.0",
"jest": "^29.6.3",
"json-server": "^1.0.0-beta.3",
"prettier": "2.8.8",
"react-native-svg-transformer": "^1.5.1",
"react-test-renderer": "18.2.0",
......
......@@ -9,13 +9,12 @@ import {
} from 'react-native';
import R from '../assets/R';
const Button = props => {
const {
title,
onPress,
containerStyle,
txtStyle,
title,
onPress,
containerStyle,
txtStyle,
backgroundColor,
height,
borderRadius,
......@@ -43,11 +42,11 @@ const Button = props => {
{
width: width,
height: height,
paddingHorizontal:paddingHorizontal,
paddingVertical:paddingVertical,
paddingHorizontal: paddingHorizontal,
paddingVertical: paddingVertical,
backgroundColor: backgroundColor,
borderRadius: borderRadius,
marginRight: marginRight
marginRight: marginRight,
},
{...containerStyle},
]}
......@@ -55,14 +54,18 @@ const Button = props => {
onPress={onPress}>
<View
style={{
flex:1,
justifyContent:'space-around',
flexDirection:'row',
alignItems:'center',
flex: 1,
justifyContent: 'space-around',
flexDirection: 'row',
alignItems: 'center',
}}>
{iconLeft && <Image source={iconLeft} tintColor={tintColorLeft} style={iconStyleLeft} />}
{iconLeft && (
<Image
source={iconLeft}
tintColor={tintColorLeft}
style={iconStyleLeft}
/>
)}
<Text
style={[
{
......@@ -77,9 +80,9 @@ const Button = props => {
]}>
{title}
</Text>
{icon&& <Image source={icon} style={iconStyle} />}
{icon && <Image source={icon} style={iconStyle} />}
</View>
</TouchableOpacity>
);
};
export default Button ;
export default Button;
import React, { useState } from 'react';
import React, {useState} from 'react';
import {Text, View, StyleSheet} from 'react-native';
import ClassActivityView from './view';
const ClassActivity = (props) => {
const [dataList , setDataList] = useState([
{
id:'1',
class_activity:'ATTT2024.1',
course:'2024',
training_system:'CQUI',
class_by_course:'ATTT2024.1',
science:'MMT&TT',
class_leader:'Nguyễn Minh Đức',
},
{
"id": "2",
"class_activity": "IS2024.IP57.1",
"course": "2024",
"training_system": "CLC",
"class_by_course": "IS2024.IP57.1",
"science": "CNTT",
"class_leader": "Trần Thị Hương"
},
{
"id": "3",
"class_activity": "BGF197.47.1",
"course": "2023",
"training_system": "CQUI",
"class_by_course": "BGF197.47.1",
"science": "Kinh tế",
"class_leader": "Phạm Văn Nam"
},
{
"id": "4",
"class_activity": "CS301.12.3",
"course": "2022",
"training_system": "CLC",
"class_by_course": "CS301.12.3",
"science": "Khoa học Máy tính",
"class_leader": "Lê Thị Mai"
},
{
"id": "5",
"class_activity": "MA205.C33.2",
"course": "2025",
"training_system": "CQUI",
"class_by_course": "MA205.C33.2",
"science": "Toán",
"class_leader": "Nguyễn Văn Hùng"
},
{
"id": "6",
"class_activity": "ENG101.P2.5",
"course": "2024",
"training_system": "CLC",
"class_by_course": "ENG101.P2.5",
"science": "Ngoại ngữ",
"class_leader": "Hoàng Thu Trang"
},
{
"id": "7",
"class_activity": "PHYS202.3A.1",
"course": "2023",
"training_system": "CQUI",
"class_by_course": "PHYS202.3A.1",
"science": "Vật lý",
"class_leader": "Vũ Đức Anh"
},
{
"id": "8",
"class_activity": "CHEM101.12.2",
"course": "2025",
"training_system": "CLC",
"class_by_course": "CHEM101.12.2",
"science": "Hóa học",
"class_leader": "Đỗ Lan Phương"
},
{
"id": "9",
"class_activity": "BIO202.A1.1",
"course": "2022",
"training_system": "CQUI",
"class_by_course": "BIO202.A1.1",
"science": "Sinh học",
"class_leader": "Nguyễn Thị Ngọc"
},
{
"id": "10",
"class_activity": "LAW303.L12.1",
"course": "2024",
"training_system": "CLC",
"class_by_course": "LAW303.L12.1",
"science": "Luật",
"class_leader": "Phan Minh Tuấn"
},
{
"id": "11",
"class_activity": "HIS204.HB1.3",
"course": "2023",
"training_system": "CQUI",
"class_by_course": "HIS204.HB1.3",
"science": "Lịch sử",
"class_leader": "Trần Văn Bình"
},
{
"id": "12",
"class_activity": "PSY101.PC2.1",
"course": "2025",
"training_system": "CLC",
"class_by_course": "PSY101.PC2.1",
"science": "Tâm lý",
"class_leader": "Ngô Thị Hạnh"
},
{
"id": "13",
"class_activity": "ART203.AR3.2",
"course": "2022",
"training_system": "CQUI",
"class_by_course": "ART203.AR3.2",
"science": "Mỹ thuật",
"class_leader": "Bùi Văn Sơn"
},
{
"id": "14",
"class_activity": "ECON305.EC2.1",
"course": "2024",
"training_system": "CLC",
"class_by_course": "ECON305.EC2.1",
"science": "Kinh tế quốc tế",
"class_leader": "Nguyễn Thuỳ Dung"
},
{
"id": "15",
"class_activity": "MED401.MC1.1",
"course": "2025",
"training_system": "CQUI",
"class_by_course": "MED401.MC1.1",
"science": "Y học",
"class_leader": "Trần Quốc Việt"
},
{
"id": "16",
"class_activity": "EDU202.ED5.2",
"course": "2023",
"training_system": "CLC",
"class_by_course": "EDU202.ED5.2",
"science": "Giáo dục",
"class_leader": "Lê Hoài Nam"
}
])
return (
<ClassActivityView dataList={dataList}
setDataList={setDataList}
/>
);
const ClassActivity = props => {
const [dataList, setDataList] = useState([
{
id: '1',
class_activity: 'ATTT2024.1',
course: '2024',
training_system: 'CQUI',
class_by_course: 'ATTT2024.1',
science: 'MMT&TT',
class_leader: 'Nguyễn Minh Đức',
},
{
id: '2',
class_activity: 'IS2024.IP57.1',
course: '2024',
training_system: 'CLC',
class_by_course: 'IS2024.IP57.1',
science: 'CNTT',
class_leader: 'Trần Thị Hương',
},
{
id: '3',
class_activity: 'BGF197.47.1',
course: '2023',
training_system: 'CQUI',
class_by_course: 'BGF197.47.1',
science: 'Kinh tế',
class_leader: 'Phạm Văn Nam',
},
{
id: '4',
class_activity: 'CS301.12.3',
course: '2022',
training_system: 'CLC',
class_by_course: 'CS301.12.3',
science: 'Khoa học Máy tính',
class_leader: 'Lê Thị Mai',
},
{
id: '5',
class_activity: 'MA205.C33.2',
course: '2025',
training_system: 'CQUI',
class_by_course: 'MA205.C33.2',
science: 'Toán',
class_leader: 'Nguyễn Văn Hùng',
},
{
id: '6',
class_activity: 'ENG101.P2.5',
course: '2024',
training_system: 'CLC',
class_by_course: 'ENG101.P2.5',
science: 'Ngoại ngữ',
class_leader: 'Hoàng Thu Trang',
},
{
id: '7',
class_activity: 'PHYS202.3A.1',
course: '2023',
training_system: 'CQUI',
class_by_course: 'PHYS202.3A.1',
science: 'Vật lý',
class_leader: 'Vũ Đức Anh',
},
{
id: '8',
class_activity: 'CHEM101.12.2',
course: '2025',
training_system: 'CLC',
class_by_course: 'CHEM101.12.2',
science: 'Hóa học',
class_leader: 'Đỗ Lan Phương',
},
{
id: '9',
class_activity: 'BIO202.A1.1',
course: '2022',
training_system: 'CQUI',
class_by_course: 'BIO202.A1.1',
science: 'Sinh học',
class_leader: 'Nguyễn Thị Ngọc',
},
{
id: '10',
class_activity: 'LAW303.L12.1',
course: '2024',
training_system: 'CLC',
class_by_course: 'LAW303.L12.1',
science: 'Luật',
class_leader: 'Phan Minh Tuấn',
},
{
id: '11',
class_activity: 'HIS204.HB1.3',
course: '2023',
training_system: 'CQUI',
class_by_course: 'HIS204.HB1.3',
science: 'Lịch sử',
class_leader: 'Trần Văn Bình',
},
{
id: '12',
class_activity: 'PSY101.PC2.1',
course: '2025',
training_system: 'CLC',
class_by_course: 'PSY101.PC2.1',
science: 'Tâm lý',
class_leader: 'Ngô Thị Hạnh',
},
{
id: '13',
class_activity: 'ART203.AR3.2',
course: '2022',
training_system: 'CQUI',
class_by_course: 'ART203.AR3.2',
science: 'Mỹ thuật',
class_leader: 'Bùi Văn Sơn',
},
{
id: '14',
class_activity: 'ECON305.EC2.1',
course: '2024',
training_system: 'CLC',
class_by_course: 'ECON305.EC2.1',
science: 'Kinh tế quốc tế',
class_leader: 'Nguyễn Thuỳ Dung',
},
{
id: '15',
class_activity: 'MED401.MC1.1',
course: '2025',
training_system: 'CQUI',
class_by_course: 'MED401.MC1.1',
science: 'Y học',
class_leader: 'Trần Quốc Việt',
},
{
id: '16',
class_activity: 'EDU202.ED5.2',
course: '2023',
training_system: 'CLC',
class_by_course: 'EDU202.ED5.2',
science: 'Giáo dục',
class_leader: 'Lê Hoài Nam',
},
]);
return <ClassActivityView dataList={dataList} setDataList={setDataList} />;
};
export default ClassActivity;
......@@ -2,7 +2,7 @@ import React, {useState} from 'react';
import {Text, View, StyleSheet} from 'react-native';
import DetailStudentView from './view';
const DetailStudent = (props) => {
const DetailStudent = props => {
const [student, setStudent] = useState({
name: 'Nguyễn Minh Đức',
code_student: '2598671',
......@@ -11,58 +11,53 @@ const DetailStudent = (props) => {
tele_phone: '0123456789',
gender: 'Nam',
average_score: '8.5',
latest_semester_average_score:'8.5',
training_average_score:'100',
type:[
latest_semester_average_score: '8.5',
training_average_score: '100',
type: [
{
id:1,
name:'Chuẩn đầu ra NN',
status:true,
id: 1,
name: 'Chuẩn đầu ra NN',
status: true,
},
{
id:2,
name:'Chuẩn trình NN',
status:true,
},
{
id:3,
name:'Quá tiến độ học tập',
status:false,
},
{
id:4,
name:'Nợ học phí',
status:false,
},
]
id: 2,
name: 'Chuẩn trình NN',
status: true,
},
{
id: 3,
name: 'Quá tiến độ học tập',
status: false,
},
{
id: 4,
name: 'Nợ học phí',
status: false,
},
],
});
const handleCheckboxChange = (itemId, newValue) => {
setStudent(prevStudent => {
// Sao chép danh sách type cũ
const updatedTypes = prevStudent.type.map(item => {
if (item.id === itemId) {
// Nếu id trùng -> tạo object mới với status cập nhật
return {
...item,
status: newValue,
};
} else {
// Nếu không trùng -> giữ nguyên item
return item;
}
});
// Trả về student mới với type đã cập nhật
return {
...prevStudent,
type: updatedTypes,
};
});
};
return (
<DetailStudentView
<DetailStudentView
student={student}
onCheckboxChange={handleCheckboxChange}
/>
......
import { StyleSheet, Text, View } from 'react-native'
import R from '../../../../assets/R'
import {StyleSheet, Text, View} from 'react-native';
import R from '../../../../assets/R';
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: R.colors.white,
},
containerCard:{
marginHorizontal:15,
marginVertical:5,
borderRadius:10,
},
card:{
borderBottomEndRadius:10,
borderBottomStartRadius:10,
paddingHorizontal:10,
paddingVertical:5,
container: {
flex: 1,
backgroundColor: R.colors.white,
},
containerCard: {
marginHorizontal: 15,
marginVertical: 5,
borderRadius: 10,
},
card: {
borderBottomEndRadius: 10,
borderBottomStartRadius: 10,
paddingHorizontal: 10,
paddingVertical: 5,
backgroundColor:R.colors.white,
shadowColor:R.colors.black,
shadowOffset:{width:0.5,height:2},
shadowOpacity:Platform.OS === 'ios' ? 0.25 : 1,
shadowRadius:2,
elevation:Platform.OS === 'ios' ? 1 : 2,
},
backgroundColor: R.colors.white,
shadowColor: R.colors.black,
shadowOffset: {width: 0.5, height: 2},
shadowOpacity: Platform.OS === 'ios' ? 0.25 : 1,
shadowRadius: 2,
elevation: Platform.OS === 'ios' ? 1 : 2,
},
containerText:{
flexDirection:'row',
alignItems:'center',
justifyContent:'center',
marginBottom:5,
},
containerTextItemLeft:{
alignItems:'flex-start',
justifyContent:'flex-start',
width:'45%',
},
containerTextItemRight:{
flexDirection:'row',
alignItems:'center',
justifyContent:'center',
},
sizedBox:{
flex:3
},
text:{
fontSize:R.sizes.sm,
fontFamily:R.fonts.fontMedium,
fontWeight:'600',
color:R.colors.black,
textAlign:'center',
},
containerSubText:{
flexDirection:'row',
marginBottom:5
},
containerSubTextItemLeft:{
},
containerSubTextItemRight:{
},
textTitle:{
fontSize:R.sizes.md,
fontFamily:R.fonts.fontMedium,
fontWeight:'600',
color:R.colors.blue,
marginHorizontal:15,
},
label:{
fontSize:R.sizes.sm,
fontFamily:R.fonts.fontMedium,
fontWeight:'600',
color:R.colors.black,
},
checkboxContainer: {
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'space-between',
},
checkboxItem: {
width: '50%',
marginBottom: 15,
},
})
containerText: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
marginBottom: 5,
},
containerTextItemLeft: {
alignItems: 'flex-start',
justifyContent: 'flex-start',
width: '45%',
},
containerTextItemRight: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
sizedBox: {
flex: 3,
},
export default styles
text: {
fontSize: R.sizes.sm,
fontFamily: R.fonts.fontMedium,
fontWeight: '600',
color: R.colors.black,
textAlign: 'center',
},
containerSubText: {
flexDirection: 'row',
marginBottom: 5,
},
containerSubTextItemLeft: {},
containerSubTextItemRight: {},
textTitle: {
fontSize: R.sizes.md,
fontFamily: R.fonts.fontMedium,
fontWeight: '600',
color: R.colors.blue,
marginHorizontal: 15,
},
label: {
fontSize: R.sizes.sm,
fontFamily: R.fonts.fontMedium,
fontWeight: '600',
color: R.colors.black,
},
checkboxContainer: {
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'space-between',
},
checkboxItem: {
width: '50%',
marginBottom: 15,
},
});
export default styles;
......@@ -23,18 +23,23 @@ const DetailStudentView = props => {
return statusColors[status] || '#9E9E9E';
};
const statusColor = getStatusColor(student.status);
return (
<View style={styles.container}>
<Header title={'Nguyễn Minh Đức - 2598671'} isBack />
<View style={styles.body}>
<View style={[styles.card ,{marginHorizontal:15, marginTop:10 , borderRadius:10}]}>
<View
style={[
styles.card,
{marginHorizontal: 15, marginTop: 10, borderRadius: 10},
]}>
<View style={styles.containerText}>
<View style={styles.containerTextItemLeft}>
<Text style={styles.text}>STC TL / STC CTDT 23 / 102</Text>
</View>
<View style={styles.sizedBox}></View>
<View style={styles.containerTextItemRight}>
<Text style={[styles.text]}>Tình trng: {' '}</Text>
<Text style={[styles.text]}>Tình trng: </Text>
<Text style={[styles.text, {color: statusColor}]}>
{student.status}
</Text>
......@@ -44,7 +49,7 @@ const DetailStudentView = props => {
<View style={styles.containerSubText}>
<View style={styles.containerSubTextItemLeft}>
<Text style={[styles.text]}>
Ngày sinh: {' '}
Ngày sinh:{' '}
<Text
style={[
styles.text,
......@@ -57,7 +62,7 @@ const DetailStudentView = props => {
<View style={styles.sizedBox}></View>
<View style={styles.containerSubTextItemRight}>
<Text style={[styles.text]}>
SDT: {' '}
SDT:{' '}
<Text
style={[
styles.text,
......@@ -72,7 +77,7 @@ const DetailStudentView = props => {
<View style={styles.containerSubText}>
<View style={styles.containerSubTextItemLeft}>
<Text style={[styles.text]}>
Gii tính: {' '}
Gii tính:{' '}
<Text
style={[
styles.text,
......@@ -85,7 +90,7 @@ const DetailStudentView = props => {
<View style={styles.sizedBox}></View>
<View style={styles.containerSubTextItemRight}>
<Text style={[styles.text]}>
Đim trung bình: {' '}
Đim trung bình:{' '}
<Text
style={[
styles.text,
......@@ -101,7 +106,7 @@ const DetailStudentView = props => {
<View style={styles.containerSubText}>
<View style={styles.containerSubTextItemLeft}>
<Text style={[styles.text]}>
Đim TB hc kì gn nht: {' '}
Đim TB hc kì gn nht:{' '}
<Text
style={[
styles.text,
......@@ -116,7 +121,7 @@ const DetailStudentView = props => {
<View style={styles.containerSubText}>
<View style={styles.containerSubTextItemLeft}>
<Text style={[styles.text]}>
Đim rèn luyn TB: {' '}
Đim rèn luyn TB:{' '}
<Text
style={[
styles.text,
......@@ -146,17 +151,23 @@ const DetailStudentView = props => {
))}
</View>
</View>
<Text style={[styles.textTitle ,{marginTop:10}]}>Lch s tình trng ca sinh viên</Text>
<View style={[styles.containerCard, {backgroundColor:getStatusColor(student.status)}]}>
<Text
<Text style={[styles.textTitle, {marginTop: 10}]}>
Lch s tình trng ca sinh viên
</Text>
<View
style={[
styles.containerCard,
{backgroundColor: getStatusColor(student.status)},
]}>
<Text
style={[
{
fontSize: R.sizes.sm,
fontFamily: R.fonts.fontMedium,
fontWeight: '600',
color: R.colors.white,
marginHorizontal:10,
marginVertical:3
marginHorizontal: 10,
marginVertical: 3,
},
]}>
Trng thái hc tp:{' '}
......@@ -165,7 +176,6 @@ const DetailStudentView = props => {
</Text>
</Text>
<View style={styles.card}>
<Text
style={[
{
......@@ -178,8 +188,6 @@ const DetailStudentView = props => {
Hc k 2, Năm hc 2024
</Text>
<Text
style={[
{
......@@ -236,7 +244,7 @@ const DetailStudentView = props => {
{student.date_student}
</Text>
</Text>
</View>
</View>
</View>
</View>
</View>
......
......@@ -5,7 +5,6 @@ const styles = StyleSheet.create({
flex: 1,
backgroundColor: R.colors.white,
},
//Search
containerSearchBox: {
borderColor: R.colors.grayBorderInputTextHeader,
borderWidth: 1,
......@@ -14,7 +13,7 @@ const styles = StyleSheet.create({
marginVertical: 15,
backgroundColor: R.colors.white,
flexDirection: 'row',
height:35
height: 35,
},
boxIconSearch: {
maxWidth: 35,
......@@ -28,20 +27,18 @@ const styles = StyleSheet.create({
fontFamily: R.fonts.fontMedium,
fontWeight: '500',
flex: 1,
margin:0,
padding:0,
margin: 0,
padding: 0,
},
//Filter
statusContainer: {
marginBottom: 15,
marginHorizontal: 15,
flexDirection: "row",
justifyContent: "space-around"
flexDirection: 'row',
justifyContent: 'space-around',
},
statusCard: {
flexDirection: 'row',
alignItems: 'center',
},
statusDot: {
width: 10,
......@@ -64,11 +61,11 @@ const styles = StyleSheet.create({
},
body: {
flex:1,
flex: 1,
},
listContainer: {
paddingBottom: 20,
},
},
studentCard: {
backgroundColor: R.colors.white,
borderRadius: 15,
......@@ -112,8 +109,6 @@ const styles = StyleSheet.create({
color: R.colors.black,
},
statusIndicator: {
width: 15,
height: 15,
......
......@@ -13,12 +13,11 @@ import Header from '../../../components/Header/Header';
import styles from './style';
import R from '../../../assets/R';
import * as SCREENNAME from '../../../routers/ScreenNames';
import { useNavigation } from '@react-navigation/native';
import {useNavigation} from '@react-navigation/native';
const ListStudentView = props => {
const {searchText, onSearchChange, filter, statusStats} = props;
console.log(props);
const navigate = useNavigation();
//Search
const renderSearchBox = () => {
return (
<View style={styles.containerSearchBox}>
......@@ -42,12 +41,9 @@ const ListStudentView = props => {
</View>
);
};
//List status
const renderListStatus = () => {
return (
<View
style={styles.statusContainer}
>
<View style={styles.statusContainer}>
{statusStats.map((stat, index) => (
<View
key={index}
......@@ -65,8 +61,7 @@ const ListStudentView = props => {
);
};
//List student
const renderStudentItem = ({item , onPress}) => {
const renderStudentItem = ({item, onPress}) => {
const isLeftIcon = item.gender === 'Nam';
const genderIcon =
item.gender === 'Nam' ? R.images.icMale : R.images.icFemale;
......@@ -74,17 +69,29 @@ const ListStudentView = props => {
const statusColor = getStatusColor(item.status);
return (
<TouchableOpacity style={styles.studentCard} onPress={()=>{navigate.navigate(SCREENNAME.DETAILSTUDENT)}}>
<TouchableOpacity
style={styles.studentCard}
onPress={() => {
navigate.navigate(SCREENNAME.DETAILSTUDENT);
}}>
<View style={styles.studentCardContent}>
<View style={styles.studentInfo}>
{/*Tên sinh viên*/}
<View style={styles.leftSection}>
<Text style={styles.studentName}>{item.name}</Text>
{isLeftIcon && (
<Image source={genderIcon} style={styles.genderIcon} resizeMode="contain"/>
<Image
source={genderIcon}
style={styles.genderIcon}
resizeMode="contain"
/>
)}
{!isLeftIcon && (
<Image source={genderIcon} style={styles.genderIcon} resizeMode="contain"/>
<Image
source={genderIcon}
style={styles.genderIcon}
resizeMode="contain"
/>
)}
</View>
<View style={styles.rightSection}>
......@@ -106,11 +113,23 @@ const ListStudentView = props => {
<View style={styles.studentInfo}>
{/*Tên sinh viên*/}
<View style={styles.leftSection}>
<Text style={[styles.studentName,{fontFamily:R.fonts.fontRegular,fontWeight:'400'}]}>Ngày sinh: {item.date_student}</Text>
<Text
style={[
styles.studentName,
{fontFamily: R.fonts.fontRegular, fontWeight: '400'},
]}>
Ngày sinh: {item.date_student}
</Text>
</View>
<View style={styles.rightSection}>
{/*Mã sinh viên*/}
<Text style={[styles.studentName,{fontFamily:R.fonts.fontRegular,fontWeight:'400'}]}>SĐT: {item.tele_phone}</Text>
<Text
style={[
styles.studentName,
{fontFamily: R.fonts.fontRegular, fontWeight: '400'},
]}>
SĐT: {item.tele_phone}
</Text>
</View>
</View>
</View>
......@@ -133,14 +152,14 @@ const ListStudentView = props => {
<View style={styles.body}>
{renderSearchBox()}
{renderListStatus()}
<FlatList
data={filter || []}
renderItem={renderStudentItem}
vertical
keyExtractor={(item, index) => `${index}`}
showsVerticalScrollIndicator={false}
contentContainerStyle={{paddingTop: 5}}
/>
<FlatList
data={filter || []}
renderItem={renderStudentItem}
vertical
keyExtractor={(item, index) => `${index}`}
showsVerticalScrollIndicator={false}
contentContainerStyle={{paddingTop: 5}}
/>
</View>
</View>
);
......
import { StyleSheet , Platform} from 'react-native'
import {StyleSheet, Platform} from 'react-native';
import R from '../../assets/R';
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: R.colors.white,
},
body:{
flex:1,
},
card:{
borderWidth:1,
borderColor:R.colors.grayBorderInputTextHeader,
borderRadius:10,
padding:5,
marginTop:15,
marginBottom:15,
marginHorizontal:15,
alignItems:'center',
justifyContent:'center',
container: {
flex: 1,
backgroundColor: R.colors.white,
},
body: {
flex: 1,
},
containerList: {
flex: 1,
justifyContent: 'center',
},
card: {
borderWidth: 1,
borderColor: R.colors.grayBorderInputTextHeader,
borderRadius: 10,
padding: 5,
marginTop: 15,
marginBottom: 15,
marginHorizontal: 15,
alignItems: 'center',
justifyContent: 'center',
backgroundColor:R.colors.white,
shadowColor:R.colors.black,
shadowOffset:{width:0.5,height:2},
shadowOpacity:Platform.OS === 'ios' ? 0.25 : 1,
shadowRadius:5,
elevation:Platform.OS === 'ios' ? 1 : 2,
},
btnCard:{
borderRadius:10,
borderWidth:1,
padding:5,
width:'100%',
alignItems:'center',
justifyContent:'center',
borderColor:R.colors.grayBorderInputTextHeader,
},
text_title:{
fontSize:R.fontsize.fontSizeContent,
fontWeight:'600',
color:R.colors.black,
fontFamily:R.fonts.fontMedium,
},
text:{
fontSize:R.fontsize.fontSizeContent,
color:R.colors.black,
fontFamily:R.fonts.fontRegular,
fontWeight:'400',
},
containerCard:{
padding:10,
marginBottom:15 ,
borderRadius:10,
backgroundColor:R.colors.white,
shadowColor:R.colors.black,
shadowOffset:{width:0,height:2},
shadowOpacity:Platform.OS === 'ios' ? 0.25 : 1,
shadowRadius:1,
elevation:Platform.OS === 'ios' ? 1 : 2,
marginHorizontal:15,
marginVertical:15,
},
containerText:{
flexDirection:'row',
},
sizedBox:{
width:'35%',
},
containerButton:{
alignItems:'flex-end',
}
backgroundColor: R.colors.white,
shadowColor: R.colors.black,
shadowOffset: {width: 0.5, height: 2},
shadowOpacity: Platform.OS === 'ios' ? 0.25 : 1,
shadowRadius: 5,
elevation: Platform.OS === 'ios' ? 1 : 2,
},
btnCard: {
borderRadius: 10,
borderWidth: 1,
padding: 5,
width: '100%',
alignItems: 'center',
justifyContent: 'center',
borderColor: R.colors.grayBorderInputTextHeader,
},
text_title: {
fontSize: R.fontsize.fontSizeContent,
fontWeight: '600',
color: R.colors.black,
fontFamily: R.fonts.fontMedium,
},
text: {
fontSize: R.fontsize.fontSizeContent,
color: R.colors.black,
fontFamily: R.fonts.fontRegular,
fontWeight: '400',
},
containerCard: {
padding: 10,
marginBottom: 15,
borderRadius: 10,
backgroundColor: R.colors.white,
shadowColor: R.colors.black,
shadowOffset: {width: 0, height: 2},
shadowOpacity: Platform.OS === 'ios' ? 0.25 : 1,
shadowRadius: 1,
elevation: Platform.OS === 'ios' ? 1 : 2,
marginHorizontal: 15,
marginVertical: 15,
},
containerEmpty: {
alignItems: 'center',
justifyContent: 'center',
},
textEmpty: {
color: R.colors.black,
fontSize: R.fontsize.fontSizeSubTitle,
fontWeight: '500',
fontFamily: R.fonts.fontMedium,
},
textHeader:{
fontSize: R.fontsize.fontSizeContent,
fontWeight: '600',
fontFamily: R.fonts.fontMedium,
color: R.colors.black,
},
containerText: {
flexDirection: 'row',
},
sizedBox: {
width: '35%',
},
containerButton: {
alignItems: 'flex-end',
},
});
})
export default styles
\ No newline at end of file
export default styles;
import React from 'react';
import {
Text,
View,
TouchableOpacity,
StyleSheet,
SafeAreaView,
FlatList,
} from 'react-native';
import {Text, View, TouchableOpacity, FlatList, Image} from 'react-native';
import styles from './style';
import Header from '../../components/Header/Header';
import Button from '../../components/Button';
import R from '../../assets/R';
import * as SCREENNAME from '../../routers/ScreenNames';
import {useNavigation} from '@react-navigation/native';
const ClassActivityView = props => {
const {dataList, setDataList} = props;
const navigate = useNavigation();
const renderItem = ({item}) => {
return (
<View style={styles.containerCard}>
<Text style={styles.text_title}>Lp sinh hot:{' '}
<Text style={styles.text}>{item.class_activity}</Text>
</Text>
<Text style={styles.text_title}>
Lp sinh hot: <Text style={styles.text}>{item.class_activity}</Text>
</Text>
<View style={styles.containerText}>
<Text style={styles.text_title}>Khoá: {' '}
<Text style={styles.text}>{item.course}</Text>
</Text>
<View style={styles.sizedBox}></View>
<Text style={styles.text_title}>H ĐT: {' '}
<Text style={styles.text}>{item.training_system}</Text>
</Text>
</View>
<Text style={styles.text_title}>Lp theo khoa: {' '}
<Text style={styles.text}>{item.class_by_course}</Text>
</Text>
<Text style={styles.text_title}>Khoa: {' '}
<Text style={styles.text}>{item.science}</Text>
<Text style={styles.text_title}>
Khoá: <Text style={styles.text}>{item.course}</Text>
</Text>
<Text style={styles.text_title}>Lp trưởng: {' '}
<Text style={styles.text}>{item.class_leader}</Text>
<View style={styles.sizedBox}></View>
<Text style={styles.text_title}>
H ĐT: <Text style={styles.text}>{item.training_system}</Text>
</Text>
</View>
<Text style={styles.text_title}>
Lp theo khoa: <Text style={styles.text}>{item.class_by_course}</Text>
</Text>
<Text style={styles.text_title}>
Khoa: <Text style={styles.text}>{item.science}</Text>
</Text>
<Text style={styles.text_title}>
Lp trưởng: <Text style={styles.text}>{item.class_leader}</Text>
</Text>
<View style={styles.containerButton}>
<Button
title="Chi tiết"
......@@ -60,23 +55,50 @@ const ClassActivityView = props => {
</View>
);
};
return (
<View style={styles.container}>
<Header title={'Danh sách lớp sinh hoạt'} isBack />
<View style={styles.body}>
<View style={styles.card}>
<TouchableOpacity style={styles.btnCard}>
<Text style={styles.text}>Khoá 2024</Text>
</TouchableOpacity>
const renderItemEmpty = () => {
return (
<View style={styles.containerEmpty}>
<Image source={R.images.icNoData} maxWidth={50} maxHeight={50} />
<Text style={styles.textEmpty}>Không có d liu</Text>
</View>
);
};
const renderList = () => {
return (
<FlatList
data={dataList || []}
renderItem={renderItem}
showsVerticalScrollIndicator={false}
vertical
keyExtractor={(item, index) => `${index}`}
/>
data={dataList || []}
renderItem={renderItem}
showsVerticalScrollIndicator={false}
vertical
keyExtractor={(item, index) => `${index}`}
/>
);
};
const renderHeaderBody = () => {
return (
<View style={styles.card}>
<TouchableOpacity style={styles.btnCard} onPress={() => {}}>
<Text style={[styles.text, styles.textHeader]}>Khoá 2024</Text>
</TouchableOpacity>
</View>
);
};
const renderBody = () => {
return (
<View style={styles.body}>
{renderHeaderBody()}
<View style={styles.containerList}>
{dataList?.length > 0 ? renderList() : renderItemEmpty()}
</View>
</View>
);
};
return (
<View style={styles.container}>
<Header title={'Danh sách lớp sinh hoạt'} isBack />
{renderBody()}
</View>
);
};
......
import { StyleSheet, Text, View } from 'react-native'
import R from '../../../assets/R'
import {StyleSheet, Text, View} from 'react-native';
import R from '../../../assets/R';
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: R.colors.white,
},
back_button: {
position: 'absolute',
top: 20,
left: 15,
},
background_header: {
width: '100%',
height: 178,
},
text_title: {
fontSize: R.fontsize.fontSizeSubTitle,
fontWeight: '600',
fontFamily: R.fonts.fontMedium,
color: R.colors.blue,
},
container_content: {
padding: 15,
},
text_content: {
fontSize: R.fontsize.fontSizeLabel,
fontWeight: '400',
fontFamily: R.fonts.fontRegular,
color: R.colors.black,
},
icon:{
width:20,
height:15,
},
info:{
paddingHorizontal: 15, paddingVertical: 5
}
})
export default styles
\ No newline at end of file
container: {
flex: 1,
backgroundColor: R.colors.white,
},
back_button: {
position: 'absolute',
top: 20,
left: 15,
},
background_header: {
width: '100%',
height: 178,
},
text_title: {
fontSize: R.fontsize.fontSizeSubTitle,
fontWeight: '600',
fontFamily: R.fonts.fontMedium,
color: R.colors.blue,
},
container_content: {
padding: 15,
},
text_content: {
fontSize: R.fontsize.fontSizeLabel,
fontWeight: '400',
fontFamily: R.fonts.fontRegular,
color: R.colors.black,
},
icon: {
width: 20,
height: 15,
},
info: {
paddingHorizontal: 15,
paddingVertical: 5,
},
});
export default styles;
import React from 'react';
import { Text, View, TouchableOpacity, StyleSheet, ImageBackground, Image } from 'react-native';
import {
Text,
View,
TouchableOpacity,
StyleSheet,
ImageBackground,
Image,
} from 'react-native';
import R from '../../../assets/R';
import styles from './style';
import { useNavigation } from '@react-navigation/native';
const DetailClassScheduleView = (props) => {
const { } = props;
import {useNavigation} from '@react-navigation/native';
const DetailClassScheduleView = props => {
const {} = props;
const navigate = useNavigation();
const ArrowLeftIcon = R.images.icBack;
return (
<View
style={styles.container}
>
<ImageBackground
<View style={styles.container}>
<ImageBackground
source={R.images.igBackground}
style={styles.background_header}
>
<TouchableOpacity style={styles.back_button} onPress={() => navigate.goBack()}>
<Image source={ArrowLeftIcon} style= {styles.icon}/>
style={styles.background_header}>
<TouchableOpacity
style={styles.back_button}
onPress={() => navigate.goBack()}>
<Image source={ArrowLeftIcon} style={styles.icon} />
</TouchableOpacity>
</ImageBackground>
<View style={styles.container_content}>
<Text style={styles.text_title}>Lch dy lp IT0032.47.T1</Text>
<Text style={[styles.text_content, {fontWeight:'600', fontFamily:R.fonts.fontMedium}]}>Th 6: 25/07/2025, 07:00 - 09:00</Text>
<Text
style={[
styles.text_content,
{fontWeight: '600', fontFamily: R.fonts.fontMedium},
]}>
Th 6: 25/07/2025, 07:00 - 09:00
</Text>
<View style={[styles.container_content, styles.info]}>
<Text style={[styles.text_content, {fontWeight:'600', fontFamily:R.fonts.fontMedium}]}>V trí:
<Text
style={[
styles.text_content,
{fontWeight: '600', fontFamily: R.fonts.fontMedium},
]}>
V trí:
<Text style={styles.text_content}> Phòng B205</Text>
</Text>
<Text style={[styles.text_content, {fontWeight:'600', fontFamily:R.fonts.fontMedium}]}>Sĩ s:
<Text
style={[
styles.text_content,
{fontWeight: '600', fontFamily: R.fonts.fontMedium},
]}>
Sĩ s:
<Text style={styles.text_content}> 40</Text>
</Text>
<Text style={[styles.text_content, {fontWeight:'600', fontFamily:R.fonts.fontMedium}]}>Lp hc:
<Text
style={[
styles.text_content,
{fontWeight: '600', fontFamily: R.fonts.fontMedium},
]}>
Lp hc:
<Text style={styles.text_content}> C810</Text>
</Text>
<Text style={[styles.text_content, {fontWeight:'600', fontFamily:R.fonts.fontMedium}]}>Hình thc hc:
<Text
style={[
styles.text_content,
{fontWeight: '600', fontFamily: R.fonts.fontMedium},
]}>
Hình thc hc:
<Text style={styles.text_content}> Thc hành</Text>
</Text>
</View>
</View>
</View>
......
......@@ -59,32 +59,50 @@ const Filter3Day = ({navigation}) => {
const mockEvents = createMockEvents();
const formatDateToString = (date) => {
const formatDateToString = date => {
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
return `${year}-${month}-${day}`;
};
const getEventsForDate = (date) => {
const getEventsForDate = date => {
const dateStr = formatDateToString(date);
return mockEvents.filter(event => event.date === dateStr);
};
const getDayName = (date) => {
const days = ['Chủ nhật', 'Thứ 2', 'Thứ 3', 'Thứ 4', 'Thứ 5', 'Thứ 6', 'Thứ 7'];
const getDayName = date => {
const days = [
'Chủ nhật',
'Thứ 2',
'Thứ 3',
'Thứ 4',
'Thứ 5',
'Thứ 6',
'Thứ 7',
];
return days[date.getDay()];
};
const getMonthName = (monthIndex) => {
const getMonthName = monthIndex => {
const months = [
'Tháng 1', 'Tháng 2', 'Tháng 3', 'Tháng 4', 'Tháng 5', 'Tháng 6',
'Tháng 7', 'Tháng 8', 'Tháng 9', 'Tháng 10', 'Tháng 11', 'Tháng 12',
'Tháng 1',
'Tháng 2',
'Tháng 3',
'Tháng 4',
'Tháng 5',
'Tháng 6',
'Tháng 7',
'Tháng 8',
'Tháng 9',
'Tháng 10',
'Tháng 11',
'Tháng 12',
];
return months[monthIndex];
};
const get3DaysDates = (date) => {
const get3DaysDates = date => {
const dates = [];
for (let i = 0; i < 3; i++) {
const dayDate = new Date(date);
......@@ -94,7 +112,7 @@ const Filter3Day = ({navigation}) => {
return dates;
};
const isToday = (date) => {
const isToday = date => {
const today = new Date();
return (
date.getDate() === today.getDate() &&
......@@ -103,7 +121,7 @@ const Filter3Day = ({navigation}) => {
);
};
const handleMonthSelect = (monthIndex) => {
const handleMonthSelect = monthIndex => {
const newDate = new Date(currentDate);
newDate.setMonth(monthIndex);
setCurrentDate(newDate);
......@@ -149,20 +167,20 @@ const Filter3Day = ({navigation}) => {
const calculateEventPosition = (startTime, endTime) => {
const [startHour, startMinute] = startTime.split(':').map(Number);
const [endHour, endMinute] = endTime.split(':').map(Number);
const startTotalMinutes = startHour * 60 + startMinute;
const endTotalMinutes = endHour * 60 + endMinute;
const durationMinutes = endTotalMinutes - startTotalMinutes;
const HOUR_HEIGHT = 80;
const topPosition = (startTotalMinutes / 60) * HOUR_HEIGHT;
const height = (durationMinutes / 60) * HOUR_HEIGHT;
return { topPosition, height };
return {topPosition, height};
};
return (
<Filter3DayView
<Filter3DayView
navigation={navigation}
currentDate={currentDate}
selectedDate={selectedDate}
......
import { StyleSheet, Dimensions } from 'react-native';
import {StyleSheet, Dimensions} from 'react-native';
import R from '../../../assets/R';
const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
const {width: screenWidth, height: screenHeight} = Dimensions.get('window');
const HOUR_HEIGHT = 80;
const DAY_COLUMN_WIDTH = (screenWidth - 70) / 3;
......@@ -71,7 +71,7 @@ const styles = StyleSheet.create({
borderRadius: 15,
alignItems: 'center',
justifyContent: 'center',
marginVertical: 5
marginVertical: 5,
},
todayNumberContainer: {
backgroundColor: R.colors.blue,
......@@ -90,8 +90,7 @@ const styles = StyleSheet.create({
flex: 1,
backgroundColor: R.colors.white,
},
scrollContent: {
},
scrollContent: {},
timelineContainer: {
flexDirection: 'row',
position: 'relative',
......@@ -155,4 +154,4 @@ const styles = StyleSheet.create({
},
});
export default styles;
\ No newline at end of file
export default styles;
......@@ -9,7 +9,7 @@ import {
import R from '../../../assets/R';
import styles from './style';
const Filter3DayView = (props) => {
const Filter3DayView = props => {
const {
currentDate,
showMonthPicker,
......@@ -21,10 +21,9 @@ const Filter3DayView = (props) => {
get3DaysDates,
isToday,
handleMonthSelect,
calculateEventPosition
calculateEventPosition,
} = props;
const renderMonthPicker = () => {
if (!showMonthPicker) return null;
......@@ -45,7 +44,8 @@ const Filter3DayView = (props) => {
<Text
style={[
styles.monthItemText,
currentDate.getMonth() === index && styles.monthItemTextSelected,
currentDate.getMonth() === index &&
styles.monthItemTextSelected,
]}>
{getMonthName(index)}
</Text>
......@@ -64,23 +64,26 @@ const Filter3DayView = (props) => {
<View style={styles.timeColumnHeader} />
{threeDaysDates.map((date, index) => {
const isTodayDate = isToday(date);
return (
<View key={index} style={styles.dayHeaderCell}>
<Text style={[
styles.dayHeaderText,
isTodayDate && styles.todayHeaderText
]}>
<Text
style={[
styles.dayHeaderText,
isTodayDate && styles.todayHeaderText,
]}>
{getDayName(date)}
</Text>
<View style={[
styles.dayNumberContainer,
isTodayDate && styles.todayNumberContainer
]}>
<Text style={[
styles.dayHeaderNumber,
isTodayDate && styles.todayHeaderNumber
<View
style={[
styles.dayNumberContainer,
isTodayDate && styles.todayNumberContainer,
]}>
<Text
style={[
styles.dayHeaderNumber,
isTodayDate && styles.todayHeaderNumber,
]}>
{date.getDate()}
</Text>
</View>
......@@ -92,7 +95,7 @@ const Filter3DayView = (props) => {
};
const renderTimeSlots = () => {
const hours = Array.from({length: 24}, (_, i) => i);
const hours = Array.from({length: 24}, (_, i) => i);
const threeDaysDates = get3DaysDates(currentDate);
return (
......@@ -101,10 +104,9 @@ const Filter3DayView = (props) => {
ref={scrollViewRef}
showsVerticalScrollIndicator={false}
contentContainerStyle={styles.scrollContent}>
<View style={styles.timelineContainer}>
<View style={styles.timeLabelsColumn}>
{hours.map((hour) => {
{hours.map(hour => {
const timeStr = hour.toString().padStart(2, '0') + ':00';
return (
<View key={hour} style={styles.timeSlot}>
......@@ -117,13 +119,16 @@ const Filter3DayView = (props) => {
<View style={styles.daysGridContainer}>
{threeDaysDates.map((date, dayIndex) => (
<View key={dayIndex} style={styles.dayColumn}>
{hours.map((hour) => (
{hours.map(hour => (
<View key={hour} style={styles.gridCell} />
))}
{getEventsForDate(date).map((event) => {
const { topPosition, height } = calculateEventPosition(event.time, event.endTime);
{getEventsForDate(date).map(event => {
const {topPosition, height} = calculateEventPosition(
event.time,
event.endTime,
);
return (
<TouchableOpacity
key={event.id}
......@@ -137,10 +142,12 @@ const Filter3DayView = (props) => {
right: 4,
zIndex: 10,
backgroundColor: R.colors.blue,
}
},
]}
activeOpacity={0.7}>
<Text style={styles.eventTitle} numberOfLines={height > 80 ? 3 : 2}>
<Text
style={styles.eventTitle}
numberOfLines={height > 80 ? 3 : 2}>
{event.title}
</Text>
{height > 50 && (
......@@ -149,7 +156,9 @@ const Filter3DayView = (props) => {
</Text>
)}
<Text style={styles.eventTime}>
Thi gian hc: {event.time} - {event.endTime}, {getDayName(date)} {date.getDate()}/{date.getMonth() + 1}/{date.getFullYear()}
Thi gian hc: {event.time} - {event.endTime},{' '}
{getDayName(date)} {date.getDate()}/
{date.getMonth() + 1}/{date.getFullYear()}
</Text>
</TouchableOpacity>
);
......@@ -172,5 +181,4 @@ const Filter3DayView = (props) => {
);
};
export default Filter3DayView
export default Filter3DayView;
import React, {useState, useRef, useEffect} from 'react';
import {
Dimensions,
DeviceEventEmitter,
PanResponder,
} from 'react-native';
import {Dimensions, DeviceEventEmitter, PanResponder} from 'react-native';
import FilterWeekView from './view';
// ==================== HẰNG SỐ ====================
......@@ -16,10 +12,10 @@ const FilterWeek = ({navigation}) => {
// B1: State ngày tháng và lịch
const [currentDate, setCurrentDate] = useState(new Date());
const [selectedDate, setSelectedDate] = useState(new Date());
// B2: State month picker
const [showMonthPicker, setShowMonthPicker] = useState(false);
// B3: Tham chiếu scroll
const scrollViewRef = useRef(null);
......@@ -30,7 +26,7 @@ const FilterWeek = ({navigation}) => {
// ==================== HÀM TIỆN ÍCH ====================
// T1: Định dạng ngày thành chuỗi
const formatDateToString = (date) => {
const formatDateToString = date => {
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
......@@ -38,7 +34,7 @@ const FilterWeek = ({navigation}) => {
};
// T2: Kiểm tra ngày hôm nay
const isToday = (someDate) => {
const isToday = someDate => {
const today = new Date();
return (
someDate.getDate() === today.getDate() &&
......@@ -48,22 +44,32 @@ const FilterWeek = ({navigation}) => {
};
// T3: Lấy tên ngày trong tuần
const getDayName = (date) => {
const getDayName = date => {
const days = ['CN', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7'];
return days[date.getDay()];
};
// T4: Lấy tên tháng
const getMonthName = (monthIndex) => {
const getMonthName = monthIndex => {
const months = [
'Tháng 1', 'Tháng 2', 'Tháng 3', 'Tháng 4', 'Tháng 5', 'Tháng 6',
'Tháng 7', 'Tháng 8', 'Tháng 9', 'Tháng 10', 'Tháng 11', 'Tháng 12',
'Tháng 1',
'Tháng 2',
'Tháng 3',
'Tháng 4',
'Tháng 5',
'Tháng 6',
'Tháng 7',
'Tháng 8',
'Tháng 9',
'Tháng 10',
'Tháng 11',
'Tháng 12',
];
return months[monthIndex];
};
// T5: Lấy các ngày trong tuần
const getWeekDates = (date) => {
const getWeekDates = date => {
const startOfWeek = new Date(date);
startOfWeek.setDate(date.getDate() - date.getDay());
......@@ -156,7 +162,7 @@ const FilterWeek = ({navigation}) => {
const mockEvents = createMockEvents();
// D3: Hàm truy vấn sự kiện
const getEventsForDate = (date) => {
const getEventsForDate = date => {
const dateStr = formatDateToString(date);
return mockEvents.filter(event => event.date === dateStr);
};
......@@ -179,7 +185,7 @@ const FilterWeek = ({navigation}) => {
// ==================== XỬ LÝ SỰ KIỆN ====================
// X1: Xử lý chọn tháng
const handleMonthSelect = (monthIndex) => {
const handleMonthSelect = monthIndex => {
const newDate = new Date(currentDate);
newDate.setMonth(monthIndex);
setCurrentDate(newDate);
......
......@@ -57,14 +57,14 @@ const styles = StyleSheet.create({
color: R.colors.black,
fontWeight: '600',
},
dayHeaderNumberContainerToday: {
borderRadius: 15,
borderRadius: 15,
justifyContent: 'center',
alignItems: 'center',
},
dayHeaderNumberToday: {
color: R.colors.white,
color: R.colors.white,
fontFamily: R.fonts.fontMedium,
fontSize: R.fontsize.fontSizeContent,
fontWeight: '600',
......@@ -154,4 +154,4 @@ const styles = StyleSheet.create({
},
});
export default styles;
\ No newline at end of file
export default styles;
import React from 'react';
import {
View,
Text,
TouchableOpacity,
ScrollView,
FlatList,
} from 'react-native';
import {View, Text, TouchableOpacity, ScrollView, FlatList} from 'react-native';
import R from '../../../assets/R';
import styles from './style';
......@@ -22,7 +16,6 @@ const FilterWeekView = ({
calculateEventPosition,
handleMonthSelect,
}) => {
const renderMonthPicker = () => {
if (!showMonthPicker) return null;
......@@ -32,7 +25,7 @@ const FilterWeekView = ({
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={styles.monthPickerContent}>
{Array.from({ length: 12 }, (_, index) => (
{Array.from({length: 12}, (_, index) => (
<TouchableOpacity
key={index}
style={[
......@@ -43,7 +36,8 @@ const FilterWeekView = ({
<Text
style={[
styles.monthItemText,
currentDate.getMonth() === index && styles.monthItemTextSelected,
currentDate.getMonth() === index &&
styles.monthItemTextSelected,
]}>
{getMonthName(index)}
</Text>
......@@ -65,18 +59,23 @@ const FilterWeekView = ({
return (
<View key={index} style={styles.dayHeaderCell}>
<Text style={[
styles.dayHeaderText,
isCurrentDay && styles.dayHeaderTextToday
]}>
<Text
style={[
styles.dayHeaderText,
isCurrentDay && styles.dayHeaderTextToday,
]}>
{getDayName(date)}
</Text>
<View style={isCurrentDay ? styles.dayHeaderNumberContainerToday : {}}>
<Text style={[
styles.dayHeaderNumber,
isCurrentDay && styles.dayHeaderNumberToday
]}>
<View
style={
isCurrentDay ? styles.dayHeaderNumberContainerToday : {}
}>
<Text
style={[
styles.dayHeaderNumber,
isCurrentDay && styles.dayHeaderNumberToday,
]}>
{date.getDate()}
</Text>
</View>
......@@ -88,7 +87,7 @@ const FilterWeekView = ({
};
const renderTimeSlots = () => {
const hours = Array.from({ length: 24 }, (_, i) => i);
const hours = Array.from({length: 24}, (_, i) => i);
const weekDates = getWeekDates(currentDate);
return (
......@@ -97,10 +96,9 @@ const FilterWeekView = ({
ref={scrollViewRef}
showsVerticalScrollIndicator={false}
contentContainerStyle={styles.scrollContent}>
<View style={styles.timelineContainer}>
<View style={styles.timeLabelsColumn}>
{hours.map((hour) => {
{hours.map(hour => {
const timeStr = hour.toString().padStart(2, '0') + ':00';
return (
<View key={hour} style={styles.timeSlot}>
......@@ -113,12 +111,15 @@ const FilterWeekView = ({
<View style={styles.weekGridContainer}>
{weekDates.map((date, dayIndex) => (
<View key={dayIndex} style={styles.dayColumn}>
{hours.map((hour) => (
{hours.map(hour => (
<View key={hour} style={styles.gridCell} />
))}
{getEventsForDate(date).map((event) => {
const { topPosition, height } = calculateEventPosition(event.time, event.endTime);
{getEventsForDate(date).map(event => {
const {topPosition, height} = calculateEventPosition(
event.time,
event.endTime,
);
return (
<TouchableOpacity
......@@ -133,10 +134,12 @@ const FilterWeekView = ({
right: 2,
zIndex: 10,
backgroundColor: R.colors.blue,
}
},
]}
activeOpacity={0.7}>
<Text style={styles.eventTitle} numberOfLines={height > 60 ? 2 : 1}>
<Text
style={styles.eventTitle}
numberOfLines={height > 60 ? 2 : 1}>
{event.title}
</Text>
{height > 40 && (
......@@ -168,5 +171,4 @@ const FilterWeekView = ({
);
};
export default FilterWeekView;
\ No newline at end of file
export default FilterWeekView;
......@@ -12,7 +12,7 @@ const FilterDay = ({navigation}) => {
DeviceEventEmitter.emit('onDateChange', selectedDate);
}, [selectedDate]);
const createMockEvents = () => {
const createMockEvents = () => {
return [
{
id: '1',
......@@ -46,32 +46,42 @@ const FilterDay = ({navigation}) => {
const mockEvents = createMockEvents();
const formatDateToString = (date) => {
const formatDateToString = date => {
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
return `${year}-${month}-${day}`;
};
const getEventsForDate = (date) => {
const getEventsForDate = date => {
const dateStr = formatDateToString(date);
return mockEvents.filter(event => event.date === dateStr);
};
const getDayName = (date) => {
const getDayName = date => {
const days = ['CN', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7'];
return days[date.getDay()];
};
const getMonthName = (monthIndex) => {
const getMonthName = monthIndex => {
const months = [
'Tháng 1', 'Tháng 2', 'Tháng 3', 'Tháng 4', 'Tháng 5', 'Tháng 6',
'Tháng 7', 'Tháng 8', 'Tháng 9', 'Tháng 10', 'Tháng 11', 'Tháng 12',
'Tháng 1',
'Tháng 2',
'Tháng 3',
'Tháng 4',
'Tháng 5',
'Tháng 6',
'Tháng 7',
'Tháng 8',
'Tháng 9',
'Tháng 10',
'Tháng 11',
'Tháng 12',
];
return months[monthIndex];
};
const handleMonthSelect = (monthIndex) => {
const handleMonthSelect = monthIndex => {
const newDate = new Date(currentDate);
newDate.setMonth(monthIndex);
setCurrentDate(newDate);
......@@ -117,33 +127,32 @@ const FilterDay = ({navigation}) => {
const calculateEventPosition = (startTime, endTime) => {
const [startHour, startMinute] = startTime.split(':').map(Number);
const [endHour, endMinute] = endTime.split(':').map(Number);
const startTotalMinutes = startHour * 60 + startMinute;
const endTotalMinutes = endHour * 60 + endMinute;
const durationMinutes = endTotalMinutes - startTotalMinutes;
const HOUR_HEIGHT = 80;
const topPosition = (startTotalMinutes / 60) * HOUR_HEIGHT;
const height = (durationMinutes / 60) * HOUR_HEIGHT;
return { topPosition, height };
return {topPosition, height};
};
return (
<FilterDayView
navigation={navigation}
currentDate={currentDate}
selectedDate={selectedDate}
showMonthPicker={showMonthPicker}
scrollViewRef={scrollViewRef}
panResponder={panResponder}
getEventsForDate={getEventsForDate}
getDayName={getDayName}
getMonthName={getMonthName}
handleMonthSelect={handleMonthSelect}
toggleMonthPicker={toggleMonthPicker}
calculateEventPosition={calculateEventPosition}
<FilterDayView
navigation={navigation}
currentDate={currentDate}
selectedDate={selectedDate}
showMonthPicker={showMonthPicker}
scrollViewRef={scrollViewRef}
panResponder={panResponder}
getEventsForDate={getEventsForDate}
getDayName={getDayName}
getMonthName={getMonthName}
handleMonthSelect={handleMonthSelect}
toggleMonthPicker={toggleMonthPicker}
calculateEventPosition={calculateEventPosition}
/>
);
};
......
......@@ -29,10 +29,10 @@ const styles = StyleSheet.create({
paddingHorizontal: 15,
paddingVertical: 12,
alignItems: 'center',
justifyContent:'center',
maxWidth:70,
borderRightWidth:1,
borderRightColor:R.colors.gray,
justifyContent: 'center',
maxWidth: 70,
borderRightWidth: 1,
borderRightColor: R.colors.gray,
},
dayName: {
fontSize: R.fontsize.fontSizeLabel,
......@@ -124,4 +124,4 @@ const styles = StyleSheet.create({
},
});
export default styles;
\ No newline at end of file
export default styles;
import React from 'react';
import {
View,
Text,
TouchableOpacity,
ScrollView,
} from 'react-native';
import {View, Text, TouchableOpacity, ScrollView} from 'react-native';
import R from '../../../assets/R';
import styles from './style';
const FilterDayView = (props) => {
const {
const FilterDayView = props => {
const {
selectedDate,
showMonthPicker,
scrollViewRef,
panResponder,
getEventsForDate,
getDayName,
calculateEventPosition, } = props;
calculateEventPosition,
} = props;
const isToday = (date) => {
const today = new Date();
return (
date.getDate() === today.getDate() &&
date.getMonth() === today.getMonth() &&
date.getFullYear() === today.getFullYear()
);
};
const renderMonthPicker = () => {
if (!showMonthPicker) return null;
}
const isToday = date => {
const today = new Date();
return (
date.getDate() === today.getDate() &&
date.getMonth() === today.getMonth() &&
date.getFullYear() === today.getFullYear()
);
};
const renderMonthPicker = () => {
if (!showMonthPicker) return null;
};
const renderDateInfo = () => {
return (
<View style={{backgroundColor: R.colors.grayBorderInputTextHeader}}>
<View style={styles.dateInfoContainer}>
const renderDateInfo = () => {
return (
<View style={{backgroundColor: R.colors.grayBorderInputTextHeader}}>
<View style={styles.dateInfoContainer}>
<Text style={styles.dayName}>{getDayName(selectedDate)}</Text>
<Text style={
isToday(selectedDate)
? styles.dayNumberToday
: styles.dayNumber
}>{selectedDate.getDate()}</Text>
</View>
<Text
style={
isToday(selectedDate) ? styles.dayNumberToday : styles.dayNumber
}>
{selectedDate.getDate()}
</Text>
</View>
);
};
const renderTimeSlots = () => {
const hours = Array.from({length: 24}, (_, i) => i);
const selectedEvents = getEventsForDate(selectedDate);
return (
<View style={styles.timeSlotsContainer} {...panResponder.panHandlers}>
<ScrollView
ref={scrollViewRef}
showsVerticalScrollIndicator={false}
contentContainerStyle={styles.scrollContent}>
<View style={styles.timelineContainer}>
<View style={styles.timeLabelsColumn}>
{hours.map((hour) => {
const timeStr = hour.toString().padStart(2, '0') + ':00';
return (
<View key={hour} style={styles.timeSlot}>
<Text style={styles.timeText}>{timeStr}</Text>
</View>
);
})}
</View>
<View style={styles.eventsColumn}>
{hours.map((hour) => (
<View key={hour} style={styles.gridLine} />
))}
{selectedEvents.map((event) => {
const { topPosition, height } = calculateEventPosition(event.time, event.endTime);
return (
<TouchableOpacity
key={event.id}
style={[
styles.eventCard,
{
position: 'absolute',
top: topPosition,
height: Math.max(height, 40),
left: 5,
right: 15,
zIndex: 10,
backgroundColor: R.colors.blue,
}
]}
activeOpacity={0.7}>
<Text style={styles.eventTitle} numberOfLines={height > 60 ? 2 : 1}>
{event.title}
</Text>
{height > 40 && (
<Text style={styles.eventSubtitle} numberOfLines={1}>
{event.subtitle}
</Text>
)}
<Text style={styles.eventTime}>
{event.time} - {event.endTime}
</View>
);
};
const renderTimeSlots = () => {
const hours = Array.from({length: 24}, (_, i) => i);
const selectedEvents = getEventsForDate(selectedDate);
return (
<View style={styles.timeSlotsContainer} {...panResponder.panHandlers}>
<ScrollView
ref={scrollViewRef}
showsVerticalScrollIndicator={false}
contentContainerStyle={styles.scrollContent}>
<View style={styles.timelineContainer}>
<View style={styles.timeLabelsColumn}>
{hours.map(hour => {
const timeStr = hour.toString().padStart(2, '0') + ':00';
return (
<View key={hour} style={styles.timeSlot}>
<Text style={styles.timeText}>{timeStr}</Text>
</View>
);
})}
</View>
<View style={styles.eventsColumn}>
{hours.map(hour => (
<View key={hour} style={styles.gridLine} />
))}
{selectedEvents.map(event => {
const {topPosition, height} = calculateEventPosition(
event.time,
event.endTime,
);
return (
<TouchableOpacity
key={event.id}
style={[
styles.eventCard,
{
position: 'absolute',
top: topPosition,
height: Math.max(height, 40),
left: 5,
right: 15,
zIndex: 10,
backgroundColor: R.colors.blue,
},
]}
activeOpacity={0.7}>
<Text
style={styles.eventTitle}
numberOfLines={height > 60 ? 2 : 1}>
{event.title}
</Text>
{height > 40 && (
<Text style={styles.eventSubtitle} numberOfLines={1}>
{event.subtitle}
</Text>
</TouchableOpacity>
);
})}
</View>
)}
<Text style={styles.eventTime}>
{event.time} - {event.endTime}
</Text>
</TouchableOpacity>
);
})}
</View>
</ScrollView>
</View>
);
};
</View>
</ScrollView>
</View>
);
};
return (
<View style={styles.container}>
{renderMonthPicker()}
<View style={styles.container}>
{renderMonthPicker()}
{renderDateInfo()}
{renderTimeSlots()}
</View>
</View>
);
};
......
......@@ -11,16 +11,18 @@ const ClassSchedule = ({events = [], onDateSelect, onEventPress}) => {
// B1: State ngày tháng và lịch
const [currentDate, setCurrentDate] = useState(new Date());
const [selectedDate, setSelectedDate] = useState(null);
// B2: State bottom sheet
const [showBottomSheet, setShowBottomSheet] = useState(false);
// B3: Tham chiếu animation
const bottomSheetTranslateY = useRef(new Animated.Value(BOTTOM_SHEET_HEIGHT)).current;
const bottomSheetTranslateY = useRef(
new Animated.Value(BOTTOM_SHEET_HEIGHT),
).current;
// ==================== HÀM TIỆN ÍCH ====================
// T1: Định dạng ngày thành chuỗi
const formatDateToString = (date) => {
const formatDateToString = date => {
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
......@@ -28,7 +30,7 @@ const ClassSchedule = ({events = [], onDateSelect, onEventPress}) => {
};
// T2: Định dạng ngày để hiển thị
const formatDateToDisplay = (date) => {
const formatDateToDisplay = date => {
const day = date.getDate().toString().padStart(2, '0');
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const year = date.getFullYear();
......@@ -36,7 +38,7 @@ const ClassSchedule = ({events = [], onDateSelect, onEventPress}) => {
};
// T3: Chuyển đổi chuỗi thành ngày
const parseLocalDate = (dateString) => {
const parseLocalDate = dateString => {
const [year, month, day] = dateString.split('-').map(Number);
return new Date(year, month - 1, day);
};
......@@ -176,7 +178,7 @@ const ClassSchedule = ({events = [], onDateSelect, onEventPress}) => {
const allEvents = [...events, ...mockEvents];
// D3: Hàm truy vấn sự kiện
const getEventsForDate = (date) => {
const getEventsForDate = date => {
const dateStr = formatDateToString(date);
return allEvents.filter(event => event.date === dateStr);
};
......@@ -216,11 +218,11 @@ const ClassSchedule = ({events = [], onDateSelect, onEventPress}) => {
}, [currentDate]);
// L2: Hàm kiểm tra ngày tháng
const isCurrentMonth = (date) => {
const isCurrentMonth = date => {
return date.getMonth() === currentDate.getMonth();
};
const isToday = (date) => {
const isToday = date => {
const today = new Date();
return (
date.getDate() === today.getDate() &&
......@@ -251,7 +253,7 @@ const ClassSchedule = ({events = [], onDateSelect, onEventPress}) => {
}).start();
}
},
})
}),
).current;
// A2: Hàm animation Bottom Sheet
......@@ -277,7 +279,7 @@ const ClassSchedule = ({events = [], onDateSelect, onEventPress}) => {
// ==================== XỬ LÝ SỰ KIỆN ====================
// X1: Xử lý điều hướng
const navigateMonth = (direction) => {
const navigateMonth = direction => {
const newDate = new Date(currentDate);
if (direction === 'prev') {
newDate.setMonth(newDate.getMonth() - 1);
......@@ -292,10 +294,10 @@ const ClassSchedule = ({events = [], onDateSelect, onEventPress}) => {
};
// X2: Xử lý chọn ngày
const handleDatePress = (date) => {
const handleDatePress = date => {
const dateStr = formatDateToString(date);
const dayEvents = getEventsForDate(date);
setSelectedDate(dateStr);
onDateSelect?.(dateStr);
......@@ -305,7 +307,7 @@ const ClassSchedule = ({events = [], onDateSelect, onEventPress}) => {
};
// X3: Xử lý tương tác sự kiện
const handleEventPress = (event) => {
const handleEventPress = event => {
onEventPress?.(event);
};
......@@ -336,4 +338,4 @@ const ClassSchedule = ({events = [], onDateSelect, onEventPress}) => {
);
};
export default ClassSchedule;
\ No newline at end of file
export default ClassSchedule;
......@@ -119,9 +119,9 @@ const styles = StyleSheet.create({
fontFamily: R.fonts.fontRegular,
textAlign: 'center',
},
containerBottomSheet:{
flex:1,
marginBottom:10,
containerBottomSheet: {
flex: 1,
marginBottom: 10,
},
modalBackdrop: {
......@@ -137,7 +137,6 @@ const styles = StyleSheet.create({
},
bottomSheetContent: {
height: BOTTOM_SHEET_HEIGHT,
},
dragHandle: {
width: 40,
......@@ -176,7 +175,7 @@ const styles = StyleSheet.create({
fontWeight: '400',
},
eventsScrollView: {
paddingTop:10,
paddingTop: 10,
},
noEventsContainer: {
flex: 1,
......@@ -196,7 +195,7 @@ const styles = StyleSheet.create({
borderRadius: 12,
padding: 15,
marginBottom: 10,
marginHorizontal:15,
marginHorizontal: 15,
borderLeftWidth: 4,
borderLeftColor: R.colors.blue500,
shadowColor: R.colors.black,
......
......@@ -11,8 +11,8 @@ import {
SafeAreaView,
} from 'react-native';
import R from '../../assets/R';
import { styles, CELL_WIDTH, BOTTOM_SHEET_HEIGHT } from './style';
import { useNavigation } from '@react-navigation/native';
import {styles, CELL_WIDTH, BOTTOM_SHEET_HEIGHT} from './style';
import {useNavigation} from '@react-navigation/native';
import * as SCREENNAME from '../../routers/ScreenNames';
const ClassScheduleView = ({
......@@ -37,8 +37,18 @@ const ClassScheduleView = ({
const navigation = useNavigation();
const renderHeader = () => {
const monthNames = [
'Tháng 1', 'Tháng 2', 'Tháng 3', 'Tháng 4', 'Tháng 5', 'Tháng 6',
'Tháng 7', 'Tháng 8', 'Tháng 9', 'Tháng 10', 'Tháng 11', 'Tháng 12',
'Tháng 1',
'Tháng 2',
'Tháng 3',
'Tháng 4',
'Tháng 5',
'Tháng 6',
'Tháng 7',
'Tháng 8',
'Tháng 9',
'Tháng 10',
'Tháng 11',
'Tháng 12',
];
return (
......@@ -70,7 +80,7 @@ const ClassScheduleView = ({
{weekDays.map((day, index) => (
<View key={index} style={styles.weekDayCell}>
<Text style={styles.weekDayText}>{day}</Text>
</View>
</View>
))}
</View>
);
......@@ -93,7 +103,6 @@ const ClassScheduleView = ({
]}
onPress={() => handleDatePress(date)}
activeOpacity={0.7}>
<Text
style={[
styles.dayText,
......@@ -109,9 +118,7 @@ const ClassScheduleView = ({
{dayEvents.slice(0, 2).map((event, eventIndex) => (
<TouchableOpacity
key={event.id}
style={[
styles.eventBar,
]}
style={[styles.eventBar]}
onPress={() => handleEventPress(event)}>
<Text style={styles.eventBarText} numberOfLines={1}>
{event.title}
......@@ -150,9 +157,7 @@ const ClassScheduleView = ({
return (
<View style={styles.bottomSheetContent}>
<View style={styles.dragHandle} >
</View>
<View style={styles.dragHandle}></View>
<View style={styles.bottomSheetHeader}>
<Text style={styles.bottomSheetTitle}>
......@@ -171,34 +176,35 @@ const ClassScheduleView = ({
<View style={styles.noEventsContainer}>
<Text style={styles.noEventsText}>Không có s kin nào</Text>
</View>
) :
(selectedEvents.map((event, index) => (
<View style={styles.containerBottomSheet}>
<TouchableOpacity
key={event.id}
style={styles.eventCard}
onPress={() => navigation.navigate(SCREENNAME.DETAILSCHEDULE, { event })}
activeOpacity={0.7}>
<View style={styles.eventTimeContainer}>
<Text style={styles.eventTime}>
{event.time}
{event.endTime && ` - ${event.endTime}`}
</Text>
</View>
) : (
selectedEvents.map((event, index) => (
<View style={styles.containerBottomSheet}>
<TouchableOpacity
key={event.id}
style={styles.eventCard}
onPress={() =>
navigation.navigate(SCREENNAME.DETAILSCHEDULE, {event})
}
activeOpacity={0.7}>
<View style={styles.eventTimeContainer}>
<Text style={styles.eventTime}>
{event.time}
{event.endTime && ` - ${event.endTime}`}
</Text>
</View>
<View style={styles.eventContent}>
<Text style={styles.eventTitle} numberOfLines={2}>
{event.title}
</Text>
{event.description && (
<Text style={styles.eventDescription} numberOfLines={3}>
{event.description}
<View style={styles.eventContent}>
<Text style={styles.eventTitle} numberOfLines={2}>
{event.title}
</Text>
)}
</View>
</TouchableOpacity>
</View>
{event.description && (
<Text style={styles.eventDescription} numberOfLines={3}>
{event.description}
</Text>
)}
</View>
</TouchableOpacity>
</View>
))
)}
</ScrollView>
......@@ -213,21 +219,19 @@ const ClassScheduleView = ({
transparent={true}
animationType="none"
onRequestClose={handleCloseBottomSheet}>
<TouchableOpacity
style={styles.modalBackdrop}
activeOpacity={1}
onPress={handleCloseBottomSheet}>
<Animated.View
style={[
styles.bottomSheet,
{
transform: [{ translateY: bottomSheetTranslateY }],
transform: [{translateY: bottomSheetTranslateY}],
},
]}
{...panResponder.panHandlers}>
<TouchableOpacity activeOpacity={1} >
<TouchableOpacity activeOpacity={1}>
{renderBottomSheetContent()}
</TouchableOpacity>
</Animated.View>
......@@ -237,7 +241,6 @@ const ClassScheduleView = ({
};
return (
<View style={styles.container}>
<ScrollView showsVerticalScrollIndicator={false}>
<View style={styles.body}>
......@@ -251,6 +254,4 @@ const ClassScheduleView = ({
);
};
export default ClassScheduleView;
\ No newline at end of file
export default ClassScheduleView;
import React, { useState } from 'react';
import React, {useState} from 'react';
import {Text, View, StyleSheet} from 'react-native';
import CompensateView from './view';
const Compensate = (props) => {
const [dataList, setDataList] = useState([
{id: 1, classCode: 'ATTT2024.1', rest: 5, compensate: 0, total: 25},
{id: 2, classCode: 'ATTT2024.2', rest: 4, compensate: 1, total: 25},
{id: 3, classCode: 'ATTT2024.3', rest: 6, compensate: 0, total: 25},
{id: 4, classCode: 'ATTT2024.4', rest: 3, compensate: 2, total: 25},
{id: 5, classCode: 'ATTT2024.5', rest: 5, compensate: 0, total: 25},
{id: 6, classCode: 'CNTT2024.1', rest: 2, compensate: 1, total: 25},
{id: 7, classCode: 'CNTT2024.2', rest: 4, compensate: 0, total: 25},
{id: 8, classCode: 'CNTT2024.3', rest: 5, compensate: 0, total: 25},
{id: 9, classCode: 'CNTT2024.4', rest: 3, compensate: 1, total: 25},
{id: 10, classCode: 'CNTT2024.5', rest: 6, compensate: 0, total: 25},
{id: 11, classCode: 'KTPM2024.1', rest: 4, compensate: 1, total: 25},
{id: 12, classCode: 'KTPM2024.2', rest: 2, compensate: 2, total: 25},
{id: 13, classCode: 'KTPM2024.3', rest: 5, compensate: 0, total: 25},
{id: 14, classCode: 'KTPM2024.4', rest: 4, compensate: 0, total: 25},
{id: 15, classCode: 'KTPM2024.5', rest: 3, compensate: 1, total: 25},
{id: 16, classCode: 'HTTT2024.1', rest: 5, compensate: 0, total: 25},
{id: 17, classCode: 'HTTT2024.2', rest: 6, compensate: 0, total: 25},
{id: 18, classCode: 'HTTT2024.3', rest: 3, compensate: 2, total: 25},
{id: 19, classCode: 'HTTT2024.4', rest: 4, compensate: 1, total: 25},
{id: 20, classCode: 'HTTT2024.5', rest: 5, compensate: 0, total: 25},
{id: 21, classCode: 'KHMT2024.1', rest: 4, compensate: 0, total: 25},
{id: 22, classCode: 'KHMT2024.2', rest: 5, compensate: 1, total: 25},
{id: 23, classCode: 'KHMT2024.3', rest: 6, compensate: 0, total: 25},
{id: 24, classCode: 'KHMT2024.4', rest: 3, compensate: 1, total: 25},
{id: 25, classCode: 'KHMT2024.5', rest: 5, compensate: 0, total: 25},
{id: 26, classCode: 'MMT2024.1', rest: 4, compensate: 1, total: 25},
{id: 27, classCode: 'MMT2024.2', rest: 2, compensate: 0, total: 25},
{id: 28, classCode: 'MMT2024.3', rest: 5, compensate: 0, total: 25},
{id: 29, classCode: 'MMT2024.4', rest: 3, compensate: 2, total: 25},
{id: 30, classCode: 'MMT2024.5', rest: 6, compensate: 0, total: 25},
]);
return (
<CompensateView dataList={dataList} />
);
const Compensate = props => {
const [dataList, setDataList] = useState([
{id: 1, classCode: 'ATTT2024.1', rest: 5, compensate: 0, total: 25},
{id: 2, classCode: 'ATTT2024.2', rest: 4, compensate: 1, total: 25},
{id: 3, classCode: 'ATTT2024.3', rest: 6, compensate: 0, total: 25},
{id: 4, classCode: 'ATTT2024.4', rest: 3, compensate: 2, total: 25},
{id: 5, classCode: 'ATTT2024.5', rest: 5, compensate: 0, total: 25},
{id: 6, classCode: 'CNTT2024.1', rest: 2, compensate: 1, total: 25},
{id: 7, classCode: 'CNTT2024.2', rest: 4, compensate: 0, total: 25},
{id: 8, classCode: 'CNTT2024.3', rest: 5, compensate: 0, total: 25},
{id: 9, classCode: 'CNTT2024.4', rest: 3, compensate: 1, total: 25},
{id: 10, classCode: 'CNTT2024.5', rest: 6, compensate: 0, total: 25},
{id: 11, classCode: 'KTPM2024.1', rest: 4, compensate: 1, total: 25},
{id: 12, classCode: 'KTPM2024.2', rest: 2, compensate: 2, total: 25},
{id: 13, classCode: 'KTPM2024.3', rest: 5, compensate: 0, total: 25},
{id: 14, classCode: 'KTPM2024.4', rest: 4, compensate: 0, total: 25},
{id: 15, classCode: 'KTPM2024.5', rest: 3, compensate: 1, total: 25},
{id: 16, classCode: 'HTTT2024.1', rest: 5, compensate: 0, total: 25},
{id: 17, classCode: 'HTTT2024.2', rest: 6, compensate: 0, total: 25},
{id: 18, classCode: 'HTTT2024.3', rest: 3, compensate: 2, total: 25},
{id: 19, classCode: 'HTTT2024.4', rest: 4, compensate: 1, total: 25},
{id: 20, classCode: 'HTTT2024.5', rest: 5, compensate: 0, total: 25},
{id: 21, classCode: 'KHMT2024.1', rest: 4, compensate: 0, total: 25},
{id: 22, classCode: 'KHMT2024.2', rest: 5, compensate: 1, total: 25},
{id: 23, classCode: 'KHMT2024.3', rest: 6, compensate: 0, total: 25},
{id: 24, classCode: 'KHMT2024.4', rest: 3, compensate: 1, total: 25},
{id: 25, classCode: 'KHMT2024.5', rest: 5, compensate: 0, total: 25},
{id: 26, classCode: 'MMT2024.1', rest: 4, compensate: 1, total: 25},
{id: 27, classCode: 'MMT2024.2', rest: 2, compensate: 0, total: 25},
{id: 28, classCode: 'MMT2024.3', rest: 5, compensate: 0, total: 25},
{id: 29, classCode: 'MMT2024.4', rest: 3, compensate: 2, total: 25},
{id: 30, classCode: 'MMT2024.5', rest: 6, compensate: 0, total: 25},
]);
return <CompensateView dataList={dataList} />;
};
export default Compensate;
import React, { useState } from 'react';
import React, {useState} from 'react';
import {Text, View, StyleSheet} from 'react-native';
import DetailCompensateView from './view';
const DetailCompensate = (props) => {
const [item, setItem] = useState({
rest: 5,
compensate: 0,
total: 25,
});
const [itemDetail, setItemDetail] = useState({
rest: 5,
compensate: 0,
total: 25,
});
const [listData, setDataList] = useState([
{
id:1,
date:'2024-01-01',
status:'Đã xác nhận',
dayOfWeek:'Thứ 2',
periods:[
{
id:1,
time:'6',
},
{
id:2,
time:'7',
},
{
id:3,
time:'8',
},
{
id:4,
time:'9',
}
],
dateStudy:'30/07/2025',
location:'Phòng B2.12',
teacher:'Nguyễn Minh Đức',
note:'',
},
{
id:2,
date:'2024-01-01',
status:'Chờ phê duyệt',
dayOfWeek:'Thứ 2',
periods:[
{
id:1,
time:'6',
},
{
id:2,
time:'7',
},
{
id:3,
time:'8',
},
{
id:4,
time:'9',
}
],
dateStudy:'30/07/2025',
location:'Phòng B2.12',
teacher:'',
note:'',
},
{
id:3,
date:'2024-01-01',
status:'Từ chối',
dayOfWeek:'Thứ 2',
periods:[
{
id:1,
time:'6',
},
{
id:2,
time:'7',
},
{
id:3,
time:'8',
},
{
id:4,
time:'9',
}
],
dateStudy:'30/07/2025',
location:'Phòng B2.12',
teacher:'',
note:'',
},
{
id:4,
date:'2024-01-01',
status:'Đã xác nhận',
dayOfWeek:'Thứ 2',
periods:[
{
id:1,
time:'6',
},
{
id:2,
time:'7',
},
{
id:3,
time:'8',
},
{
id:4,
time:'9',
}
],
dateStudy:'30/07/2025',
location:'Phòng B2.12',
teacher:'',
note:'',
},
{
id:5,
date:'2024-01-01',
status:'Đã xác nhận',
dayOfWeek:'Thứ 2',
periods:[
{
id:1,
time:'6',
},
{
id:2,
time:'7',
},
{
id:3,
time:'8',
},
{
id:4,
time:'9',
}
],
dateStudy:'30/07/2025',
location:'Phòng B2.12',
teacher:'',
note:'',
},
])
const DetailCompensate = props => {
const [item, setItem] = useState({
rest: 5,
compensate: 0,
total: 25,
});
const [itemDetail, setItemDetail] = useState({
rest: 5,
compensate: 0,
total: 25,
});
const [listData, setDataList] = useState([
{
id: 1,
date: '2024-01-01',
status: 'Đã xác nhận',
dayOfWeek: 'Thứ 2',
periods: [
{
id: 1,
time: '6',
},
{
id: 2,
time: '7',
},
{
id: 3,
time: '8',
},
{
id: 4,
time: '9',
},
],
dateStudy: '30/07/2025',
location: 'Phòng B2.12',
teacher: 'Nguyễn Minh Đức',
note: '',
},
{
id: 2,
date: '2024-01-01',
status: 'Chờ phê duyệt',
dayOfWeek: 'Thứ 2',
periods: [
{
id: 1,
time: '6',
},
{
id: 2,
time: '7',
},
{
id: 3,
time: '8',
},
{
id: 4,
time: '9',
},
],
dateStudy: '30/07/2025',
location: 'Phòng B2.12',
teacher: '',
note: '',
},
{
id: 3,
date: '2024-01-01',
status: 'Từ chối',
dayOfWeek: 'Thứ 2',
periods: [
{
id: 1,
time: '6',
},
{
id: 2,
time: '7',
},
{
id: 3,
time: '8',
},
{
id: 4,
time: '9',
},
],
dateStudy: '30/07/2025',
location: 'Phòng B2.12',
teacher: '',
note: '',
},
{
id: 4,
date: '2024-01-01',
status: 'Đã xác nhận',
dayOfWeek: 'Thứ 2',
periods: [
{
id: 1,
time: '6',
},
{
id: 2,
time: '7',
},
{
id: 3,
time: '8',
},
{
id: 4,
time: '9',
},
],
dateStudy: '30/07/2025',
location: 'Phòng B2.12',
teacher: '',
note: '',
},
{
id: 5,
date: '2024-01-01',
status: 'Đã xác nhận',
dayOfWeek: 'Thứ 2',
periods: [
{
id: 1,
time: '6',
},
{
id: 2,
time: '7',
},
{
id: 3,
time: '8',
},
{
id: 4,
time: '9',
},
],
dateStudy: '30/07/2025',
location: 'Phòng B2.12',
teacher: '',
note: '',
},
]);
return (
<DetailCompensateView item={item} listData={listData} itemDetail={itemDetail}/>
<DetailCompensateView
item={item}
listData={listData}
itemDetail={itemDetail}
/>
);
};
......
import { StyleSheet, Text, View } from 'react-native'
import {StyleSheet, Text, View} from 'react-native';
import R from '../../../assets/R';
const styles = StyleSheet.create({
container:{
flex:1,
backgroundColor:R.colors.white
},
body:{
flex:1,
backgroundColor:R.colors.white
},
text:{
fontSize:R.fontsize.fontSizeSubTitle,
fontFamily:R.fonts.fontRegular,
fontWeight:'400',
color:R.colors.black,
},
card:{
borderRadius:10,
marginVertical:10,
backgroundColor:R.colors.white,
shadowColor:R.colors.black,
shadowOffset:{width:0,height:2},
shadowOpacity:Platform.OS === 'ios' ? 0.25 : 1,
shadowRadius:5,
elevation:Platform.OS === 'ios' ? 1 : 2,
marginHorizontal:15,
}
})
container: {
flex: 1,
backgroundColor: R.colors.white,
},
body: {
flex: 1,
backgroundColor: R.colors.white,
},
text: {
fontSize: R.fontsize.fontSizeSubTitle,
fontFamily: R.fonts.fontRegular,
fontWeight: '400',
color: R.colors.black,
},
card: {
borderRadius: 10,
export default styles;
\ No newline at end of file
marginVertical: 10,
backgroundColor: R.colors.white,
shadowColor: R.colors.black,
shadowOffset: {width: 0, height: 2},
shadowOpacity: Platform.OS === 'ios' ? 0.25 : 1,
shadowRadius: 5,
elevation: Platform.OS === 'ios' ? 1 : 2,
marginHorizontal: 15,
},
});
export default styles;
......@@ -4,7 +4,7 @@ import styles from './style';
import Header from '../../../components/Header/Header';
import R from '../../../assets/R';
import Button from '../../../components/Button';
const DetailCompensateView = (props) => {
const DetailCompensateView = props => {
const {item, listData, itemDetail} = props;
const getColor = status => {
......@@ -26,23 +26,54 @@ const DetailCompensateView = (props) => {
borderTopRightRadius: 10,
borderTopLeftRadius: 10,
}}>
<View style={{borderTopRightRadius:10, borderTopLeftRadius:10, backgroundColor:getColor(item.status)}}>
<Text style={[styles.text, {fontSize: R.sizes.sm, paddingHorizontal:10, paddingVertical:2, color:R.colors.white , fontWeight:'bold', fontFamily:R.fonts.fontMedium,}]}>
<Text style={{fontSize: R.sizes.sm ,color:R.colors.white}}>{item.status}</Text>
<View
style={{
borderTopRightRadius: 10,
borderTopLeftRadius: 10,
backgroundColor: getColor(item.status),
}}>
<Text
style={[
styles.text,
{
fontSize: R.sizes.sm,
paddingHorizontal: 10,
paddingVertical: 2,
color: R.colors.white,
fontWeight: 'bold',
fontFamily: R.fonts.fontMedium,
},
]}>
<Text style={{fontSize: R.sizes.sm, color: R.colors.white}}>
{item.status}
</Text>
</Text>
</View>
</View>
<View style={{paddingHorizontal:10, paddingTop:3, paddingBottom:10}}>
<View style={{paddingHorizontal: 10, paddingTop: 3, paddingBottom: 10}}>
{/* Row 1 */}
<View
style={{
flexDirection: 'row',
}}>
<View style={{flex: 1}}>
<Text style={[styles.text, {fontSize: R.fontsize.fontSizeContent , fontWeight:600, fontFamily:R.fonts.fontMedium}]}>
<Text
style={[
styles.text,
{
fontSize: R.fontsize.fontSizeContent,
fontWeight: 600,
fontFamily: R.fonts.fontMedium,
},
]}>
Ngày báo ngh:{' '}
<Text style={{fontSize: R.fontsize.fontSizeContent , fontWeight:400, fontFamily:R.fonts.fontRegular}}>
<Text
style={{
fontSize: R.fontsize.fontSizeContent,
fontWeight: 400,
fontFamily: R.fonts.fontRegular,
}}>
{item.date}
</Text>
</Text>
......@@ -55,54 +86,115 @@ const DetailCompensateView = (props) => {
</View>
{/* Row 2 */}
<View>
<Text style={[styles.text, {fontSize:R.fontsize.fontSizeContent , fontWeight:600, fontFamily:R.fonts.fontMedium}]}>Thi gian ngh:{' '}
<Text style={{fontSize: R.fontsize.fontSizeContent , fontWeight:400, fontFamily:R.fonts.fontRegular}}>{item.dayOfWeek} - Tiết:{' '}
{item.periods.map((item, index) => {
return <Text key={index}>{item.time},</Text>;
})}
- Ngày: {''}{item.dateStudy}
<Text
style={[
styles.text,
{
fontSize: R.fontsize.fontSizeContent,
fontWeight: 600,
fontFamily: R.fonts.fontMedium,
},
]}>
Thi gian ngh:{' '}
<Text
style={{
fontSize: R.fontsize.fontSizeContent,
fontWeight: 400,
fontFamily: R.fonts.fontRegular,
}}>
{item.dayOfWeek} - Tiết:{' '}
{item.periods.map((item, index) => {
return <Text key={index}>{item.time},</Text>;
})}
- Ngày: {''}
{item.dateStudy}
</Text>
</Text>
</View>
{/* Row 3 */}
<View style={{}}>
<Text style={[styles.text, {fontSize:R.fontsize.fontSizeContent , fontWeight:600, fontFamily:R.fonts.fontMedium}]}>Địa đim:{' '}
<Text style={{fontSize: R.fontsize.fontSizeContent , fontWeight:400, fontFamily:R.fonts.fontRegular}}>{item.location}</Text>
<Text
style={[
styles.text,
{
fontSize: R.fontsize.fontSizeContent,
fontWeight: 600,
fontFamily: R.fonts.fontMedium,
},
]}>
Địa đim:{' '}
<Text
style={{
fontSize: R.fontsize.fontSizeContent,
fontWeight: 400,
fontFamily: R.fonts.fontRegular,
}}>
{item.location}
</Text>
</Text>
</View>
{/* Row 4 */}
<View style={{}}>
<Text style={[styles.text, {fontSize:R.fontsize.fontSizeContent , fontWeight:600, fontFamily:R.fonts.fontMedium}]}>Ging viên thay thế:{' '}
<Text style={{fontSize: R.fontsize.fontSizeContent , fontWeight:400, fontFamily:R.fonts.fontRegular}}>{item.teacher}</Text>
<Text
style={[
styles.text,
{
fontSize: R.fontsize.fontSizeContent,
fontWeight: 600,
fontFamily: R.fonts.fontMedium,
},
]}>
Ging viên thay thế:{' '}
<Text
style={{
fontSize: R.fontsize.fontSizeContent,
fontWeight: 400,
fontFamily: R.fonts.fontRegular,
}}>
{item.teacher}
</Text>
</Text>
</View>
{/* Row 5 */}
<View style={{}}>
<Text style={[styles.text, {fontSize:R.fontsize.fontSizeContent , fontWeight:600, fontFamily:R.fonts.fontMedium}]}>Ghi chú:{' '}
<Text style={{fontSize: R.fontsize.fontSizeContent , fontWeight:400, fontFamily:R.fonts.fontRegular}}>{item.note}</Text>
<Text
style={[
styles.text,
{
fontSize: R.fontsize.fontSizeContent,
fontWeight: 600,
fontFamily: R.fonts.fontMedium,
},
]}>
Ghi chú:{' '}
<Text
style={{
fontSize: R.fontsize.fontSizeContent,
fontWeight: 400,
fontFamily: R.fonts.fontRegular,
}}>
{item.note}
</Text>
</Text>
</View>
{
item.status === 'Chờ phê duyệt' && (
<View style={{alignItems:'flex-end'}}>
{item.status === 'Chờ phê duyệt' && (
<View style={{alignItems: 'flex-end'}}>
<Button
title='Huỷ'
onPress={()=>{}}
backgroundColor={R.colors.orange}
textColor={R.colors.white}
height={25}
width={90}
borderRadius={15}
fontSize={R.fontsize.fontSizeContent}
fontWeight={'600'}
fontFamily={R.fonts.fontMedium}
paddingHorizontal={15}
title="Huỷ"
onPress={() => {}}
backgroundColor={R.colors.orange}
textColor={R.colors.white}
height={25}
width={90}
borderRadius={15}
fontSize={R.fontsize.fontSizeContent}
fontWeight={'600'}
fontFamily={R.fonts.fontMedium}
paddingHorizontal={15}
/>
</View>
)
}
</View>
)}
</View>
</View>
);
......@@ -112,9 +204,27 @@ const DetailCompensateView = (props) => {
<View style={styles.container}>
<Header title={'ATTT2024.1'} isBack />
<View style={styles.body}>
<View style={{alignItems: 'center', marginTop:10}}>
<Text style={[styles.text, {fontSize:R.fontsize.fontSizeContent , fontWeight:600, fontFamily:R.fonts.fontMedium}]}>Ngh / Bù / Tng</Text>
<Text style={[styles.text, {fontSize:R.fontsize.fontSizeContent , fontWeight:400, fontFamily:R.fonts.fontRegular}]}>
<View style={{alignItems: 'center', marginTop: 10}}>
<Text
style={[
styles.text,
{
fontSize: R.fontsize.fontSizeContent,
fontWeight: 600,
fontFamily: R.fonts.fontMedium,
},
]}>
Ngh / Bù / Tng
</Text>
<Text
style={[
styles.text,
{
fontSize: R.fontsize.fontSizeContent,
fontWeight: 400,
fontFamily: R.fonts.fontRegular,
},
]}>
{itemDetail?.rest} / {itemDetail?.compensate} / {itemDetail?.total}
</Text>
</View>
......
import { StyleSheet, Text, View, Dimensions } from 'react-native'
import {StyleSheet, Text, View, Dimensions} from 'react-native';
import R from '../../../assets/R';
//B1: Xác định chiều rộng cột đầu tiên
const width_first = 100;
//B2: Xác định chiều rộng của 15 cột tiếp theo
const width_second = 110;
const width_first = 100;
//B2: Xác định chiều rộng của 15 cột tiếp theo
const width_second = 110;
//B3: Xác định số tiết diễn ra trong 1 ngày -> để có kích thước bảng
const period_count = 15;
//B4: Xác định chiều rộng của bảng
const total_width_table = width_first + (width_second * period_count);
//B4: Xác định chiều rộng của bảng
const total_width_table = width_first + width_second * period_count;
const styles = StyleSheet.create({
container:{
flex:1,
backgroundColor:R.colors.white,
},
body:{
flex:1,
backgroundColor:R.colors.white,
padding:15,
},
containerInput:{
flexDirection:'row',
justifyContent:'space-between',
marginBottom:15
},
txtSubtitle:{
fontWeight:'600',
fontFamily:R.fonts.fontMedium,
fontSize:R.fontsize.fontSizeLabel,
color:R.colors.black,
},
containerDropDown:{
marginBottom:15
},
btnRegister:{
alignItems:'flex-end',
},
btnRegister2:{
marginVertical:15
},
container: {
flex: 1,
backgroundColor: R.colors.white,
},
body: {
flex: 1,
backgroundColor: R.colors.white,
padding: 15,
},
containerInput: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 15,
},
txtSubtitle: {
fontWeight: '600',
fontFamily: R.fonts.fontMedium,
fontSize: R.fontsize.fontSizeLabel,
color: R.colors.black,
},
containerDropDown: {
marginBottom: 15,
},
btnRegister: {
alignItems: 'flex-end',
},
btnRegister2: {
marginVertical: 15,
},
//Header bảng lịch
tableContainer:{
marginTop:15,
borderWidth:1,
borderColor:R.colors.gray,
width:total_width_table,
},
//Header bảng lịch
tableContainer: {
marginTop: 15,
borderWidth: 1,
borderColor: R.colors.gray,
width: total_width_table,
},
headerRow: {
flexDirection: 'row',
backgroundColor: R.colors.white,
borderBottomWidth: 1,
borderBottomColor: R.colors.gray,
},
headerText: {
fontSize: R.sizes.sm,
fontWeight: '500',
fontFamily: R.fonts.fontMedium,
color: R.colors.black,
},
dateColumn: {
height: 40,
width:width_first,
paddingHorizontal: 10,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: R.colors.blue2,
borderRightWidth:1,
borderRightColor:R.colors.gray,
},
periodColumn: {
height: 40,
width:width_second,
paddingHorizontal: 5,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: R.colors.blue2,
borderRightWidth:1,
borderRightColor:R.colors.gray,
},
dateBody:{
width: width_first,
minHeight: 40,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: R.colors.white,
borderRightWidth:1,
borderRightColor:R.colors.gray,
},
periodBody:{
width: width_second,
padding:5,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: R.colors.white,
borderRightWidth:1,
borderRightColor:R.colors.gray,
},
dataRow: {
flexDirection: 'row',
borderBottomWidth: 1,
borderBottomColor: R.colors.gray,
minHeight: 50,
},
periodCell: {
padding: 2,
alignItems: 'center',
justifyContent: 'center',
minHeight: 50,
width: '100%',
},
dateText:{
fontSize: R.sizes.sm,
fontWeight: '400',
fontFamily: R.fonts.fontRegular,
color: R.colors.black,
},
percentText:{
fontSize: R.sizes.sm,
fontWeight: '500',
fontFamily: R.fonts.fontMedium,
color: R.colors.black,
},
codeText:{
fontSize: R.sizes.sm,
fontWeight: '500',
fontFamily: R.fonts.fontMedium,
color: R.colors.black,
},
})
export default styles
\ No newline at end of file
headerRow: {
flexDirection: 'row',
backgroundColor: R.colors.white,
borderBottomWidth: 1,
borderBottomColor: R.colors.gray,
},
headerText: {
fontSize: R.sizes.sm,
fontWeight: '500',
fontFamily: R.fonts.fontMedium,
color: R.colors.black,
},
dateColumn: {
height: 40,
width: width_first,
paddingHorizontal: 10,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: R.colors.blue2,
borderRightWidth: 1,
borderRightColor: R.colors.gray,
},
periodColumn: {
height: 40,
width: width_second,
paddingHorizontal: 5,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: R.colors.blue2,
borderRightWidth: 1,
borderRightColor: R.colors.gray,
},
dateBody: {
width: width_first,
minHeight: 40,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: R.colors.white,
borderRightWidth: 1,
borderRightColor: R.colors.gray,
},
periodBody: {
width: width_second,
padding: 5,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: R.colors.white,
borderRightWidth: 1,
borderRightColor: R.colors.gray,
},
dataRow: {
flexDirection: 'row',
borderBottomWidth: 1,
borderBottomColor: R.colors.gray,
minHeight: 50,
},
periodCell: {
padding: 2,
alignItems: 'center',
justifyContent: 'center',
minHeight: 50,
width: '100%',
},
dateText: {
fontSize: R.sizes.sm,
fontWeight: '400',
fontFamily: R.fonts.fontRegular,
color: R.colors.black,
},
percentText: {
fontSize: R.sizes.sm,
fontWeight: '500',
fontFamily: R.fonts.fontMedium,
color: R.colors.black,
},
codeText: {
fontSize: R.sizes.sm,
fontWeight: '500',
fontFamily: R.fonts.fontMedium,
color: R.colors.black,
},
});
export default styles;
......@@ -17,8 +17,8 @@ import CheckBox from '../../../components/CheckBox';
const CompensateRegisterView = props => {
const {isShow, setShowSchedule, scheduleData, onCheckboxChange} = props;
const getCheckColor = (item) => {
if ( item?.breakTime=== item?.totalSession && item?.percent === '100%') {
const getCheckColor = item => {
if (item?.breakTime === item?.totalSession && item?.percent === '100%') {
return R.colors.blue;
}
return R.colors.red;
......@@ -36,7 +36,9 @@ const CompensateRegisterView = props => {
</View>
{Array.from({length: 15}, (_, i) => (
<View key={i} style={[styles.periodColumn, {backgroundColor: R.colors.blue3}]}>
<View
key={i}
style={[styles.periodColumn, {backgroundColor: R.colors.blue3}]}>
<Text style={styles.headerText}>Tiết {i + 1} </Text>
</View>
))}
......@@ -65,34 +67,35 @@ const CompensateRegisterView = props => {
styles.periodCell,
period.available && styles.availableCell,
]}>
<CheckBox
<CheckBox
checked={period.available}
value={period.available}
onValueChange={value => onCheckboxChange(index, periodIndex, value)}
onValueChange={value =>
onCheckboxChange(index, periodIndex, value)
}
size={20}
labelStyle={styles.label}
checkedColor={R.colors.main}
tickColor={R.colors.white}
/>
<View style={{flexDirection:'row'}}>
<Text
style={[
styles.percentText,
period.available && styles.availableText,
{color:getCheckColor(period)}
]}>
{period.percent}
</Text>
<Text
style={[
styles.codeText,
{color:getCheckColor(period), marginLeft:3},
period.available && styles.availableText,
]}>
({period.breakTime}/{period.totalSession})
</Text>
<View style={{flexDirection: 'row'}}>
<Text
style={[
styles.percentText,
period.available && styles.availableText,
{color: getCheckColor(period)},
]}>
{period.percent}
</Text>
<Text
style={[
styles.codeText,
{color: getCheckColor(period), marginLeft: 3},
period.available && styles.availableText,
]}>
({period.breakTime}/{period.totalSession})
</Text>
</View>
</View>
</View>
))}
......@@ -210,20 +213,19 @@ const CompensateRegisterView = props => {
/>
</View>
<ScrollView
showsHorizontalScrollIndicator={false}
horizontal>{renderSchedule()}</ScrollView>
<ScrollView showsHorizontalScrollIndicator={false} horizontal>
{renderSchedule()}
</ScrollView>
<View style={styles.btnRegister2}>
<Button
title={'Đăng kí dạy bù'}
backgroundColor={R.colors.blue}
textColor={R.colors.white}
onPress={()=>{}}
onPress={() => {}}
fontSize={R.sizes.sm}
fontFamily={R.fonts.fontMedium}
height={35}
containerStyle={{paddingHorizontal: 15, borderRadius: 10}}
/>
</View>
</View>
......
import { StyleSheet, Text, View } from 'react-native'
import R from '../../assets/R'
import {StyleSheet, Text, View} from 'react-native';
import R from '../../assets/R';
const styles = StyleSheet.create({
container:{
flex:1,
backgroundColor:R.colors.white,
},
body:{
flex:1,
backgroundColor:R.colors.white,
},
card: {
borderRadius: 10,
padding: 5,
marginTop: 15,
marginBottom:5,
marginHorizontal: 15,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: R.colors.white,
shadowColor: R.colors.black,
shadowOffset: {width: 0.5, height: 2},
shadowOpacity: Platform.OS === 'ios' ? 0.25 : 1,
shadowRadius: 5,
elevation: Platform.OS === 'ios' ? 1 : 2,
},
btnCard: {
borderRadius: 10,
borderWidth: 1,
padding: 5,
width: '100%',
alignItems: 'center',
justifyContent: 'center',
borderColor: R.colors.grayBorderInputTextHeader,
},
text: {
fontSize: R.sizes.sm,
color: R.colors.black,
fontFamily: R.fonts.fontRegular,
fontWeight: '400',
},
containerCard: {
padding: 10,
borderRadius: 10,
marginVertical:10,
backgroundColor: R.colors.white,
shadowColor: R.colors.black,
shadowOffset: {width: 0, height: 2},
shadowOpacity: Platform.OS === 'ios' ? 0.25 : 1,
shadowRadius: 1,
elevation: Platform.OS === 'ios' ? 1 : 2,
marginHorizontal: 15,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
containerText: {
alignItems: 'center',
justifyContent: 'center',
},
btnRight: {},
btnRegister:{
borderRadius:10,
alignItems:'center',
justifyContent:'center',
marginHorizontal:15,
marginVertical:10,
backgroundColor:R.colors.blue,
borderRadius:10,
padding:5,
height:35
}
})
container: {
flex: 1,
backgroundColor: R.colors.white,
},
body: {
flex: 1,
backgroundColor: R.colors.white,
},
card: {
borderRadius: 10,
padding: 5,
marginTop: 15,
marginBottom: 5,
marginHorizontal: 15,
alignItems: 'center',
justifyContent: 'center',
export default styles
backgroundColor: R.colors.white,
shadowColor: R.colors.black,
shadowOffset: {width: 0.5, height: 2},
shadowOpacity: Platform.OS === 'ios' ? 0.25 : 1,
shadowRadius: 5,
elevation: Platform.OS === 'ios' ? 1 : 2,
},
btnCard: {
borderRadius: 10,
borderWidth: 1,
padding: 5,
width: '100%',
alignItems: 'center',
justifyContent: 'center',
borderColor: R.colors.grayBorderInputTextHeader,
},
text: {
fontSize: R.sizes.sm,
color: R.colors.black,
fontFamily: R.fonts.fontRegular,
fontWeight: '400',
},
containerCard: {
padding: 10,
borderRadius: 10,
marginVertical: 10,
backgroundColor: R.colors.white,
shadowColor: R.colors.black,
shadowOffset: {width: 0, height: 2},
shadowOpacity: Platform.OS === 'ios' ? 0.25 : 1,
shadowRadius: 1,
elevation: Platform.OS === 'ios' ? 1 : 2,
marginHorizontal: 15,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
containerText: {
alignItems: 'center',
justifyContent: 'center',
},
btnRight: {},
btnRegister: {
borderRadius: 10,
alignItems: 'center',
justifyContent: 'center',
marginHorizontal: 15,
marginVertical: 10,
backgroundColor: R.colors.blue,
borderRadius: 10,
padding: 5,
height: 35,
},
});
export default styles;
import React from 'react';
import {Text, View, TouchableOpacity, StyleSheet, FlatList, Image} from 'react-native';
import {
Text,
View,
TouchableOpacity,
StyleSheet,
FlatList,
Image,
} from 'react-native';
import styles from './style';
import Header from '../../components/Header/Header';
import R from '../../assets/R';
import*as SCREENNAME from '../../routers/ScreenNames';
import { useNavigation } from '@react-navigation/native';
const CompensateView = (props) => {
import * as SCREENNAME from '../../routers/ScreenNames';
import {useNavigation} from '@react-navigation/native';
const CompensateView = props => {
const {dataList} = props;
const navigation = useNavigation();
const renderItem = ({item}) => {
......@@ -29,9 +36,27 @@ const CompensateView = (props) => {
</Text>
</View>
<View style={{alignItems:'center'}}>
<Text style={[styles.text, {fontSize:R.fontsize.fontSizeContent , fontWeight:600, fontFamily:R.fonts.fontMedium}]}>Ngh / Bù / Tng</Text>
<Text style={[styles.text, {fontSize:R.fontsize.fontSizeContent , fontWeight:400, fontFamily:R.fonts.fontRegular}]}>
<View style={{alignItems: 'center'}}>
<Text
style={[
styles.text,
{
fontSize: R.fontsize.fontSizeContent,
fontWeight: 600,
fontFamily: R.fonts.fontMedium,
},
]}>
Ngh / Bù / Tng
</Text>
<Text
style={[
styles.text,
{
fontSize: R.fontsize.fontSizeContent,
fontWeight: 400,
fontFamily: R.fonts.fontRegular,
},
]}>
{item.rest} / {item.compensate} / {item.total}
</Text>
</View>
......@@ -53,7 +78,17 @@ const CompensateView = (props) => {
<View style={styles.body}>
<View style={styles.card}>
<TouchableOpacity style={styles.btnCard}>
<Text style={[styles.text, {fontSize:R.fontsize.fontSizeContent , fontWeight:600, fontFamily:R.fonts.fontMedium}]}>Hc k 2, Năm 2025</Text>
<Text
style={[
styles.text,
{
fontSize: R.fontsize.fontSizeContent,
fontWeight: 600,
fontFamily: R.fonts.fontMedium,
},
]}>
Hc k 2, Năm 2025
</Text>
</TouchableOpacity>
</View>
<FlatList
......@@ -63,9 +98,13 @@ const CompensateView = (props) => {
vertical
keyExtractor={(item, index) => `${index}`}
/>
<TouchableOpacity style={styles.btnRegister} onPress={ () => navigation.navigate(SCREENNAME.REGISTERMAKEUP)}>
<Text style={[styles.text, {color:R.colors.white}]}>Đăng kí báo bù</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.btnRegister}
onPress={() => navigation.navigate(SCREENNAME.REGISTERMAKEUP)}>
<Text style={[styles.text, {color: R.colors.white}]}>
Đăng kí báo bù
</Text>
</TouchableOpacity>
</View>
</View>
);
......
import React, { useState } from 'react';
import React, {useState} from 'react';
import {Text, View, StyleSheet} from 'react-native';
import DetailEmailView from './view';
const DetailEmail = (props) => {
const DetailEmail = props => {
const [incoming_document, setIncomingDocument] = useState({
title:'Đăng ký tham gia TechX 2025 - Định hình tương lai công nghệ!',
avatar:'https://i.pinimg.com/736x/a5/71/ca/a571cac1f9e27c642f3b5e13f76f87fb.jpg',
name:'Vũ công bình',
date:'27/07/2025',
from:'ducnm@.abc.com',
cc:[{id:1, name:'ducnm@.abc.com'},{id:2, name:'ducnm@.abc.com'},{id:3, name:'ducnm@.abc.com'}, {id:4, name:'ducnm@.abc.com'}, {id:5, name:'ducnm@.abc.com'}, {id:6, name:'ducnm@.abc.com'}, {id:7, name:'ducnm@.abc.com'}, {id:8, name:'ducnm@.abc.com'}, {id:9, name:'ducnm@.abc.com'}, {id:10, name:'ducnm@.abc.com'}, {id:11, name:'ducnm@.abc.com'}, {id:12, name:'ducnm@.abc.com'}, {id:13, name:'ducnm@.abc.com'}, {id:14, name:'ducnm@.abc.com'}, {id:15, name:'ducnm@.abc.com'}, {id:16, name:'ducnm@.abc.com'}, {id:17, name:'ducnm@.abc.com'}, {id:18, name:'ducnm@.abc.com'}, {id:19, name:'ducnm@.abc.com'}, {id:20, name:'ducnm@.abc.com'}],
bcc:'ducnm@.abc.com',
to:'ducnm@.abc.com',
content: "Kính gửi toàn thể Anh/Chị CBNV,\n\nTheo cập nhật mới nhất từ cơ quan khí tượng, bão số 3 (tên quốc tế: Wipha) hiện đang cách Quảng Ninh – Hải Phòng khoảng 233km về phía Đông. Trong 12 giờ qua, bão đã suy yếu 3 cấp (còn cấp 9), tuy nhiên dự báo sẽ mạnh lên khi đi vào khu vực Vịnh Bắc Bộ trong hôm nay (21/7).\n\nDự kiến từ chiều và tối nay, các tỉnh vùng ven biển và khu vực đồng bằng Bắc Bộ, bao gồm cả Hà Nội, có thể xảy ra mưa to, gió lớn, thậm chí có hiện tượng ngập úng cục bộ, cây đổ, mất điện.\n\nĐể đảm bảo an toàn cho toàn thể CBNV, công ty xin lưu ý:\n\n1. CBNV đang sinh sống tại khu vực bị ảnh hưởng bởi mưa bão có thể chủ động làm việc từ xa (remote) vào ngày mai nếu thấy điều kiện di chuyển không an toàn.\n\n2. Trong mọi trường hợp, ưu tiên cao nhất là an toàn cá nhân. Nếu gặp tình trạng ngập sâu, cây gãy đổ, đường trơn trượt nguy hiểm... vui lòng không cố gắng di chuyển đến văn phòng.\n\n3. Các quản lý trực tiếp chủ động nhắc nhở thành viên trong nhóm, và tạo điều kiện linh hoạt để đảm bảo công việc được duy trì hiệu quả, dù làm việc tại nhà.\n\nCông ty khuyến nghị anh/chị:\n\n- Hạn chế ra ngoài khi mưa gió lớn, kiểm tra và gia cố nhà cửa nếu cần thiết;\n- Liên hệ ngay với quản lý hoặc bộ phận HCNS nếu có tình huống khẩn cấp.\n\nRất mong anh/chị giữ gìn sức khỏe, an toàn và chủ động phối hợp trong thời gian này."
title: 'Đăng ký tham gia TechX 2025 - Định hình tương lai công nghệ!',
avatar:
'https://i.pinimg.com/736x/a5/71/ca/a571cac1f9e27c642f3b5e13f76f87fb.jpg',
name: 'Vũ công bình',
date: '27/07/2025',
from: 'ducnm@.abc.com',
cc: [
{id: 1, name: 'ducnm@.abc.com'},
{id: 2, name: 'ducnm@.abc.com'},
{id: 3, name: 'ducnm@.abc.com'},
{id: 4, name: 'ducnm@.abc.com'},
{id: 5, name: 'ducnm@.abc.com'},
{id: 6, name: 'ducnm@.abc.com'},
{id: 7, name: 'ducnm@.abc.com'},
{id: 8, name: 'ducnm@.abc.com'},
{id: 9, name: 'ducnm@.abc.com'},
{id: 10, name: 'ducnm@.abc.com'},
{id: 11, name: 'ducnm@.abc.com'},
{id: 12, name: 'ducnm@.abc.com'},
{id: 13, name: 'ducnm@.abc.com'},
{id: 14, name: 'ducnm@.abc.com'},
{id: 15, name: 'ducnm@.abc.com'},
{id: 16, name: 'ducnm@.abc.com'},
{id: 17, name: 'ducnm@.abc.com'},
{id: 18, name: 'ducnm@.abc.com'},
{id: 19, name: 'ducnm@.abc.com'},
{id: 20, name: 'ducnm@.abc.com'},
],
bcc: 'ducnm@.abc.com',
to: 'ducnm@.abc.com',
content:
'Kính gửi toàn thể Anh/Chị CBNV,\n\nTheo cập nhật mới nhất từ cơ quan khí tượng, bão số 3 (tên quốc tế: Wipha) hiện đang cách Quảng Ninh – Hải Phòng khoảng 233km về phía Đông. Trong 12 giờ qua, bão đã suy yếu 3 cấp (còn cấp 9), tuy nhiên dự báo sẽ mạnh lên khi đi vào khu vực Vịnh Bắc Bộ trong hôm nay (21/7).\n\nDự kiến từ chiều và tối nay, các tỉnh vùng ven biển và khu vực đồng bằng Bắc Bộ, bao gồm cả Hà Nội, có thể xảy ra mưa to, gió lớn, thậm chí có hiện tượng ngập úng cục bộ, cây đổ, mất điện.\n\nĐể đảm bảo an toàn cho toàn thể CBNV, công ty xin lưu ý:\n\n1. CBNV đang sinh sống tại khu vực bị ảnh hưởng bởi mưa bão có thể chủ động làm việc từ xa (remote) vào ngày mai nếu thấy điều kiện di chuyển không an toàn.\n\n2. Trong mọi trường hợp, ưu tiên cao nhất là an toàn cá nhân. Nếu gặp tình trạng ngập sâu, cây gãy đổ, đường trơn trượt nguy hiểm... vui lòng không cố gắng di chuyển đến văn phòng.\n\n3. Các quản lý trực tiếp chủ động nhắc nhở thành viên trong nhóm, và tạo điều kiện linh hoạt để đảm bảo công việc được duy trì hiệu quả, dù làm việc tại nhà.\n\nCông ty khuyến nghị anh/chị:\n\n- Hạn chế ra ngoài khi mưa gió lớn, kiểm tra và gia cố nhà cửa nếu cần thiết;\n- Liên hệ ngay với quản lý hoặc bộ phận HCNS nếu có tình huống khẩn cấp.\n\nRất mong anh/chị giữ gìn sức khỏe, an toàn và chủ động phối hợp trong thời gian này.',
});
return (
<DetailEmailView incoming_document={incoming_document}/>
);
return <DetailEmailView incoming_document={incoming_document} />;
};
export default DetailEmail;
import { StyleSheet, Text, View } from 'react-native'
import R from '../../../assets/R'
import {StyleSheet, Text, View} from 'react-native';
import R from '../../../assets/R';
const styles = StyleSheet.create({
container:{
flex:1,
backgroundColor:R.colors.white,
},
body:{
flex:1,
backgroundColor:R.colors.white,
paddingHorizontal:15,
paddingVertical:10
},
header:{
backgroundColor:R.colors.blue,
height:50,
flexDirection:'row',
alignItems:'center',
justifyContent:'space-between',
paddingHorizontal:15
},
iconBack:{
width:25,
height:20
},
iconDelete:{
width:25,
height:20
},
title:{
fontSize:R.fontsize.fontSizeSubTitle,
fontFamily:R.fonts.fontMedium,
fontWeight:'600',
color:R.colors.black,
},
avatarBox:{
height:50,
flexDirection:'row',
marginVertical:5
},
avatarContainer:{
width:50,
height:50,
borderRadius:25,
},
avatar:{
width:50,
height:50,
borderRadius:25,
},
avatarTextContainer:{
flex:1,
marginLeft:10,
paddingVertical:2,
flexDirection:'row',
justifyContent:'space-between',
},
name:{
fontSize:R.fontsize.fontSizeLabel,
fontFamily:R.fonts.fontMedium,
fontWeight:'600',
color:R.colors.black,
},
date:{
fontSize:R.fontsize.fontSizeLabel,
fontFamily:R.fonts.fontMedium,
fontWeight:'600',
color:R.colors.gray,
},
iconDrop:{
width:20,
height:20
},
toMeContainer:{
flexDirection:'row',
alignItems:'center',
},
detailSendContainer:{
width:'100%',
height:200,
backgroundColor:R.colors.blue4,
borderRadius:15,
paddingHorizontal:15,
paddingVertical:10
},
textTitleMail:{
fontSize:R.fontsize.fontSizeLabel,
fontFamily:R.fonts.fontBold,
fontWeight:'600',
color:R.colors.black,
},
textSubMail:{
fontSize:R.fontsize.fontSizeLabel,
fontFamily:R.fonts.fontRegular,
fontWeight:'400',
color:R.colors.black,
},
textContent:{
fontSize:R.fontsize.fontSizeLabel,
fontFamily:R.fonts.fontRegular,
fontWeight:'400',
color:R.colors.black,
},
iconReply:{
width:15,
height:15
},
iconForward:{
width:15,
height:15
}
})
export default styles
container: {
flex: 1,
backgroundColor: R.colors.white,
},
body: {
flex: 1,
backgroundColor: R.colors.white,
paddingHorizontal: 15,
paddingVertical: 10,
},
header: {
backgroundColor: R.colors.blue,
height: 50,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: 15,
},
iconBack: {
width: 25,
height: 20,
},
iconDelete: {
width: 25,
height: 20,
},
title: {
fontSize: R.fontsize.fontSizeSubTitle,
fontFamily: R.fonts.fontMedium,
fontWeight: '600',
color: R.colors.black,
},
avatarBox: {
height: 50,
flexDirection: 'row',
marginVertical: 5,
},
avatarContainer: {
width: 50,
height: 50,
borderRadius: 25,
},
avatar: {
width: 50,
height: 50,
borderRadius: 25,
},
avatarTextContainer: {
flex: 1,
marginLeft: 10,
paddingVertical: 2,
flexDirection: 'row',
justifyContent: 'space-between',
},
name: {
fontSize: R.fontsize.fontSizeLabel,
fontFamily: R.fonts.fontMedium,
fontWeight: '600',
color: R.colors.black,
},
date: {
fontSize: R.fontsize.fontSizeLabel,
fontFamily: R.fonts.fontMedium,
fontWeight: '600',
color: R.colors.gray,
},
iconDrop: {
width: 20,
height: 20,
},
toMeContainer: {
flexDirection: 'row',
alignItems: 'center',
},
detailSendContainer: {
width: '100%',
height: 200,
backgroundColor: R.colors.blue4,
borderRadius: 15,
paddingHorizontal: 15,
paddingVertical: 10,
},
textTitleMail: {
fontSize: R.fontsize.fontSizeLabel,
fontFamily: R.fonts.fontBold,
fontWeight: '600',
color: R.colors.black,
},
textSubMail: {
fontSize: R.fontsize.fontSizeLabel,
fontFamily: R.fonts.fontRegular,
fontWeight: '400',
color: R.colors.black,
},
textContent: {
fontSize: R.fontsize.fontSizeLabel,
fontFamily: R.fonts.fontRegular,
fontWeight: '400',
color: R.colors.black,
},
iconReply: {
width: 15,
height: 15,
},
iconForward: {
width: 15,
height: 15,
},
});
export default styles;
......@@ -28,61 +28,61 @@ const DetailEmailView = props => {
</View>
);
};
const renderBottomCard = () =>{
return(
const renderBottomCard = () => {
return (
<View style={styles.detailSendContainer}>
<ScrollView nestedScrollEnabled={true} style={{flex:1} }>
<Text style={styles.textTitleMail}>From:{' '}
<Text style={styles.textSubMail}>{incoming_document.from}</Text>
</Text>
<Text style={styles.textTitleMail}>CC:{' '}
<Text style={styles.textSubMail}>{incoming_document.cc.map((item,index)=>{
return(
<Text key={index}>{item.name},</Text>
)
})}</Text>
</Text>
<Text style={styles.textTitleMail}>BCC:{' '}
<Text style={styles.textSubMail}>{incoming_document.bcc}</Text>
</Text>
<Text style={styles.textTitleMail}>TO:{' '}
<Text style={styles.textSubMail}>{incoming_document.to}</Text>
</Text>
</ScrollView>
</View>
)
}
<ScrollView nestedScrollEnabled={true} style={{flex: 1}}>
<Text style={styles.textTitleMail}>
From:{' '}
<Text style={styles.textSubMail}>{incoming_document.from}</Text>
</Text>
<Text style={styles.textTitleMail}>
CC:{' '}
<Text style={styles.textSubMail}>
{incoming_document.cc.map((item, index) => {
return <Text key={index}>{item.name},</Text>;
})}
</Text>
</Text>
<Text style={styles.textTitleMail}>
BCC: <Text style={styles.textSubMail}>{incoming_document.bcc}</Text>
</Text>
<Text style={styles.textTitleMail}>
TO: <Text style={styles.textSubMail}>{incoming_document.to}</Text>
</Text>
</ScrollView>
</View>
);
};
const renderButton =(
{
title,
onPress,
style,
icon,
textStyle,
iconRight,
}
)=>{
return(
const renderButton = ({
title,
onPress,
style,
icon,
textStyle,
iconRight,
}) => {
return (
<TouchableOpacity style={style} onPress={onPress}>
<View style={{flexDirection:'row', alignItems:'center', justifyContent:'center', marginHorizontal:10,}}>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
marginHorizontal: 10,
}}>
<Image source={icon} style={styles.iconReply} resizeMode="contain" />
<Text style={textStyle}>{title}</Text>
<Image
source={icon}
style={styles.iconReply}
resizeMode="contain"
/>
<Text style={textStyle}>{title}</Text>
<Image
source={iconRight}
style={[styles.iconForward, { transform: [{ rotateY: '180deg' }] }]}
resizeMode="contain"
/>
source={iconRight}
style={[styles.iconForward, {transform: [{rotateY: '180deg'}]}]}
resizeMode="contain"
/>
</View>
</TouchableOpacity>
)
}
);
};
const renderBody = () => {
return (
......@@ -100,18 +100,18 @@ const DetailEmailView = props => {
<View style={styles.avatarTextContainer}>
<View>
<Text style={styles.name}>{incoming_document.name}</Text>
<TouchableOpacity
<TouchableOpacity
style={styles.toMeContainer}
onPress={() => setShowBottomCard(!showBottomCard)}
>
<Text>
to me
</Text>
onPress={() => setShowBottomCard(!showBottomCard)}>
<Text>to me</Text>
<Image
source={R.images.icDrop}
style={[styles.iconDrop, {
transform: [{ rotate: showBottomCard ? '180deg' : '0deg' }]
}]}
style={[
styles.iconDrop,
{
transform: [{rotate: showBottomCard ? '180deg' : '0deg'}],
},
]}
resizeMode="contain"
/>
</TouchableOpacity>
......@@ -119,94 +119,90 @@ const DetailEmailView = props => {
<Text style={styles.date}>{incoming_document.date}</Text>
</View>
</View>
{showBottomCard && renderBottomCard()}
<View style={{marginVertical:15}}>
<View style={{marginVertical: 15}}>
<Text style={styles.textContent}>{incoming_document.content}</Text>
</View>
<View style={{marginBottom:35 , flexDirection:'row', justifyContent:'space-between'}}>
<View
style={{
marginBottom: 35,
flexDirection: 'row',
justifyContent: 'space-between',
}}>
{renderButton({
title:'Reply',
onPress:()=>{},
icon:R.images.icReply,
style:{
backgroundColor:R.colors.white,
padding:5,
borderRadius:15,
borderColor:R.colors.black,
borderWidth:1,
width:105,
flexDirection:'row',
alignItems:'center',
justifyContent:'center',
height:40,
title: 'Reply',
onPress: () => {},
icon: R.images.icReply,
style: {
backgroundColor: R.colors.white,
padding: 5,
borderRadius: 15,
borderColor: R.colors.black,
borderWidth: 1,
width: 105,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
height: 40,
},
textStyle:{
color:R.colors.black,
fontSize:R.fontsize.fontSizeLabel,
fontFamily:R.fonts.fontMedium,
fontWeight:'600',
marginLeft:5
textStyle: {
color: R.colors.black,
fontSize: R.fontsize.fontSizeLabel,
fontFamily: R.fonts.fontMedium,
fontWeight: '600',
marginLeft: 5,
},
})}
{renderButton({
title:'Reply All',
onPress:()=>{},
icon:R.images.icReplyAll,
style:{
backgroundColor:R.colors.white,
padding:5,
borderRadius:15,
borderColor:R.colors.black,
borderWidth:1,
width:105,
flexDirection:'row',
alignItems:'center',
justifyContent:'center',
height:40,
title: 'Reply All',
onPress: () => {},
icon: R.images.icReplyAll,
style: {
backgroundColor: R.colors.white,
padding: 5,
borderRadius: 15,
borderColor: R.colors.black,
borderWidth: 1,
width: 105,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
height: 40,
},
textStyle:{
color:R.colors.black,
fontSize:R.fontsize.fontSizeLabel,
fontFamily:R.fonts.fontMedium,
fontWeight:'600',
marginLeft:5
textStyle: {
color: R.colors.black,
fontSize: R.fontsize.fontSizeLabel,
fontFamily: R.fonts.fontMedium,
fontWeight: '600',
marginLeft: 5,
},
})}
{renderButton({
title:'Forward',
onPress:()=>{},
iconRight:R.images.icReply,
style:{
backgroundColor:R.colors.white,
padding:5,
borderRadius:15,
borderColor:R.colors.black,
borderWidth:1,
width:105,
flexDirection:'row',
alignItems:'center',
justifyContent:'center',
height:40,
{renderButton({
title: 'Forward',
onPress: () => {},
iconRight: R.images.icReply,
style: {
backgroundColor: R.colors.white,
padding: 5,
borderRadius: 15,
borderColor: R.colors.black,
borderWidth: 1,
width: 105,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
height: 40,
},
textStyle:{
color:R.colors.black,
fontSize:R.fontsize.fontSizeLabel,
fontFamily:R.fonts.fontMedium,
fontWeight:'600',
marginRight:5
textStyle: {
color: R.colors.black,
fontSize: R.fontsize.fontSizeLabel,
fontFamily: R.fonts.fontMedium,
fontWeight: '600',
marginRight: 5,
},
})}
</View>
</ScrollView>
);
};
......
import React, { useState, useEffect } from 'react';
import React, {useState, useEffect} from 'react';
import EmailHomeView from './view';
const EmailHome = (props) => {
const EmailHome = props => {
const [emails, setEmails] = useState([]);
const [loading, setLoading] = useState(true);
......@@ -10,7 +10,7 @@ const EmailHome = (props) => {
const today = new Date();
const yesterday = new Date(today);
yesterday.setDate(yesterday.getDate() - 1);
const weekAgo = new Date(today);
weekAgo.setDate(weekAgo.getDate() - 7);
......@@ -22,65 +22,82 @@ const EmailHome = (props) => {
id: 1,
sender: 'Nguyễn Minh Đức',
subject: 'Bảng lương tháng 10',
preview: 'Kính gửi nhân viên ưu tú đây là bảng lương tháng 10 của bạn hãy kiểm tra nếu có thắc...',
preview:
'Kính gửi nhân viên ưu tú đây là bảng lương tháng 10 của bạn hãy kiểm tra nếu có thắc...',
date: today,
isRead: true,
hasAttachment: false,
avatar: 'https://via.placeholder.com/40'
avatar: 'https://via.placeholder.com/40',
},
{
id: 2,
sender: 'Vũ Công Bình',
subject: 'Re: ĐƠN XIN ỨNG LƯƠNG',
preview: 'Kính gửi nhân viên ưu tú đây là bảng lương tháng 10 của bạn hãy kiểm tra nếu có thắc...',
preview:
'Kính gửi nhân viên ưu tú đây là bảng lương tháng 10 của bạn hãy kiểm tra nếu có thắc...',
date: yesterday,
isRead: false,
hasAttachment: true,
avatar: 'https://via.placeholder.com/40'
avatar: 'https://via.placeholder.com/40',
},
{
id: 3,
sender: 'Vũ Công Bình',
subject: 'Re: ĐƠN XIN ỨNG LƯƠNG',
preview: 'Kính gửi nhân viên ưu tú đây là bảng lương tháng 10 của bạn hãy kiểm tra nếu có thắc...',
preview:
'Kính gửi nhân viên ưu tú đây là bảng lương tháng 10 của bạn hãy kiểm tra nếu có thắc...',
date: yesterday,
isRead: false,
hasAttachment: true,
avatar: 'https://via.placeholder.com/40'
avatar: 'https://via.placeholder.com/40',
},
{
id: 4,
sender: 'Trần Thị Mai',
subject: 'Thông báo họp tuần',
preview: 'Cuộc họp tuần sẽ được tổ chức vào thứ 2 tuần tới lúc 9h00 sáng tại phòng họp A...',
preview:
'Cuộc họp tuần sẽ được tổ chức vào thứ 2 tuần tới lúc 9h00 sáng tại phòng họp A...',
date: weekAgo,
isRead: true,
hasAttachment: false,
avatar: 'https://via.placeholder.com/40'
avatar: 'https://via.placeholder.com/40',
},
{
id: 5,
sender: 'Phòng Nhân Sự',
subject: 'Thông báo nghỉ lễ',
preview: 'Công ty thông báo lịch nghỉ lễ Quốc Khánh 2/9 từ ngày 31/8 đến 3/9...',
preview:
'Công ty thông báo lịch nghỉ lễ Quốc Khánh 2/9 từ ngày 31/8 đến 3/9...',
date: monthAgo,
isRead: true,
hasAttachment: false,
avatar: 'https://via.placeholder.com/40'
}
avatar: 'https://via.placeholder.com/40',
},
];
};
// Logic để format ngày hiển thị
const formatEmailDate = (emailDate) => {
const formatEmailDate = emailDate => {
const today = new Date();
const yesterday = new Date(today);
yesterday.setDate(yesterday.getDate() - 1);
// Reset time để so sánh chỉ ngày
const emailDateOnly = new Date(emailDate.getFullYear(), emailDate.getMonth(), emailDate.getDate());
const todayOnly = new Date(today.getFullYear(), today.getMonth(), today.getDate());
const yesterdayOnly = new Date(yesterday.getFullYear(), yesterday.getMonth(), yesterday.getDate());
const emailDateOnly = new Date(
emailDate.getFullYear(),
emailDate.getMonth(),
emailDate.getDate(),
);
const todayOnly = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate(),
);
const yesterdayOnly = new Date(
yesterday.getFullYear(),
yesterday.getMonth(),
yesterday.getDate(),
);
if (emailDateOnly.getTime() === todayOnly.getTime()) {
return 'Hôm nay';
......@@ -91,14 +108,14 @@ const EmailHome = (props) => {
const day = emailDate.getDate().toString().padStart(2, '0');
const month = (emailDate.getMonth() + 1).toString().padStart(2, '0');
const year = emailDate.getFullYear();
return `${day}/${month}/${year}`;
}
};
//Nhóm các email trong danh sách theo ngày trả về một đối tượng trong đó các khoá là ngày
const groupEmailsByDate = (emailList) => {
const groupEmailsByDate = emailList => {
const grouped = {};
emailList.forEach(email => {
const dateLabel = formatEmailDate(email.date);
if (!grouped[dateLabel]) {
......@@ -118,7 +135,7 @@ const EmailHome = (props) => {
}, 1000);
}, []);
const handleEmailPress = (email) => {
const handleEmailPress = email => {
console.log('Email pressed:', email.subject);
};
......@@ -134,7 +151,7 @@ const EmailHome = (props) => {
const groupedEmails = groupEmailsByDate(emails);
return (
<EmailHomeView
<EmailHomeView
emails={emails}
groupedEmails={groupedEmails}
loading={loading}
......
import React, { useState } from 'react';
import React, {useState} from 'react';
import {Text, View, StyleSheet} from 'react-native';
import SendEmailView from './view';
const SendEmail = (props) => {
const SendEmail = props => {
const [chip, setChips] = useState([]);
const handleChange = (newChips) => {
const handleChange = newChips => {
setChips(newChips);
};
const [dataList, setDataList] = useState([
['john@doe.com', 'jane@doe.com', 'tung@doe.com']
['john@doe.com', 'jane@doe.com', 'tung@doe.com'],
]);
return (
<SendEmailView handleChange={handleChange} chip={chip} dataList={dataList}/>
<SendEmailView
handleChange={handleChange}
chip={chip}
dataList={dataList}
/>
);
};
......
import { StyleSheet, Text, View } from 'react-native'
import R from '../../../assets/R'
import {StyleSheet, Text, View} from 'react-native';
import R from '../../../assets/R';
const styles = StyleSheet.create({
container:{
flex:1,
backgroundColor:R.colors.white
},
body:{
flex:1,
backgroundColor:R.colors.white,
padding:15
},
header:{
flexDirection:'row',
backgroundColor:R.colors.blue,
height:50,
alignItems:'center',
justifyContent:'space-between',
paddingHorizontal:15
},
icon:{
width:25,
height:20
},
sendButton:{
backgroundColor:R.colors.orange,
borderRadius:5,
width:90,
paddingHorizontal:5,
height:35,
alignItems:'center',
justifyContent:'space-around',
flexDirection:'row'
},
sendText:{
color:R.colors.white,
fontSize:R.fontsize.fontSizeSubTitle,
fontFamily:R.fonts.fontRegular,
fontWeight:'400',
},
iconSend:{
width:20,
height:20
},
title:{
fontSize:R.fontsize.fontSizeSubTitle,
fontFamily:R.fonts.fontMedium,
fontWeight:'600',
color:R.colors.white
},
iconClose:{
width:15,
height:15
},
inputContainer:{
flexDirection:'row',
borderBottomWidth:1,
borderColor:R.colors.grayBorderInputTextHeader,
borderRadius:5,
height:35,
alignItems:'center',
},
input:{
flex:1,
padding:0,
paddingHorizontal:10,
paddingVertical:0,
}
})
container: {
flex: 1,
backgroundColor: R.colors.white,
},
body: {
flex: 1,
backgroundColor: R.colors.white,
padding: 15,
},
header: {
flexDirection: 'row',
backgroundColor: R.colors.blue,
height: 50,
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: 15,
},
icon: {
width: 25,
height: 20,
},
sendButton: {
backgroundColor: R.colors.orange,
borderRadius: 5,
width: 90,
paddingHorizontal: 5,
height: 35,
alignItems: 'center',
justifyContent: 'space-around',
flexDirection: 'row',
},
sendText: {
color: R.colors.white,
fontSize: R.fontsize.fontSizeSubTitle,
fontFamily: R.fonts.fontRegular,
fontWeight: '400',
},
iconSend: {
width: 20,
height: 20,
},
title: {
fontSize: R.fontsize.fontSizeSubTitle,
fontFamily: R.fonts.fontMedium,
fontWeight: '600',
color: R.colors.white,
},
iconClose: {
width: 15,
height: 15,
},
inputContainer: {
flexDirection: 'row',
borderBottomWidth: 1,
borderColor: R.colors.grayBorderInputTextHeader,
borderRadius: 5,
height: 35,
alignItems: 'center',
},
input: {
flex: 1,
padding: 0,
paddingHorizontal: 10,
paddingVertical: 0,
},
});
export default styles
\ No newline at end of file
export default styles;
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