@@ -66,8 +66,8 @@ const Profile: React.FC<Props> = ({ avatarImageSrc, profileName }) => { | |||||
</Typography> | </Typography> | ||||
<Divider /> | <Divider /> | ||||
<MenuItem onClick={() => { router.replace("/changepassword") }}>{t("Change Password")}</MenuItem> | <MenuItem onClick={() => { router.replace("/changepassword") }}>{t("Change Password")}</MenuItem> | ||||
{/* {language === "zh" && <MenuItem onClick={() => { onLangClick("en") }}>{t("Change To English Version")}</MenuItem>} | |||||
{language === "en" && <MenuItem onClick={() => { onLangClick("zh") }}>{t("Change To Chinese Version")}</MenuItem>} */} | |||||
{language === "zh" && <MenuItem onClick={() => { onLangClick("en") }}>{t("Change To English Version")}</MenuItem>} | |||||
{language === "en" && <MenuItem onClick={() => { onLangClick("zh") }}>{t("Change To Chinese Version")}</MenuItem>} | |||||
<MenuItem onClick={() => signOut()}>{t("Sign out")}</MenuItem> | <MenuItem onClick={() => signOut()}>{t("Sign out")}</MenuItem> | ||||
</Menu> | </Menu> | ||||
</> | </> | ||||
@@ -27,6 +27,7 @@ import LeaveEditModal from "../LeaveTable/LeaveEditModal"; | |||||
import dayjs from "dayjs"; | import dayjs from "dayjs"; | ||||
import { checkTotalHours } from "@/app/api/timesheets/utils"; | import { checkTotalHours } from "@/app/api/timesheets/utils"; | ||||
import unionBy from "lodash/unionBy"; | import unionBy from "lodash/unionBy"; | ||||
import { ConnectingAirportsOutlined } from "@mui/icons-material"; | |||||
export interface Props { | export interface Props { | ||||
leaveTypes: LeaveType[]; | leaveTypes: LeaveType[]; | ||||
@@ -56,8 +57,8 @@ const LeaveCalendar: React.FC<Props> = ({ | |||||
leaveRecords, | leaveRecords, | ||||
isFullTime, | isFullTime, | ||||
}) => { | }) => { | ||||
const { t } = useTranslation(["home", "common"]); | |||||
const { t ,i18n: { language }} = useTranslation(["home", "common"]); | |||||
const locale = language === "zh" ? "zh-tw" : "en"; | |||||
const theme = useTheme(); | const theme = useTheme(); | ||||
const projectMap = useMemo(() => { | const projectMap = useMemo(() => { | ||||
@@ -143,7 +144,7 @@ const LeaveCalendar: React.FC<Props> = ({ | |||||
title: `${t("{{count}} hour", { | title: `${t("{{count}} hour", { | ||||
ns: "common", | ns: "common", | ||||
count: entry.inputHours || 0, | count: entry.inputHours || 0, | ||||
})} (${leaveMap[entry.leaveTypeId]})`, | |||||
})} (${t(leaveMap[entry.leaveTypeId])})`, | |||||
backgroundColor: theme.palette.warning.light, | backgroundColor: theme.palette.warning.light, | ||||
borderColor: theme.palette.warning.light, | borderColor: theme.palette.warning.light, | ||||
textColor: theme.palette.text.primary, | textColor: theme.palette.text.primary, | ||||
@@ -269,6 +270,7 @@ const LeaveCalendar: React.FC<Props> = ({ | |||||
events={[...holidays, ...timeEntries, ...leaveEntries]} | events={[...holidays, ...timeEntries, ...leaveEntries]} | ||||
eventClick={handleEventClick} | eventClick={handleEventClick} | ||||
dateClick={handleDateClick} | dateClick={handleDateClick} | ||||
locale={locale} | |||||
/> | /> | ||||
<LeaveEditModal | <LeaveEditModal | ||||
modalSx={{ maxWidth: 400 }} | modalSx={{ maxWidth: 400 }} | ||||
@@ -108,16 +108,16 @@ const LeaveEditModal: React.FC<Props> = ({ | |||||
</Typography> | </Typography> | ||||
)} | )} | ||||
<FormControl fullWidth> | <FormControl fullWidth> | ||||
<InputLabel>{t("Leave Type")}</InputLabel> | |||||
<InputLabel>{t("Leave Types")}</InputLabel> | |||||
<Controller | <Controller | ||||
defaultValue={leaveTypes[0].id} | defaultValue={leaveTypes[0].id} | ||||
control={control} | control={control} | ||||
name="leaveTypeId" | name="leaveTypeId" | ||||
render={({ field }) => ( | render={({ field }) => ( | ||||
<Select label={t("Leave Type")} {...field}> | |||||
<Select label={t("Leave Types")} {...field}> | |||||
{leaveTypes.map((type, index) => ( | {leaveTypes.map((type, index) => ( | ||||
<MenuItem key={`${type.id}-${index}`} value={type.id}> | <MenuItem key={`${type.id}-${index}`} value={type.id}> | ||||
{type.name} | |||||
{t(type.name)} | |||||
</MenuItem> | </MenuItem> | ||||
))} | ))} | ||||
</Select> | </Select> | ||||
@@ -148,7 +148,7 @@ const LeaveEditModal: React.FC<Props> = ({ | |||||
helperText={formState.errors.inputHours?.message} | helperText={formState.errors.inputHours?.message} | ||||
/> | /> | ||||
<TextField | <TextField | ||||
label={t("Remark")} | |||||
label={t("Remarks")} | |||||
fullWidth | fullWidth | ||||
multiline | multiline | ||||
rows={2} | rows={2} | ||||
@@ -35,7 +35,7 @@ const LeaveEntryCard: React.FC<Props> = ({ entry, onEdit, leaveTypeMap }) => { | |||||
> | > | ||||
<Box> | <Box> | ||||
<Typography variant="body2" component="div" fontWeight="bold"> | <Typography variant="body2" component="div" fontWeight="bold"> | ||||
{leaveTypeMap[entry.leaveTypeId].name} | |||||
{t(leaveTypeMap[entry.leaveTypeId].name)} | |||||
</Typography> | </Typography> | ||||
<Typography component="p"> | <Typography component="p"> | ||||
{manhourFormatter.format(entry.inputHours)} | {manhourFormatter.format(entry.inputHours)} | ||||
@@ -50,7 +50,7 @@ const LeaveEntryCard: React.FC<Props> = ({ entry, onEdit, leaveTypeMap }) => { | |||||
{entry.remark && ( | {entry.remark && ( | ||||
<Box> | <Box> | ||||
<Typography variant="body2" component="div" fontWeight="bold"> | <Typography variant="body2" component="div" fontWeight="bold"> | ||||
{t("Remark")} | |||||
{t("Remarks")} | |||||
</Typography> | </Typography> | ||||
<Typography component="p">{entry.remark}</Typography> | <Typography component="p">{entry.remark}</Typography> | ||||
</Box> | </Box> | ||||
@@ -303,7 +303,7 @@ const NavigationContent: React.FC<Props> = ({ abilities, username }) => { | |||||
}, | }, | ||||
{ | { | ||||
icon: <Settings />, | icon: <Settings />, | ||||
label: "Setting", | |||||
label: "Settings", | |||||
path: "", | path: "", | ||||
isHidden: ![ | isHidden: ![ | ||||
VIEW_CLIENT, | VIEW_CLIENT, | ||||
@@ -560,7 +560,7 @@ const TimeLeaveInputTable: React.FC<Props> = ({ | |||||
}, | }, | ||||
{ | { | ||||
field: "remark", | field: "remark", | ||||
headerName: t("Remark"), | |||||
headerName: t("Remarks"), | |||||
sortable: false, | sortable: false, | ||||
flex: 1, | flex: 1, | ||||
editable: true, | editable: true, | ||||
@@ -41,7 +41,7 @@ import LeaveEditModal from "../LeaveTable/LeaveEditModal"; | |||||
import dayjs from "dayjs"; | import dayjs from "dayjs"; | ||||
import { checkTotalHours } from "@/app/api/timesheets/utils"; | import { checkTotalHours } from "@/app/api/timesheets/utils"; | ||||
import unionBy from "lodash/unionBy"; | import unionBy from "lodash/unionBy"; | ||||
import { Luggage, MoreTime } from "@mui/icons-material"; | |||||
import { Language, Luggage, MoreTime } from "@mui/icons-material"; | |||||
import { Task } from "@/app/api/tasks"; | import { Task } from "@/app/api/tasks"; | ||||
export interface Props { | export interface Props { | ||||
@@ -80,8 +80,8 @@ const TimesheetAmendment: React.FC<Props> = ({ | |||||
leaveTypes, | leaveTypes, | ||||
miscTasks, | miscTasks, | ||||
}) => { | }) => { | ||||
const { t } = useTranslation(["home", "common"]); | |||||
const { t, i18n:{language}} = useTranslation(["home", "common"]); | |||||
const locale = language === "zh" ? "zh-tw" : "en"; | |||||
const theme = useTheme(); | const theme = useTheme(); | ||||
const projectMap = useMemo(() => { | const projectMap = useMemo(() => { | ||||
@@ -262,7 +262,7 @@ const TimesheetAmendment: React.FC<Props> = ({ | |||||
title: `${t("{{count}} hour", { | title: `${t("{{count}} hour", { | ||||
ns: "common", | ns: "common", | ||||
count: entry.inputHours || 0, | count: entry.inputHours || 0, | ||||
})} (${leaveMap[entry.leaveTypeId]})`, | |||||
})} (${t(leaveMap[entry.leaveTypeId])})`, | |||||
backgroundColor: theme.palette.warning.light, | backgroundColor: theme.palette.warning.light, | ||||
borderColor: theme.palette.warning.light, | borderColor: theme.palette.warning.light, | ||||
textColor: theme.palette.text.primary, | textColor: theme.palette.text.primary, | ||||
@@ -454,6 +454,7 @@ const TimesheetAmendment: React.FC<Props> = ({ | |||||
events={[...holidays, ...timeEntries, ...leaveEntries]} | events={[...holidays, ...timeEntries, ...leaveEntries]} | ||||
eventClick={handleEventClick} | eventClick={handleEventClick} | ||||
dateClick={handleDateClick} | dateClick={handleDateClick} | ||||
locale={locale} | |||||
/> | /> | ||||
<TimesheetEditModal | <TimesheetEditModal | ||||
modalSx={{ maxWidth: 400 }} | modalSx={{ maxWidth: 400 }} | ||||
@@ -42,7 +42,7 @@ export const TimesheetAmendmentModal: React.FC<Props> = ({ | |||||
const { t } = useTranslation("home"); | const { t } = useTranslation("home"); | ||||
const isMobile = useIsMobile(); | const isMobile = useIsMobile(); | ||||
const title = t("Timesheet Amendment"); | |||||
const title = t("Timesheet Amendments"); | |||||
const content = ( | const content = ( | ||||
<TimesheetAmendment | <TimesheetAmendment | ||||
leaveTypes={leaveTypes} | leaveTypes={leaveTypes} | ||||
@@ -195,7 +195,7 @@ const FastTimeEntryModal: React.FC<Props> = ({ | |||||
<FormHelperText> | <FormHelperText> | ||||
{formState.errors.projectIds?.message || | {formState.errors.projectIds?.message || | ||||
t( | t( | ||||
'The inputted time will be evenly distributed among the selected projects. Only projects with the "Management Timesheet Allocation" task can use the fast entry.', | |||||
'The inputted time will be evenly distributed among the selected projects. Only projects with the Management Timesheet Allocation task can use the fast entry.', | |||||
)} | )} | ||||
</FormHelperText> | </FormHelperText> | ||||
</FormControl> | </FormControl> | ||||
@@ -237,7 +237,7 @@ const FastTimeEntryModal: React.FC<Props> = ({ | |||||
error={Boolean(formState.errors.otHours)} | error={Boolean(formState.errors.otHours)} | ||||
/> | /> | ||||
<TextField | <TextField | ||||
label={t("Remark")} | |||||
label={t("Remarks")} | |||||
fullWidth | fullWidth | ||||
multiline | multiline | ||||
rows={2} | rows={2} | ||||
@@ -97,7 +97,7 @@ const AutocompleteProjectSelect: React.FC<Props> = ({ | |||||
...(includeLeaves && leaveTypes | ...(includeLeaves && leaveTypes | ||||
? leaveTypes.map((l) => ({ | ? leaveTypes.map((l) => ({ | ||||
value: `leave-${l.id}`, | value: `leave-${l.id}`, | ||||
label: l.name, | |||||
label: t(l.name), | |||||
group: "leaves", | group: "leaves", | ||||
})) | })) | ||||
: []), | : []), | ||||
@@ -295,7 +295,7 @@ const TimesheetEditModal: React.FC<Props> = ({ | |||||
error={Boolean(formState.errors.otHours)} | error={Boolean(formState.errors.otHours)} | ||||
/> | /> | ||||
<TextField | <TextField | ||||
label={t("Remark")} | |||||
label={t("Remarks")} | |||||
fullWidth | fullWidth | ||||
multiline | multiline | ||||
rows={2} | rows={2} | ||||
@@ -168,7 +168,7 @@ const UserWorkspacePage: React.FC<Props> = ({ | |||||
{showTimesheetAmendment && ( | {showTimesheetAmendment && ( | ||||
<MenuItem onClick={handleAmendmentClick} sx={menuItemSx}> | <MenuItem onClick={handleAmendmentClick} sx={menuItemSx}> | ||||
<EditCalendar /> | <EditCalendar /> | ||||
{t("Timesheet Amendment")} | |||||
{t("Timesheet Amendments")} | |||||
</MenuItem> | </MenuItem> | ||||
)} | )} | ||||
</Menu> | </Menu> | ||||
@@ -41,5 +41,36 @@ | |||||
"Project Status by Team": "Project Status by Team", | "Project Status by Team": "Project Status by Team", | ||||
"Project Resource Consumption Ranking": "Project Resource Consumption Ranking", | "Project Resource Consumption Ranking": "Project Resource Consumption Ranking", | ||||
"Staff Utilization": "Staff Utilization", | "Staff Utilization": "Staff Utilization", | ||||
"Project Resource Summary": "Project Resource Summary" | |||||
"Project Resource Summary": "Project Resource Summary", | |||||
"User Workspace": "User Workspace", | |||||
"Project Management": "Project Management", | |||||
"Task Template": "Task Template", | |||||
"Invoice": "Invoice", | |||||
"Analysis Report": "Analysis Report", | |||||
"Late Start Report": "Late Start Report", | |||||
"Project Potential Delay Report": "Project Potential Delay Report", | |||||
"Resource Overconsumption Report": "Resource Overconsumption Report", | |||||
"Cost and Expense Report": "Cost and Expense Report", | |||||
"Project Completion Report": "Project Completion Report", | |||||
"Project P&L Report": "Project P&L Report", | |||||
"Financial Status Report": "Financial Status Report", | |||||
"Project Cash Flow Report": "Project Cash Flow Report", | |||||
"Staff Monthly Work Hours Analysis Report": "Staff Monthly Work Hours Analysis Report", | |||||
"Cross Team Charge Report": "Cross Team Charge Report", | |||||
"Settings": "Settings", | |||||
"Client": "Client", | |||||
"Subsidiary": "Subsidiary", | |||||
"Staff": "Staff", | |||||
"Company": "Company", | |||||
"Skill": "Skill", | |||||
"Department": "Department", | |||||
"Position": "Position", | |||||
"Salary": "Salary", | |||||
"Team": "Team", | |||||
"User Group": "User Group", | |||||
"Holiday": "Holiday", | |||||
"Mail": "Mail", | |||||
"Import Excel File": "Import Excel File", | |||||
"There are some errors": "There are some errors", | |||||
"{{count}} hour": "{{count}} hour" | |||||
} | } |
@@ -0,0 +1,65 @@ | |||||
{ | |||||
"User Workspace": "User Workspace", | |||||
"Timesheet Actions": "Timesheet Actions", | |||||
"Enter Timesheet": "Enter Timesheet", | |||||
"Record Leave": "Record Leave", | |||||
"View Past Entries": "View Past Entries", | |||||
"Timesheet Amendments": "Timesheet Amendments", | |||||
"You have no assigned projects!": "You have no assigned projects!", | |||||
"Timesheet Input": "Timesheet Input", | |||||
"Date": "Date", | |||||
"Timesheet Hours": "Timesheet Hours", | |||||
"Leave Hours": "Leave Hours", | |||||
"Daily Total Hours": "Daily Total Hours", | |||||
"Actions": "Actions", | |||||
"Project or Leave": "Project Or Leave", | |||||
"Stage": "Stage", | |||||
"Task": "Task", | |||||
"Hours": "Hours", | |||||
"Other Hours": "Other Hours", | |||||
"Remarks": "Remarks", | |||||
"Add some time entries!": "Add some time entries!", | |||||
"Record time or leave": "Record time or leave", | |||||
"Fast time entry": "Fast time entry", | |||||
"Non-billable": "Non-billable", | |||||
"None": "None", | |||||
"Leave Types": "Leave Types", | |||||
"Annual Leave": "Annual Leave", | |||||
"Sick Leave": "Sick Leave", | |||||
"Special Leave": "Special Leave", | |||||
"All projects": "All projects", | |||||
"Required": "Required", | |||||
"Required for non-billable tasks": "Required for non-billable tasks", | |||||
"There are some errors": "There are some errors", | |||||
"There are some unsaved entries.": "There are some unsaved entries.", | |||||
"Project Code and Name": "Project Code and Name", | |||||
"Please choose at least 1 project.": "Please choose at least 1 project.", | |||||
"The inputted time will be evenly distributed among the selected projects. Only projects with the Management Timesheet Allocation task can use the fast entry.": "The inputted time will be evenly distributed among the selected projects. Only projects with the 'Management Timesheet Allocation' task can use the fast entry.", | |||||
"Cannot input normal hours on holidays": "Cannot input normal hours on holidays", | |||||
"Input hours should be between 0 and {{DAILY_NORMAL_MAX_HOURS}}": "Input hours should be between 0 and {{DAILY_NORMAL_MAX_HOURS}}", | |||||
"The remark will be added to all selected projects": "The remark will be added to all selected projects", | |||||
"Hour distribution preview": "Hour distribution preview", | |||||
"Please input the hours": "Please input the hours", | |||||
"Save": "Save", | |||||
"Non-billable Task": "Non-billable Task", | |||||
"Please select some projects.": "Please select some projects.", | |||||
"Cancel": "Cancel", | |||||
"Record leave": "Record leave", | |||||
"Today": "Today", | |||||
"Close": "Close", | |||||
"Past Entries": "Past Entries", | |||||
"Has timesheet entry": "Has timesheet entry", | |||||
"Has leave entry": "Has leave entry", | |||||
"Has both timesheet and leave entry": "Has both timesheet and leave entry", | |||||
"Monthly Summary": "Monthly Summary", | |||||
"Total Monthly Work Hours": "Total Monthly Work Hours", | |||||
"Total Monthly Leave Hours": "Total Monthly Leave Hours", | |||||
"Back to Monthly Summary": "Back to Monthly Summary", | |||||
"Total Work Hours": "Total Work Hours", | |||||
"Total Leave Hours": "Total Leave Hours", | |||||
"{{count}} hour": "{{count}} hour", | |||||
"Enter Time": "Enter Time" | |||||
} |
@@ -39,5 +39,36 @@ | |||||
"Project Status by Team": "按團隊查看項目狀態", | "Project Status by Team": "按團隊查看項目狀態", | ||||
"Project Resource Consumption Ranking": "項目資源消耗排名", | "Project Resource Consumption Ranking": "項目資源消耗排名", | ||||
"Staff Utilization": "員工利用率", | "Staff Utilization": "員工利用率", | ||||
"Project Resource Summary": "項目資源摘要" | |||||
"Project Resource Summary": "項目資源摘要", | |||||
"User Workspace": "用戶工作區", | |||||
"Project Management": "項目管理", | |||||
"Task Template": "任務模板", | |||||
"Invoice": "發票", | |||||
"Analysis Report": "分析報告", | |||||
"Late Start Report": "延遲開始報告", | |||||
"Project Potential Delay Report": "項目潛在延遲報告", | |||||
"Resource Overconsumption Report": "資源超量消耗報告", | |||||
"Cost and Expense Report": "成本與費用報告", | |||||
"Project Completion Report": "項目完成報告", | |||||
"Project P&L Report": "項目損益報告", | |||||
"Financial Status Report": "財務狀況報告", | |||||
"Project Cash Flow Report": "項目現金流報告", | |||||
"Staff Monthly Work Hours Analysis Report": "員工月度工時分析報告", | |||||
"Cross Team Charge Report": "跨團隊費用報告", | |||||
"Settings": "設置", | |||||
"Client": "客戶", | |||||
"Subsidiary": "子公司", | |||||
"Staff": "員工", | |||||
"Company": "公司", | |||||
"Skill": "技能", | |||||
"Department": "部門", | |||||
"Position": "職位", | |||||
"Salary": "薪資", | |||||
"Team": "團隊", | |||||
"User Group": "用戶組", | |||||
"Holiday": "假期", | |||||
"Mail": "郵件", | |||||
"Import Excel File": "導入 Excel 文件", | |||||
"There are some errors": "發生錯誤", | |||||
"{{count}} hour": "{{count}} 小時" | |||||
} | } |
@@ -0,0 +1,65 @@ | |||||
{ | |||||
"User Workspace": "用戶工作區", | |||||
"Timesheet Actions": "時間表操作", | |||||
"Enter Timesheet": "填寫時間表", | |||||
"Record Leave": "記錄假期", | |||||
"View Past Entries": "查看過去記錄", | |||||
"Timesheet Amendments": "修訂時間表", | |||||
"You have no assigned projects!": "您沒有分配的項目!", | |||||
"Timesheet Input": "輸入時間表", | |||||
"Date": "日期", | |||||
"Timesheet Hours": "時間表工時", | |||||
"Leave Hours": "請假工時", | |||||
"Daily Total Hours": "每日總工時", | |||||
"Actions": "操作", | |||||
"Project or Leave": "項目或假期", | |||||
"Stage": "階段", | |||||
"Task": "任務", | |||||
"Hours": "工時", | |||||
"Other Hours": "其他工時", | |||||
"Remarks": "備註", | |||||
"Add some time entries!": "添加一些時間記錄!", | |||||
"Record time or leave": "記錄工時或假期", | |||||
"Fast time entry": "快速時間輸入", | |||||
"Non-billable": "不可計費", | |||||
"None": "無", | |||||
"Leave Types": "假期類型", | |||||
"Annual Leave": "年假", | |||||
"Sick Leave": "病假", | |||||
"Special Leave": "特別假", | |||||
"All projects": "所有項目", | |||||
"Required": "必填", | |||||
"Required for non-billable tasks": "非計費工作必填", | |||||
"There are some errors": "發生錯誤", | |||||
"There are some unsaved entries.": "有未保存的記錄", | |||||
"Project Code and Name": "項目代碼與名稱", | |||||
"Please choose at least 1 project.": "請至少選擇一個項目。", | |||||
"The inputted time will be evenly distributed among the selected projects. Only projects with the Management Timesheet Allocation task can use the fast entry.": "輸入的時間將平均分配到選定的項目中。只有具有「管理時間表分配」工作的項目才能使用快速輸入。", | |||||
"Cannot input normal hours on holidays": "無法在假期輸入正常工時", | |||||
"Input hours should be between 0 and {{DAILY_NORMAL_MAX_HOURS}}": "輸入的工時應介於 0 和 {{DAILY_NORMAL_MAX_HOURS}} 之間", | |||||
"The remark will be added to all selected projects": "備註將添加到所有選定的項目中", | |||||
"Hour distribution preview": "工時分配預覽", | |||||
"Please input the hours": "請輸入工時", | |||||
"Save": "保存", | |||||
"Non-billable Task": "不可計費工作", | |||||
"Please select some projects.": "請選擇一些項目。", | |||||
"Cancel": "取消", | |||||
"Record leave": "記錄假期", | |||||
"Today": "今天", | |||||
"Close": "關閉", | |||||
"Past Entries": "過去的記錄", | |||||
"Has timesheet entry": "有時間表記錄", | |||||
"Has leave entry": "有假期記錄", | |||||
"Has both timesheet and leave entry": "有時間表和假期記錄", | |||||
"Monthly Summary": "月度總結", | |||||
"Total Monthly Work Hours": "月度總工時", | |||||
"Total Monthly Leave Hours": "月度假期工時", | |||||
"Back to Monthly Summary": "返回月度總結", | |||||
"Total Work Hours": "總工時", | |||||
"Total Leave Hours": "總假期工時", | |||||
"{{count}} hour": "{{count}} 小時", | |||||
"Enter Time": "輸入工時" | |||||
} |