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,7 +9,6 @@ import {
} from 'react-native';
import R from '../assets/R';
const Button = props => {
const {
title,
......@@ -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,49 +11,44 @@ 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: 2,
name: 'Chuẩn trình NN',
status: true,
},
{
id:3,
name:'Quá tiến độ học tập',
status:false,
id: 3,
name: 'Quá tiến độ học tập',
status: false,
},
{
id:4,
name:'Nợ học phí',
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,
......
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,
containerCard: {
marginHorizontal: 15,
marginVertical: 5,
borderRadius: 10,
},
card:{
borderBottomEndRadius:10,
borderBottomStartRadius:10,
paddingHorizontal:10,
paddingVertical:5,
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,
containerText: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
marginBottom: 5,
},
containerTextItemLeft:{
alignItems:'flex-start',
justifyContent:'flex-start',
width:'45%',
containerTextItemLeft: {
alignItems: 'flex-start',
justifyContent: 'flex-start',
width: '45%',
},
containerTextItemRight:{
flexDirection:'row',
alignItems:'center',
justifyContent:'center',
containerTextItemRight: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
sizedBox:{
flex:3
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
text: {
fontSize: R.sizes.sm,
fontFamily: R.fonts.fontMedium,
fontWeight: '600',
color: R.colors.black,
textAlign: 'center',
},
containerSubTextItemLeft:{
},
containerSubTextItemRight:{
containerSubText: {
flexDirection: 'row',
marginBottom: 5,
},
textTitle:{
fontSize:R.sizes.md,
fontFamily:R.fonts.fontMedium,
fontWeight:'600',
color:R.colors.blue,
marginHorizontal:15,
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,
label: {
fontSize: R.sizes.sm,
fontFamily: R.fonts.fontMedium,
fontWeight: '600',
color: R.colors.black,
},
checkboxContainer: {
flexDirection: 'row',
......@@ -81,7 +79,6 @@ const styles = StyleSheet.create({
width: '50%',
marginBottom: 15,
},
});
})
export default styles
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,8 +151,14 @@ 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 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={[
{
......@@ -155,8 +166,8 @@ const DetailStudentView = props => {
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={[
{
......
......@@ -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,7 +61,7 @@ const styles = StyleSheet.create({
},
body: {
flex:1,
flex: 1,
},
listContainer: {
paddingBottom: 20,
......@@ -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>
......
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,
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',
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,
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,
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_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',
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,
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',
containerEmpty: {
alignItems: 'center',
justifyContent: 'center',
},
sizedBox:{
width:'35%',
textEmpty: {
color: R.colors.black,
fontSize: R.fontsize.fontSizeSubTitle,
fontWeight: '500',
fontFamily: R.fonts.fontMedium,
},
containerButton:{
alignItems:'flex-end',
}
})
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 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 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 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 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}>
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 style={styles.text_title}>
Lp trưởng: <Text style={styles.text}>{item.class_leader}</Text>
</Text>
<View style={styles.containerButton}>
<Button
......@@ -60,15 +55,16 @@ const ClassActivityView = props => {
</View>
);
};
const renderItemEmpty = () => {
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>
<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}
......@@ -76,9 +72,35 @@ const ClassActivityView = props => {
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>
);
};
export default ClassActivityView;
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: {
......@@ -30,12 +30,13 @@ const styles = StyleSheet.create({
fontFamily: R.fonts.fontRegular,
color: R.colors.black,
},
icon:{
width:20,
height:15,
icon: {
width: 20,
height: 15,
},
info:{
paddingHorizontal: 15, paddingVertical: 5
}
})
export default styles
\ No newline at end of file
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}
>
<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);
......@@ -158,7 +176,7 @@ const Filter3Day = ({navigation}) => {
const topPosition = (startTotalMinutes / 60) * HOUR_HEIGHT;
const height = (durationMinutes / 60) * HOUR_HEIGHT;
return { topPosition, height };
return {topPosition, height};
};
return (
......
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',
......
......@@ -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>
......@@ -67,19 +67,22 @@ const Filter3DayView = (props) => {
return (
<View key={index} style={styles.dayHeaderCell}>
<Text style={[
<Text
style={[
styles.dayHeaderText,
isTodayDate && styles.todayHeaderText
isTodayDate && styles.todayHeaderText,
]}>
{getDayName(date)}
</Text>
<View style={[
<View
style={[
styles.dayNumberContainer,
isTodayDate && styles.todayNumberContainer
isTodayDate && styles.todayNumberContainer,
]}>
<Text style={[
<Text
style={[
styles.dayHeaderNumber,
isTodayDate && styles.todayHeaderNumber
isTodayDate && styles.todayHeaderNumber,
]}>
{date.getDate()}
</Text>
......@@ -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,12 +119,15 @@ 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
......@@ -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Ố ====================
......@@ -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);
......
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,17 +59,22 @@ const FilterWeekView = ({
return (
<View key={index} style={styles.dayHeaderCell}>
<Text style={[
<Text
style={[
styles.dayHeaderText,
isCurrentDay && styles.dayHeaderTextToday
isCurrentDay && styles.dayHeaderTextToday,
]}>
{getDayName(date)}
</Text>
<View style={isCurrentDay ? styles.dayHeaderNumberContainerToday : {}}>
<Text style={[
<View
style={
isCurrentDay ? styles.dayHeaderNumberContainerToday : {}
}>
<Text
style={[
styles.dayHeaderNumber,
isCurrentDay && styles.dayHeaderNumberToday
isCurrentDay && styles.dayHeaderNumberToday,
]}>
{date.getDate()}
</Text>
......@@ -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;
......@@ -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);
......@@ -126,7 +136,7 @@ const FilterDay = ({navigation}) => {
const topPosition = (startTotalMinutes / 60) * HOUR_HEIGHT;
const height = (durationMinutes / 60) * HOUR_HEIGHT;
return { topPosition, height };
return {topPosition, height};
};
return (
......@@ -143,7 +153,6 @@ const FilterDay = ({navigation}) => {
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,
......
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 FilterDayView = props => {
const {
selectedDate,
showMonthPicker,
......@@ -16,9 +11,10 @@ const FilterDayView = (props) => {
panResponder,
getEventsForDate,
getDayName,
calculateEventPosition, } = props;
calculateEventPosition,
} = props;
const isToday = (date) => {
const isToday = date => {
const today = new Date();
return (
date.getDate() === today.getDate() &&
......@@ -28,22 +24,21 @@ const FilterDayView = (props) => {
};
const renderMonthPicker = () => {
if (!showMonthPicker) return null;
}
};
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>
<Text
style={
isToday(selectedDate) ? styles.dayNumberToday : styles.dayNumber
}>
{selectedDate.getDate()}
</Text>
</View>
</View>
);
};
......@@ -57,10 +52,9 @@ const FilterDayView = (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}>
......@@ -71,12 +65,15 @@ const FilterDayView = (props) => {
</View>
<View style={styles.eventsColumn}>
{hours.map((hour) => (
{hours.map(hour => (
<View key={hour} style={styles.gridLine} />
))}
{selectedEvents.map((event) => {
const { topPosition, height } = calculateEventPosition(event.time, event.endTime);
{selectedEvents.map(event => {
const {topPosition, height} = calculateEventPosition(
event.time,
event.endTime,
);
return (
<TouchableOpacity
......@@ -91,10 +88,12 @@ const FilterDayView = (props) => {
right: 15,
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 && (
......
......@@ -16,11 +16,13 @@ const ClassSchedule = ({events = [], onDateSelect, onEventPress}) => {
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,7 +294,7 @@ 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);
......@@ -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);
};
......
......@@ -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 (
......@@ -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,15 +176,16 @@ const ClassScheduleView = ({
<View style={styles.noEventsContainer}>
<Text style={styles.noEventsText}>Không có s kin nào</Text>
</View>
) :
(selectedEvents.map((event, index) => (
) : (
selectedEvents.map((event, index) => (
<View style={styles.containerBottomSheet}>
<TouchableOpacity
key={event.id}
style={styles.eventCard}
onPress={() => navigation.navigate(SCREENNAME.DETAILSCHEDULE, { event })}
onPress={() =>
navigation.navigate(SCREENNAME.DETAILSCHEDULE, {event})
}
activeOpacity={0.7}>
<View style={styles.eventTimeContainer}>
<Text style={styles.eventTime}>
{event.time}
......@@ -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;
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 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},
......@@ -40,9 +40,7 @@ const Compensate = (props) => {
{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} />
);
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 DetailCompensate = props => {
const [item, setItem] = useState({
rest: 5,
compensate: 0,
......@@ -17,148 +17,152 @@ const DetailCompensate = (props) => {
const [listData, setDataList] = useState([
{
id:1,
date:'2024-01-01',
status:'Đã xác nhận',
dayOfWeek:'Thứ 2',
periods:[
id: 1,
date: '2024-01-01',
status: 'Đã xác nhận',
dayOfWeek: 'Thứ 2',
periods: [
{
id:1,
time:'6',
id: 1,
time: '6',
},
{
id:2,
time:'7',
id: 2,
time: '7',
},
{
id:3,
time:'8',
id: 3,
time: '8',
},
{
id:4,
time:'9',
}
id: 4,
time: '9',
},
],
dateStudy:'30/07/2025',
location:'Phòng B2.12',
teacher:'Nguyễn Minh Đức',
note:'',
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: 2,
date: '2024-01-01',
status: 'Chờ phê duyệt',
dayOfWeek: 'Thứ 2',
periods: [
{
id:1,
time:'6',
id: 1,
time: '6',
},
{
id:2,
time:'7',
id: 2,
time: '7',
},
{
id:3,
time:'8',
id: 3,
time: '8',
},
{
id:4,
time:'9',
}
id: 4,
time: '9',
},
],
dateStudy:'30/07/2025',
location:'Phòng B2.12',
teacher:'',
note:'',
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: 3,
date: '2024-01-01',
status: 'Từ chối',
dayOfWeek: 'Thứ 2',
periods: [
{
id:1,
time:'6',
id: 1,
time: '6',
},
{
id:2,
time:'7',
id: 2,
time: '7',
},
{
id:3,
time:'8',
id: 3,
time: '8',
},
{
id:4,
time:'9',
}
id: 4,
time: '9',
},
],
dateStudy:'30/07/2025',
location:'Phòng B2.12',
teacher:'',
note:'',
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: 4,
date: '2024-01-01',
status: 'Đã xác nhận',
dayOfWeek: 'Thứ 2',
periods: [
{
id:1,
time:'6',
id: 1,
time: '6',
},
{
id:2,
time:'7',
id: 2,
time: '7',
},
{
id:3,
time:'8',
id: 3,
time: '8',
},
{
id:4,
time:'9',
}
id: 4,
time: '9',
},
],
dateStudy:'30/07/2025',
location:'Phòng B2.12',
teacher:'',
note:'',
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: 5,
date: '2024-01-01',
status: 'Đã xác nhận',
dayOfWeek: 'Thứ 2',
periods: [
{
id:1,
time:'6',
id: 1,
time: '6',
},
{
id:2,
time:'7',
id: 2,
time: '7',
},
{
id:3,
time:'8',
id: 3,
time: '8',
},
{
id:4,
time:'9',
}
id: 4,
time: '9',
},
],
dateStudy:'30/07/2025',
location:'Phòng B2.12',
teacher:'',
note:'',
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
container: {
flex: 1,
backgroundColor: R.colors.white,
},
body:{
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,
text: {
fontSize: R.fontsize.fontSizeSubTitle,
fontFamily: R.fonts.fontRegular,
fontWeight: '400',
color: R.colors.black,
},
card:{
borderRadius:10,
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,
}
})
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,41 +86,103 @@ 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:{' '}
<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}
- 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={()=>{}}
title="Huỷ"
onPress={() => {}}
backgroundColor={R.colors.orange}
textColor={R.colors.white}
height={25}
......@@ -101,8 +194,7 @@ const DetailCompensateView = (props) => {
paddingHorizontal={15}
/>
</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);
const total_width_table = width_first + width_second * period_count;
const styles = StyleSheet.create({
container:{
flex:1,
backgroundColor:R.colors.white,
container: {
flex: 1,
backgroundColor: R.colors.white,
},
body:{
flex:1,
backgroundColor:R.colors.white,
padding:15,
body: {
flex: 1,
backgroundColor: R.colors.white,
padding: 15,
},
containerInput:{
flexDirection:'row',
justifyContent:'space-between',
marginBottom:15
containerInput: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 15,
},
txtSubtitle:{
fontWeight:'600',
fontFamily:R.fonts.fontMedium,
fontSize:R.fontsize.fontSizeLabel,
color:R.colors.black,
txtSubtitle: {
fontWeight: '600',
fontFamily: R.fonts.fontMedium,
fontSize: R.fontsize.fontSizeLabel,
color: R.colors.black,
},
containerDropDown:{
marginBottom:15
containerDropDown: {
marginBottom: 15,
},
btnRegister:{
alignItems:'flex-end',
btnRegister: {
alignItems: 'flex-end',
},
btnRegister2:{
marginVertical:15
btnRegister2: {
marginVertical: 15,
},
//Header bảng lịch
tableContainer:{
marginTop:15,
borderWidth:1,
borderColor:R.colors.gray,
width:total_width_table,
tableContainer: {
marginTop: 15,
borderWidth: 1,
borderColor: R.colors.gray,
width: total_width_table,
},
headerRow: {
......@@ -62,41 +62,41 @@ container:{
},
dateColumn: {
height: 40,
width:width_first,
width: width_first,
paddingHorizontal: 10,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: R.colors.blue2,
borderRightWidth:1,
borderRightColor:R.colors.gray,
borderRightWidth: 1,
borderRightColor: R.colors.gray,
},
periodColumn: {
height: 40,
width:width_second,
width: width_second,
paddingHorizontal: 5,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: R.colors.blue2,
borderRightWidth:1,
borderRightColor:R.colors.gray,
borderRightWidth: 1,
borderRightColor: R.colors.gray,
},
dateBody:{
dateBody: {
width: width_first,
minHeight: 40,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: R.colors.white,
borderRightWidth:1,
borderRightColor:R.colors.gray,
borderRightWidth: 1,
borderRightColor: R.colors.gray,
},
periodBody:{
periodBody: {
width: width_second,
padding:5,
padding: 5,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: R.colors.white,
borderRightWidth:1,
borderRightColor:R.colors.gray,
borderRightWidth: 1,
borderRightColor: R.colors.gray,
},
dataRow: {
flexDirection: 'row',
......@@ -111,25 +111,23 @@ container:{
minHeight: 50,
width: '100%',
},
dateText:{
dateText: {
fontSize: R.sizes.sm,
fontWeight: '400',
fontFamily: R.fonts.fontRegular,
color: R.colors.black,
},
percentText:{
percentText: {
fontSize: R.sizes.sm,
fontWeight: '500',
fontFamily: R.fonts.fontMedium,
color: R.colors.black,
},
codeText:{
codeText: {
fontSize: R.sizes.sm,
fontWeight: '500',
fontFamily: R.fonts.fontMedium,
color: R.colors.black,
},
})
export default styles
\ No newline at end of file
});
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>
))}
......@@ -68,31 +70,32 @@ const CompensateRegisterView = props => {
<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'}}>
<View style={{flexDirection: 'row'}}>
<Text
style={[
styles.percentText,
period.available && styles.availableText,
{color:getCheckColor(period)}
{color: getCheckColor(period)},
]}>
{period.percent}
</Text>
<Text
style={[
styles.codeText,
{color:getCheckColor(period), marginLeft:3},
{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,
container: {
flex: 1,
backgroundColor: R.colors.white,
},
body:{
flex:1,
backgroundColor:R.colors.white,
body: {
flex: 1,
backgroundColor: R.colors.white,
},
card: {
borderRadius: 10,
padding: 5,
marginTop: 15,
marginBottom:5,
marginBottom: 5,
marginHorizontal: 15,
alignItems: 'center',
justifyContent: 'center',
......@@ -44,7 +44,7 @@ const styles = StyleSheet.create({
containerCard: {
padding: 10,
borderRadius: 10,
marginVertical:10,
marginVertical: 10,
backgroundColor: R.colors.white,
shadowColor: R.colors.black,
shadowOffset: {width: 0, height: 2},
......@@ -62,18 +62,17 @@ const styles = StyleSheet.create({
},
btnRight: {},
btnRegister:{
borderRadius:10,
alignItems:'center',
justifyContent:'center',
marginHorizontal:15,
marginVertical:10,
backgroundColor:R.colors.blue,
borderRadius:10,
padding:5,
height:35
}
})
btnRegister: {
borderRadius: 10,
alignItems: 'center',
justifyContent: 'center',
marginHorizontal: 15,
marginVertical: 10,
backgroundColor: R.colors.blue,
borderRadius: 10,
padding: 5,
height: 35,
},
});
export default styles
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,8 +98,12 @@ 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
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:{' '}
<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 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 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 style={styles.textTitleMail}>
TO: <Text style={styles.textSubMail}>{incoming_document.to}</Text>
</Text>
</ScrollView>
</View>
)
}
);
};
const renderButton =(
{
const renderButton = ({
title,
onPress,
style,
icon,
textStyle,
iconRight,
}
)=>{
return(
}) => {
return (
<TouchableOpacity style={style} onPress={onPress}>
<View style={{flexDirection:'row', alignItems:'center', justifyContent:'center', marginHorizontal:10,}}>
<Image
source={icon}
style={styles.iconReply}
resizeMode="contain"
/>
<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={iconRight}
style={[styles.iconForward, { transform: [{ rotateY: '180deg' }] }]}
style={[styles.iconForward, {transform: [{rotateY: '180deg'}]}]}
resizeMode="contain"
/>
</View>
</TouchableOpacity>
)
}
);
};
const renderBody = () => {
return (
......@@ -102,16 +102,16 @@ const DetailEmailView = props => {
<Text style={styles.name}>{incoming_document.name}</Text>
<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,
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);
......@@ -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';
......@@ -96,7 +113,7 @@ const EmailHome = (props) => {
}
};
//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 => {
......@@ -118,7 +135,7 @@ const EmailHome = (props) => {
}, 1000);
}, []);
const handleEmailPress = (email) => {
const handleEmailPress = email => {
console.log('Email pressed:', email.subject);
};
......
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
container: {
flex: 1,
backgroundColor: R.colors.white,
},
body:{
flex:1,
backgroundColor:R.colors.white,
padding:15
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
header: {
flexDirection: 'row',
backgroundColor: R.colors.blue,
height: 50,
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: 15,
},
icon:{
width:25,
height:20
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'
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',
sendText: {
color: R.colors.white,
fontSize: R.fontsize.fontSizeSubTitle,
fontFamily: R.fonts.fontRegular,
fontWeight: '400',
},
iconSend:{
width:20,
height:20
iconSend: {
width: 20,
height: 20,
},
title:{
fontSize:R.fontsize.fontSizeSubTitle,
fontFamily:R.fonts.fontMedium,
fontWeight:'600',
color:R.colors.white
title: {
fontSize: R.fontsize.fontSizeSubTitle,
fontFamily: R.fonts.fontMedium,
fontWeight: '600',
color: R.colors.white,
},
iconClose:{
width:15,
height:15
iconClose: {
width: 15,
height: 15,
},
inputContainer:{
flexDirection:'row',
borderBottomWidth:1,
borderColor:R.colors.grayBorderInputTextHeader,
borderRadius:5,
height:35,
alignItems:'center',
inputContainer: {
flexDirection: 'row',
borderBottomWidth: 1,
borderColor: R.colors.grayBorderInputTextHeader,
borderRadius: 5,
height: 35,
alignItems: 'center',
},
input:{
flex:1,
padding:0,
paddingHorizontal:10,
paddingVertical:0,
}
})
input: {
flex: 1,
padding: 0,
paddingHorizontal: 10,
paddingVertical: 0,
},
});
export default styles
\ No newline at end of file
export default styles;
import React from 'react';
import {Text, View, TouchableOpacity, StyleSheet, Image, TextInput} from 'react-native';
import {
Text,
View,
TouchableOpacity,
Image,
TextInput,
} from 'react-native';
import styles from './style';
import R from '../../../assets/R';
import Button from '../../../components/Button';
import { useNavigation } from '@react-navigation/native';
import {useNavigation} from '@react-navigation/native';
import EmailChipInput from '../../../components/Chip/EmailChipInput';
import TextMulti from '../../../components/Input/TextMulti';
import TextField from '../../../components/Input/TextField';
const SendEmailView = (props) => {
const { handleChange, chip, dataList } = props;
const SendEmailView = props => {
const {handleChange, chip, dataList} = props;
const navigation = useNavigation();
const navigation = useNavigation();
const renderHeader = () => {
const renderHeader = () => {
return (
<View style={styles.header}>
<TouchableOpacity onPress={() => navigation.goBack()}>
<Image source={R.images.icBack} style={styles.icon}/>
<Image source={R.images.icBack} style={styles.icon} />
</TouchableOpacity>
<Text style={styles.title}>Son email</Text>
<TouchableOpacity onPress={() => (navigation.goBack())} style={styles.sendButton}>
<TouchableOpacity
onPress={() => navigation.goBack()}
style={styles.sendButton}>
<Text style={styles.sendText}>Gi Đi</Text>
<Image source={R.images.icSend} style={styles.iconSend} tintColor={R.colors.white}/>
<Image
source={R.images.icSend}
style={styles.iconSend}
tintColor={R.colors.white}
/>
</TouchableOpacity>
</View>
);
}
};
return (
<View
style={styles.container}>
<View style={styles.container}>
{renderHeader()}
<View style={styles.body}>
<EmailChipInput
......@@ -38,16 +46,20 @@ const renderHeader = () => {
delimiters={dataList}
entries={chip}
onSubmit={handleChange}
chipContainerStyle={{ backgroundColor: R.colors.blue4}}
chipTextStyle={{ color:R.colors.black }}
chipContainerStyle={{backgroundColor: R.colors.blue4}}
chipTextStyle={{color: R.colors.black}}
containerStyle={{
borderBottomWidth:1,
borderBottomWidth: 1,
borderColor: R.colors.grayBorderInputTextHeader,
borderRadius: 5,
marginBottom:10
marginBottom: 10,
}}
chipImage={
<Image source={R.images.icCancel} style={styles.iconClose} tintColor={R.colors.black}/>
<Image
source={R.images.icCancel}
style={styles.iconClose}
tintColor={R.colors.black}
/>
}
/>
<EmailChipInput
......@@ -55,16 +67,20 @@ const renderHeader = () => {
delimiters={dataList}
entries={chip}
onSubmit={handleChange}
chipContainerStyle={{ backgroundColor: R.colors.blue4}}
chipTextStyle={{ color:R.colors.black }}
chipContainerStyle={{backgroundColor: R.colors.blue4}}
chipTextStyle={{color: R.colors.black}}
containerStyle={{
borderBottomWidth:1,
borderBottomWidth: 1,
borderColor: R.colors.grayBorderInputTextHeader,
borderRadius: 5,
marginBottom:10
marginBottom: 10,
}}
chipImage={
<Image source={R.images.icCancel} style={styles.iconClose} tintColor={R.colors.black}/>
<Image
source={R.images.icCancel}
style={styles.iconClose}
tintColor={R.colors.black}
/>
}
/>
<EmailChipInput
......@@ -72,16 +88,20 @@ const renderHeader = () => {
delimiters={dataList}
entries={chip}
onSubmit={handleChange}
chipContainerStyle={{ backgroundColor: R.colors.blue4}}
chipTextStyle={{ color:R.colors.black }}
chipContainerStyle={{backgroundColor: R.colors.blue4}}
chipTextStyle={{color: R.colors.black}}
containerStyle={{
borderBottomWidth:1,
borderBottomWidth: 1,
borderColor: R.colors.grayBorderInputTextHeader,
borderRadius: 5,
marginBottom:10
marginBottom: 10,
}}
chipImage={
<Image source={R.images.icCancel} style={styles.iconClose} tintColor={R.colors.black}/>
<Image
source={R.images.icCancel}
style={styles.iconClose}
tintColor={R.colors.black}
/>
}
/>
<EmailChipInput
......@@ -89,20 +109,29 @@ const renderHeader = () => {
delimiters={dataList}
entries={chip}
onSubmit={handleChange}
chipContainerStyle={{ backgroundColor: R.colors.blue4}}
chipTextStyle={{ color:R.colors.black }}
chipContainerStyle={{backgroundColor: R.colors.blue4}}
chipTextStyle={{color: R.colors.black}}
containerStyle={{
borderBottomWidth:1,
borderBottomWidth: 1,
borderColor: R.colors.grayBorderInputTextHeader,
borderRadius: 5,
marginBottom:10
marginBottom: 10,
}}
chipImage={
<Image source={R.images.icCancel} style={styles.iconClose} tintColor={R.colors.black}/>
<Image
source={R.images.icCancel}
style={styles.iconClose}
tintColor={R.colors.black}
/>
}
/>
<View style={styles.inputContainer}>
<Text style={{fontSize:12, color:R.colors.black, fontFamily:R.fonts.fontMedium}}>
<Text
style={{
fontSize: 12,
color: R.colors.black,
fontFamily: R.fonts.fontMedium,
}}>
Subject
</Text>
<TextInput
......@@ -110,16 +139,22 @@ const renderHeader = () => {
style={styles.input}
/>
</View>
<View style={[ {height:100, marginTop:10}]}>
<View style={[{height: 100, marginTop: 10}]}>
<TextInput
placeholderTextColor={R.colors.gray}
style={[styles.input , {paddingHorizontal:10 ,borderBottomWidth:1 ,borderColor:R.colors.grayBorderInputTextHeader}]}
style={[
styles.input,
{
paddingHorizontal: 10,
borderBottomWidth: 1,
borderColor: R.colors.grayBorderInputTextHeader,
},
]}
multiline={true}
numberOfLines={5}
textAlignVertical='top'
textAlignVertical="top"
/>
</View>
</View>
</View>
);
......
import { StyleSheet } from 'react-native'
import R from '../../assets/R'
import {StyleSheet} from 'react-native';
import R from '../../assets/R';
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: R.colors.white
backgroundColor: R.colors.white,
},
loadingContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: R.colors.white
backgroundColor: R.colors.white,
},
loadingText: {
marginTop: 10,
fontSize: R.fontsize.fontSizeSubTitle,
fontFamily: R.fonts.fontMedium,
color: R.colors.gray2
},
listContainer: {
color: R.colors.gray2,
},
listContainer: {},
dateSection: {
marginBottom: 10,
},
......@@ -36,13 +35,12 @@ const styles = StyleSheet.create({
paddingHorizontal: 15,
paddingVertical: 10,
backgroundColor: R.colors.white,
alignItems: 'flex-start'
},
unreadEmail: {
alignItems: 'flex-start',
},
unreadEmail: {},
avatarContainer: {
marginRight: 10,
marginTop: 5
marginTop: 5,
},
avatar: {
width: 40,
......@@ -50,16 +48,16 @@ const styles = StyleSheet.create({
borderRadius: 20,
backgroundColor: R.colors.blue,
justifyContent: 'center',
alignItems: 'center'
alignItems: 'center',
},
avatarText: {
color: R.colors.white,
fontSize: 16,
fontWeight: 'bold'
fontWeight: 'bold',
},
emailContent: {
flex: 1,
marginRight: 10
marginRight: 10,
},
emailHeader: {
flexDirection: 'row',
......@@ -68,25 +66,25 @@ const styles = StyleSheet.create({
},
senderName: {
fontSize: R.fontsize.fontsSizeTitle,
fontWeight:'400',
fontWeight: '400',
fontFamily: R.fonts.fontRegular,
color: R.colors.gray4,
flex: 1,
marginRight: 10
marginRight: 10,
},
unreadText: {
fontWeight: '600',
fontFamily: R.fonts.fontMedium,
color: R.colors.black
color: R.colors.black,
},
unreadEmail: {
fontWeight: '600',
fontFamily: R.fonts.fontMedium,
color: R.colors.gray3
color: R.colors.gray3,
},
emailDate: {
fontSize: R.fontsize.fontSizeContent,
color: R.colors.gray2
color: R.colors.gray2,
},
emailSubject: {
fontSize: R.fontsize.fontSizeBtn,
......@@ -103,7 +101,7 @@ const styles = StyleSheet.create({
backgroundColor: R.colors.blue3,
justifyContent: 'center',
alignItems: 'center',
marginTop: 4
marginTop: 4,
},
attachmentCount: {
color: R.colors.blue,
......@@ -122,7 +120,7 @@ const styles = StyleSheet.create({
bottom: 5,
width: 95,
backgroundColor: R.colors.red,
borderRadius:25,
borderRadius: 25,
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'column',
......@@ -145,7 +143,7 @@ const styles = StyleSheet.create({
fontSize: R.fontsize.fontSizeContent,
fontFamily: R.fonts.fontMedium,
fontWeight: '600',
}
})
},
});
export default styles
\ No newline at end of file
export default styles;
......@@ -16,10 +16,11 @@ import FAB from '../../components/FAB/fab';
import SubButton from '../../components/FAB/sub_button';
import R from '../../assets/R';
import * as SCREENNAME from '../../routers/ScreenNames';
import { useNavigation } from '@react-navigation/native';
import {useNavigation} from '@react-navigation/native';
const EmailHomeView = props => {
const {groupedEmails, loading, onEmailPress, onRefresh, formatEmailDate} = props;
const {groupedEmails, loading, onEmailPress, onRefresh, formatEmailDate} =
props;
const navigation = useNavigation();
const screenWidth = Dimensions.get('window').width;
......@@ -27,7 +28,6 @@ const EmailHomeView = props => {
const [localGroupedEmails, setLocalGroupedEmails] = useState(groupedEmails);
const [swipedEmailId, setSwipedEmailId] = useState(null);
// Update local state when props change
React.useEffect(() => {
setLocalGroupedEmails(groupedEmails);
}, [groupedEmails]);
......@@ -45,7 +45,6 @@ const EmailHomeView = props => {
const translateX = useRef(new Animated.Value(0)).current;
const deleteThreshold = screenWidth * 0.3;
// Reset position when another email is swiped
React.useEffect(() => {
if (swipedEmailId !== null && swipedEmailId !== item.id) {
Animated.spring(translateX, {
......@@ -66,8 +65,12 @@ const EmailHomeView = props => {
},
onPanResponderMove: (evt, gestureState) => {
// console.log('gestureState L2', gestureState.dx);
if (gestureState.vx < 0 && gestureState.dx > -100 && gestureState.dx < 0) {
console.log('gestureState L2', gestureState.dx, gestureState.vx,);
if (
gestureState.vx < 0 &&
gestureState.dx > -100 &&
gestureState.dx < 0
) {
console.log('gestureState L2', gestureState.dx, gestureState.vx);
translateX.setValue(-100);
setSwipedEmailId(item.id);
} else {
......@@ -82,7 +85,7 @@ const EmailHomeView = props => {
onPanResponderRelease: (evt, gestureState) => {
// console.log('gestureState L3', gestureState);
if (Math.abs(gestureState.dx) >= 0 && gestureState.vx === 0) {
console.log('gestureState L3', gestureState.dx, gestureState.vx,);
console.log('gestureState L3', gestureState.dx, gestureState.vx);
// // Nếu di chuyển đủ lớn, vuốt để xóa
// if (gestureState.dx < -deleteThreshold ) {
// // Hiển thị nút xóa
......@@ -103,7 +106,7 @@ const EmailHomeView = props => {
// }
navigation.navigate(SCREENNAME.DETAILEMAIL);
}
}
// } else {
// // Nếu không có chuyển động đủ lớn (chỉ bấm), chuyển tới màn hình chi tiết
// navigation.navigate(SCREENNAME.DETAILEMAIL);
......@@ -124,7 +127,6 @@ const EmailHomeView = props => {
};
const handleCancelPress = () => {
// Snap back to original position
Animated.spring(translateX, {
toValue: 0,
useNativeDriver: true,
......@@ -133,7 +135,6 @@ const EmailHomeView = props => {
});
};
const handleEmailPress = () => {
// Chỉ điều hướng nếu email chưa bị vuốt
if (swipedEmailId === null) {
navigation.navigate(SCREENNAME.DETAILEMAIL);
}
......@@ -141,18 +142,16 @@ const EmailHomeView = props => {
return (
<View style={styles.swipeContainer}>
{/* Delete background */}
<Animated.View style={[styles.deleteBackground, {opacity: deleteOpacity}]}>
<Animated.View
style={[styles.deleteBackground, {opacity: deleteOpacity}]}>
<TouchableOpacity
style={styles.deleteButton}
onPress={handleDeletePress}
>
onPress={handleDeletePress}>
<Image source={R.images.icDelete} style={styles.deleteIcon} />
<Text style={styles.deleteText}>Xóa</Text>
</TouchableOpacity>
</Animated.View>
{/* Email item */}
<Animated.View
style={[{transform: [{translateX}]}]}
{...panResponder.panHandlers}>
......@@ -169,7 +168,11 @@ const EmailHomeView = props => {
<View style={styles.emailContent}>
<View style={styles.emailHeader}>
<Text style={[styles.senderName, !item.isRead && styles.unreadText]}>
<Text
style={[
styles.senderName,
!item.isRead && styles.unreadText,
]}>
{item.sender}
</Text>
</View>
......@@ -181,7 +184,10 @@ const EmailHomeView = props => {
</Text>
<Text
style={[styles.emailPreview, !item.isRead && styles.unreadEmail]}
style={[
styles.emailPreview,
!item.isRead && styles.unreadEmail,
]}
numberOfLines={2}>
{item.preview}
</Text>
......@@ -214,12 +220,13 @@ const EmailHomeView = props => {
);
};
const handleDeleteEmail = (emailId) => {
// Remove email from local state temporarily
const handleDeleteEmail = emailId => {
const updatedGroupedEmails = {};
Object.keys(localGroupedEmails).forEach(dateKey => {
const filteredEmails = localGroupedEmails[dateKey].filter(email => email.id !== emailId);
const filteredEmails = localGroupedEmails[dateKey].filter(
email => email.id !== emailId,
);
if (filteredEmails.length > 0) {
updatedGroupedEmails[dateKey] = filteredEmails;
}
......@@ -270,7 +277,6 @@ const EmailHomeView = props => {
backgroundColor={R.colors.orange}
/>
</FAB>
</View>
);
};
......
......@@ -26,42 +26,289 @@ const DetailFeedBack = props => {
{
id: '4',
question: 'Sự hỗ trợ của giảng viên trong và ngoài giờ?',
}
},
],
results: [
{ "id": 1, "Q1": 4, "Q2": 4, "Q3": 4, "Q4": 4, "GPA": 4, "comment": "Tuyệt vời" },
{ "id": 2, "Q1": 4, "Q2": 4, "Q3": 4, "Q4": 4, "GPA": 4, "comment": "Học với thầy em cảm thấy tiếp thu được nhiều và bổ ích" },
{ "id": 3, "Q1": 4, "Q2": 4, "Q3": 4, "Q4": 4, "GPA": 4, "comment": "Giảng viên giảng dễ hiểu, tận tình" },
{ "id": 4, "Q1": 4, "Q2": 4, "Q3": 4, "Q4": 4, "GPA": 4, "comment": "Bài giảng rõ ràng, mạch lạc" },
{ "id": 5, "Q1": 3, "Q2": 4, "Q3": 4, "Q4": 3, "GPA": 3.5, "comment": "Một số chỗ hơi nhanh, cần giảng chậm lại" },
{ "id": 6, "Q1": 4, "Q2": 3, "Q3": 4, "Q4": 4, "GPA": 3.75, "comment": "Ổn nhưng cần thêm ví dụ thực tế" },
{ "id": 7, "Q1": 4, "Q2": 4, "Q3": 3, "Q4": 4, "GPA": 3.75, "comment": "Rất dễ hiểu, nên có thêm bài tập nhóm" },
{ "id": 8, "Q1": 4, "Q2": 4, "Q3": 4, "Q4": 3, "GPA": 3.75, "comment": "Phong cách giảng dạy gần gũi" },
{ "id": 9, "Q1": 4, "Q2": 3, "Q3": 3, "Q4": 4, "GPA": 3.5, "comment": "Hài hước, dễ tiếp thu" },
{ "id": 10, "Q1": 4, "Q2": 4, "Q3": 4, "Q4": 4, "GPA": 4, "comment": "Rất tận tình và hỗ trợ sinh viên" },
{ "id": 11, "Q1": 3, "Q2": 4, "Q3": 4, "Q4": 3, "GPA": 3.5, "comment": "Nên chậm lại phần kiến thức nâng cao" },
{ "id": 12, "Q1": 4, "Q2": 4, "Q3": 3, "Q4": 4, "GPA": 3.75, "comment": "Cách giải thích dễ hiểu" },
{ "id": 13, "Q1": 4, "Q2": 4, "Q3": 4, "Q4": 4, "GPA": 4, "comment": "Giảng viên nhiệt huyết" },
{ "id": 14, "Q1": 4, "Q2": 4, "Q3": 3, "Q4": 3, "GPA": 3.5, "comment": "Có thêm tài liệu tham khảo thì tốt" },
{ "id": 15, "Q1": 4, "Q2": 3, "Q3": 4, "Q4": 4, "GPA": 3.75, "comment": "Thầy luôn trả lời câu hỏi tận tình" },
{ "id": 16, "Q1": 4, "Q2": 4, "Q3": 3, "Q4": 4, "GPA": 3.75, "comment": "Nội dung sát thực tế" },
{ "id": 17, "Q1": 3, "Q2": 4, "Q3": 4, "Q4": 3, "GPA": 3.5, "comment": "Bài giảng cần nhiều ví dụ minh họa hơn" },
{ "id": 18, "Q1": 4, "Q2": 4, "Q3": 4, "Q4": 3, "GPA": 3.75, "comment": "Phong thái chuyên nghiệp" },
{ "id": 19, "Q1": 4, "Q2": 4, "Q3": 4, "Q4": 4, "GPA": 4, "comment": "Rất dễ hiểu, rõ ràng" },
{ "id": 20, "Q1": 4, "Q2": 4, "Q3": 3, "Q4": 3, "GPA": 3.5, "comment": "Một số phần khó nhưng thầy đã hỗ trợ nhiều" },
{ "id": 21, "Q1": 4, "Q2": 4, "Q3": 4, "Q4": 4, "GPA": 4, "comment": "Không khí lớp học vui vẻ" },
{ "id": 22, "Q1": 4, "Q2": 3, "Q3": 4, "Q4": 3, "GPA": 3.5, "comment": "Có thể tăng thêm thời gian luyện tập" },
{ "id": 23, "Q1": 4, "Q2": 4, "Q3": 3, "Q4": 4, "GPA": 3.75, "comment": "Cách truyền đạt dễ tiếp cận" },
{ "id": 24, "Q1": 3, "Q2": 3, "Q3": 4, "Q4": 4, "GPA": 3.5, "comment": "Thầy luôn động viên sinh viên" },
{ "id": 25, "Q1": 4, "Q2": 4, "Q3": 4, "Q4": 4, "GPA": 4, "comment": "Bài giảng rất chất lượng" },
{ "id": 26, "Q1": 3, "Q2": 4, "Q3": 3, "Q4": 4, "GPA": 3.5, "comment": "Thầy thân thiện và hỗ trợ nhiệt tình" },
{ "id": 27, "Q1": 4, "Q2": 4, "Q3": 4, "Q4": 3, "GPA": 3.75, "comment": "Phương pháp giảng hiện đại" },
{ "id": 28, "Q1": 4, "Q2": 4, "Q3": 4, "Q4": 4, "GPA": 4, "comment": "Thầy giải thích kỹ càng" },
{ "id": 29, "Q1": 3, "Q2": 3, "Q3": 4, "Q4": 3, "GPA": 3.25, "comment": "Một vài chỗ khó theo kịp" },
{ "id": 30, "Q1": 4, "Q2": 4, "Q3": 4, "Q4": 4, "GPA": 4, "comment": "Thầy truyền cảm hứng học tập" },
{ "id": 31, "Q1": 4, "Q2": 3, "Q3": 4, "Q4": 3, "GPA": 3.5, "comment": "Cần nhiều buổi ôn tập hơn" },
{ "id": 32, "Q1": 4, "Q2": 4, "Q3": 3, "Q4": 4, "GPA": 3.75, "comment": "Thầy luôn khuyến khích đặt câu hỏi" }
{id: 1, Q1: 4, Q2: 4, Q3: 4, Q4: 4, GPA: 4, comment: 'Tuyệt vời'},
{
id: 2,
Q1: 4,
Q2: 4,
Q3: 4,
Q4: 4,
GPA: 4,
comment: 'Học với thầy em cảm thấy tiếp thu được nhiều và bổ ích',
},
{
id: 3,
Q1: 4,
Q2: 4,
Q3: 4,
Q4: 4,
GPA: 4,
comment: 'Giảng viên giảng dễ hiểu, tận tình',
},
{
id: 4,
Q1: 4,
Q2: 4,
Q3: 4,
Q4: 4,
GPA: 4,
comment: 'Bài giảng rõ ràng, mạch lạc',
},
{
id: 5,
Q1: 3,
Q2: 4,
Q3: 4,
Q4: 3,
GPA: 3.5,
comment: 'Một số chỗ hơi nhanh, cần giảng chậm lại',
},
{
id: 6,
Q1: 4,
Q2: 3,
Q3: 4,
Q4: 4,
GPA: 3.75,
comment: 'Ổn nhưng cần thêm ví dụ thực tế',
},
{
id: 7,
Q1: 4,
Q2: 4,
Q3: 3,
Q4: 4,
GPA: 3.75,
comment: 'Rất dễ hiểu, nên có thêm bài tập nhóm',
},
{
id: 8,
Q1: 4,
Q2: 4,
Q3: 4,
Q4: 3,
GPA: 3.75,
comment: 'Phong cách giảng dạy gần gũi',
},
{
id: 9,
Q1: 4,
Q2: 3,
Q3: 3,
Q4: 4,
GPA: 3.5,
comment: 'Hài hước, dễ tiếp thu',
},
{
id: 10,
Q1: 4,
Q2: 4,
Q3: 4,
Q4: 4,
GPA: 4,
comment: 'Rất tận tình và hỗ trợ sinh viên',
},
{
id: 11,
Q1: 3,
Q2: 4,
Q3: 4,
Q4: 3,
GPA: 3.5,
comment: 'Nên chậm lại phần kiến thức nâng cao',
},
{
id: 12,
Q1: 4,
Q2: 4,
Q3: 3,
Q4: 4,
GPA: 3.75,
comment: 'Cách giải thích dễ hiểu',
},
{
id: 13,
Q1: 4,
Q2: 4,
Q3: 4,
Q4: 4,
GPA: 4,
comment: 'Giảng viên nhiệt huyết',
},
{
id: 14,
Q1: 4,
Q2: 4,
Q3: 3,
Q4: 3,
GPA: 3.5,
comment: 'Có thêm tài liệu tham khảo thì tốt',
},
{
id: 15,
Q1: 4,
Q2: 3,
Q3: 4,
Q4: 4,
GPA: 3.75,
comment: 'Thầy luôn trả lời câu hỏi tận tình',
},
{
id: 16,
Q1: 4,
Q2: 4,
Q3: 3,
Q4: 4,
GPA: 3.75,
comment: 'Nội dung sát thực tế',
},
{
id: 17,
Q1: 3,
Q2: 4,
Q3: 4,
Q4: 3,
GPA: 3.5,
comment: 'Bài giảng cần nhiều ví dụ minh họa hơn',
},
{
id: 18,
Q1: 4,
Q2: 4,
Q3: 4,
Q4: 3,
GPA: 3.75,
comment: 'Phong thái chuyên nghiệp',
},
{
id: 19,
Q1: 4,
Q2: 4,
Q3: 4,
Q4: 4,
GPA: 4,
comment: 'Rất dễ hiểu, rõ ràng',
},
{
id: 20,
Q1: 4,
Q2: 4,
Q3: 3,
Q4: 3,
GPA: 3.5,
comment: 'Một số phần khó nhưng thầy đã hỗ trợ nhiều',
},
{
id: 21,
Q1: 4,
Q2: 4,
Q3: 4,
Q4: 4,
GPA: 4,
comment: 'Không khí lớp học vui vẻ',
},
{
id: 22,
Q1: 4,
Q2: 3,
Q3: 4,
Q4: 3,
GPA: 3.5,
comment: 'Có thể tăng thêm thời gian luyện tập',
},
{
id: 23,
Q1: 4,
Q2: 4,
Q3: 3,
Q4: 4,
GPA: 3.75,
comment: 'Cách truyền đạt dễ tiếp cận',
},
{
id: 24,
Q1: 3,
Q2: 3,
Q3: 4,
Q4: 4,
GPA: 3.5,
comment: 'Thầy luôn động viên sinh viên',
},
{
id: 25,
Q1: 4,
Q2: 4,
Q3: 4,
Q4: 4,
GPA: 4,
comment: 'Bài giảng rất chất lượng',
},
{
id: 26,
Q1: 3,
Q2: 4,
Q3: 3,
Q4: 4,
GPA: 3.5,
comment: 'Thầy thân thiện và hỗ trợ nhiệt tình',
},
{
id: 27,
Q1: 4,
Q2: 4,
Q3: 4,
Q4: 3,
GPA: 3.75,
comment: 'Phương pháp giảng hiện đại',
},
{
id: 28,
Q1: 4,
Q2: 4,
Q3: 4,
Q4: 4,
GPA: 4,
comment: 'Thầy giải thích kỹ càng',
},
{
id: 29,
Q1: 3,
Q2: 3,
Q3: 4,
Q4: 3,
GPA: 3.25,
comment: 'Một vài chỗ khó theo kịp',
},
{
id: 30,
Q1: 4,
Q2: 4,
Q3: 4,
Q4: 4,
GPA: 4,
comment: 'Thầy truyền cảm hứng học tập',
},
{
id: 31,
Q1: 4,
Q2: 3,
Q3: 4,
Q4: 3,
GPA: 3.5,
comment: 'Cần nhiều buổi ôn tập hơn',
},
{
id: 32,
Q1: 4,
Q2: 4,
Q3: 3,
Q4: 4,
GPA: 3.75,
comment: 'Thầy luôn khuyến khích đặt câu hỏi',
},
],
});
......
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,
paddingHorizontal:15,
paddingVertical:10,
body: {
flex: 1,
paddingHorizontal: 15,
paddingVertical: 10,
},
textSubTitle:{
fontSize:R.sizes.sm,
fontFamily:R.fonts.fontRegular,
fontWeight:'400',
color:R.colors.black,
textSubTitle: {
fontSize: R.sizes.sm,
fontFamily: R.fonts.fontRegular,
fontWeight: '400',
color: R.colors.black,
},
boxFeedBack:{
backgroundColor:R.colors.grayButton,
paddingVertical:5,
borderLeftWidth:3,
paddingLeft:10,
paddingRight:10,
borderLeftColor:R.colors.gray2,
boxFeedBack: {
backgroundColor: R.colors.grayButton,
paddingVertical: 5,
borderLeftWidth: 3,
paddingLeft: 10,
paddingRight: 10,
borderLeftColor: R.colors.gray2,
},
containerQuestion:{
marginVertical:10,
containerQuestion: {
marginVertical: 10,
},
tableContainer: {
borderWidth: 1,
......@@ -84,6 +84,6 @@ const styles = StyleSheet.create({
textAlign: 'center',
flexWrap: 'wrap',
},
})
});
export default styles
export default styles;
import React from 'react';
import {Text, View, TouchableOpacity, StyleSheet, FlatList, ScrollView} from 'react-native';
import {
Text,
View,
TouchableOpacity,
StyleSheet,
FlatList,
ScrollView,
} from 'react-native';
import styles from './style';
import Header from '../../../components/Header/Header';
import R from '../../../assets/R';
const DetailFeedBackView = (props) => {
const {teacher,dataListQuestion} = props;
const DetailFeedBackView = props => {
const {teacher, dataListQuestion} = props;
console.log(props);
const renderTableRow = (item, index) => {
......@@ -38,28 +45,40 @@ const DetailFeedBackView = (props) => {
const renderItem = ({item}) => {
return (
<View style={styles.boxFeedBack}>
<Text style={[styles.textSubTitle,{fontFamily:R.fonts.fontRegular,fontWeight:'400',color:R.colors.black,}]}>Q{item.id}: {item.question}</Text>
<Text
style={[
styles.textSubTitle,
{
fontFamily: R.fonts.fontRegular,
fontWeight: '400',
color: R.colors.black,
},
]}>
Q{item.id}: {item.question}
</Text>
</View>
);
};
return (
<View style={styles.container}>
<Header title={'Đánh giá giảng dạy'} isBack/>
<Header title={'Đánh giá giảng dạy'} isBack />
<View style={styles.body}>
<Text style={styles.textSubTitle}>Feedback ca sinh viên lp {teacher.class} môn {teacher.subject} đối vi ging viên {teacher.teacher}.</Text>
<Text style={styles.textSubTitle}>
Feedback ca sinh viên lp {teacher.class} môn {teacher.subject} đối
vi ging viên {teacher.teacher}.
</Text>
<View style={styles.containerQuestion}>
<FlatList
nestedScrollEnabled
data={dataListQuestion?.question || []}
renderItem={renderItem}
keyExtractor={(item) => item.id.toString()}
keyExtractor={item => item.id.toString()}
showsVerticalScrollIndicator={false}
vertical
/>
</View>
<ScrollView
showsVerticalScrollIndicator={false}
style={styles.tableContainer}>
......@@ -87,11 +106,11 @@ const DetailFeedBackView = (props) => {
</View>
</View>
{dataListQuestion?.results?.map((item, index) => renderTableRow(item, index))}
{dataListQuestion?.results?.map((item, index) =>
renderTableRow(item, index),
)}
</ScrollView>
</View>
</View>
);
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment