diff --git a/src/app/(main)/settings/changepassword/page.tsx b/src/app/(main)/settings/changepassword/page.tsx new file mode 100644 index 0000000..b6b9a41 --- /dev/null +++ b/src/app/(main)/settings/changepassword/page.tsx @@ -0,0 +1,53 @@ +import { preloadClaims } from "@/app/api/claims"; +import { preloadStaff, preloadTeamLeads } from "@/app/api/staff"; +import ChangePassword from "@/components/ChangePassword"; +import StaffSearch from "@/components/StaffSearch"; +import TeamSearch from "@/components/TeamSearch"; +import UserGroupSearch from "@/components/UserGroupSearch"; +import UserSearch from "@/components/UserSearch"; +import { I18nProvider, getServerI18n } from "@/i18n"; +import Add from "@mui/icons-material/Add"; +import Button from "@mui/material/Button"; +import Stack from "@mui/material/Stack"; +import Typography from "@mui/material/Typography"; +import { Metadata } from "next"; +import Link from "next/link"; +import { Suspense } from "react"; + + +export const metadata: Metadata = { + title: "Change Password", + }; + + + const ChangePasswordPage: React.FC = async () => { + const { t } = await getServerI18n("User Group"); + // preloadTeamLeads(); + // preloadStaff(); + return ( + <> + + + {t("Change Password")} + + + {/* + }> + + + */} + + }> + + + + + ); + }; + + export default ChangePasswordPage; \ No newline at end of file diff --git a/src/app/(main)/settings/staff/user/page.tsx b/src/app/(main)/settings/staff/user/page.tsx new file mode 100644 index 0000000..11ef8f9 --- /dev/null +++ b/src/app/(main)/settings/staff/user/page.tsx @@ -0,0 +1,22 @@ +import { Edit } from "@mui/icons-material"; +import { Metadata } from "next"; +import { I18nProvider, getServerI18n } from "@/i18n"; +import EditUser from "@/components/EditUser"; +import { Typography } from "@mui/material"; +import { Suspense } from "react"; + +const User: React.FC = async () => { + const { t } = await getServerI18n("user"); + + return ( + <> + {t("Edit User")} + + }> + + + + + ); +}; +export default User; diff --git a/src/components/ChangePassword/ChangePassword.tsx b/src/components/ChangePassword/ChangePassword.tsx new file mode 100644 index 0000000..33e19ff --- /dev/null +++ b/src/components/ChangePassword/ChangePassword.tsx @@ -0,0 +1,107 @@ +"use client"; +import { PasswordInputs, changePassword } from "@/app/api/user/actions"; +import { Grid } from "@mui/material"; +import { useRouter } from "next/navigation"; +import { useCallback, useState } from "react"; +import { FormProvider, SubmitErrorHandler, SubmitHandler, useForm } from "react-hook-form"; +import { useTranslation } from "react-i18next"; +import { Button, Stack, Tab, Tabs, TabsProps, Typography } from "@mui/material"; +import { Check, Close, Error } from "@mui/icons-material"; +import ChagnePasswordForm from "./ChangePasswordForm"; +import { ServerFetchError } from "@/app/utils/fetchUtil"; + +// interface Props { +// // auth?: auth[] +// // users?: UserResult[] +// } + +const ChangePassword: React.FC = () => { + const formProps = useForm(); + const [serverError, setServerError] = useState(""); + const router = useRouter(); + // const [tabIndex, setTabIndex] = useState(0); + const { t } = useTranslation(); + + const onSubmit = useCallback>( + async (data) => { + try { + let haveError = false; + // Minimum eight characters, at least one uppercase letter, one lowercase letter, one number and one special character: + let regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/ + + if (data.newPassword.length < 8 || data.newPassword.length > 20) { + haveError = true + formProps.setError("newPassword", { message: "The password requires 8-20 characters", type: "required" }) + } + if (!regex.test(data.newPassword)) { + haveError = true + formProps.setError("newPassword", { message: "A combination of uppercase letters, lowercase letters, numbers, and symbols is required.", type: "required" }) + } + if (data.password == data.newPassword) { + haveError = true + formProps.setError("newPassword", { message: "The new password cannot be the same as the old password", type: "required" }) + } + if (data.newPassword != data.newPasswordCheck) { + haveError = true + formProps.setError("newPassword", { message: "The new password has to be the same as the new password", type: "required" }) + formProps.setError("newPasswordCheck", { message: "The new password has to be the same as the new password", type: "required" }) + } + if (haveError) { + return + } + const postData = { + password: data.password, + newPassword: data.newPassword + } + // await changePassword(postData) + // router.replace("/home") + } catch (e) { + console.log(e) + setServerError(t("An error has occurred. Please try again later.")); + } + }, + [router] + ); + + const handleCancel = () => { + router.push(`/home`); + }; + + const onSubmitError = useCallback>( + (errors) => { + console.log(errors); + }, + [] + ); + + return ( + + + + + + + + + + ); +}; + +export default ChangePassword; diff --git a/src/components/ChangePassword/ChangePasswordForm.tsx b/src/components/ChangePassword/ChangePasswordForm.tsx new file mode 100644 index 0000000..19e2a29 --- /dev/null +++ b/src/components/ChangePassword/ChangePasswordForm.tsx @@ -0,0 +1,144 @@ +"use client"; +import Stack from "@mui/material/Stack"; +import Box from "@mui/material/Box"; +import Card from "@mui/material/Card"; +import CardContent from "@mui/material/CardContent"; +import Grid from "@mui/material/Grid"; +import TextField from "@mui/material/TextField"; +import Typography from "@mui/material/Typography"; +import { useFormContext } from "react-hook-form"; +import { useTranslation } from "react-i18next"; +import { useCallback, useState } from "react"; +import { PasswordInputs } from "@/app/api/user/actions"; +import { Visibility, VisibilityOff } from "@mui/icons-material"; +import { IconButton, InputAdornment } from "@mui/material"; + +const ChagnePasswordForm: React.FC = () => { + const { t } = useTranslation(); + + const [showNewPassword, setShowNewPassword] = useState(false); + const handleClickShowNewPassword = () => setShowNewPassword(!showNewPassword); + const handleMouseDownNewPassword = () => setShowNewPassword(!showNewPassword); + + const [showPassword, setShowPassword] = useState(false); + const handleClickShowPassword = () => setShowPassword(!showPassword); + const handleMouseDownPassword = () => setShowPassword(!showPassword); + + const { + register, + formState: { errors, defaultValues }, + control, + reset, + resetField, + setValue, + } = useFormContext(); + + // const resetGroup = useCallback(() => { + // console.log(defaultValues); + // if (defaultValues !== undefined) { + // resetField("description"); + // } + // }, [defaultValues]); + + return ( + + + + + {t("Group Info")} + + + + + + {showPassword ? : } + + + ) + }} + {...register("password", { + required: true, + })} + error={Boolean(errors.password)} + helperText={ + Boolean(errors.password) && + (errors.password?.message + ? t(errors.password.message) + : t("Please input correct password")) + } + /> + + + + + + {showNewPassword ? : } + + + ) + }} + {...register("newPassword")} + error={Boolean(errors.newPassword)} + helperText={ + Boolean(errors.newPassword) && + (errors.newPassword?.message + ? t(errors.newPassword.message) + : t("Please input correct newPassword")) + } + /> + + + + + {showNewPassword ? : } + + + ) + }} + {...register("newPasswordCheck")} + error={Boolean(errors.newPassword)} + helperText={ + Boolean(errors.newPassword) && + (errors.newPassword?.message + ? t(errors.newPassword.message) + : t("Please input correct newPassword")) + } + /> + + + + + + ); +}; +export default ChagnePasswordForm; diff --git a/src/components/ChangePassword/ChangePasswordLoading.tsx b/src/components/ChangePassword/ChangePasswordLoading.tsx new file mode 100644 index 0000000..30f29fd --- /dev/null +++ b/src/components/ChangePassword/ChangePasswordLoading.tsx @@ -0,0 +1,40 @@ +import Card from "@mui/material/Card"; +import CardContent from "@mui/material/CardContent"; +import Skeleton from "@mui/material/Skeleton"; +import Stack from "@mui/material/Stack"; +import React from "react"; + +// Can make this nicer +export const ChangePasswordLoading: React.FC = () => { + return ( + <> + + + + + + + + + + + Change Password + + + + + + + + + + + ); +}; + +export default ChangePasswordLoading; diff --git a/src/components/ChangePassword/ChangePasswordWrapper.tsx b/src/components/ChangePassword/ChangePasswordWrapper.tsx new file mode 100644 index 0000000..30acb9d --- /dev/null +++ b/src/components/ChangePassword/ChangePasswordWrapper.tsx @@ -0,0 +1,20 @@ +import React from "react"; +import ChangePasswordLoading from "./ChangePasswordLoading"; +import ChangePassword from "./ChangePassword"; + +interface SubComponents { + Loading: typeof ChangePasswordLoading; +} + +const ChangePasswordWrapper: React.FC & SubComponents = async () => { + // const records = await fetchAuth() + // const users = await fetchUser() + // console.log(users) + // const auth = records.records as auth[] + + return ; +}; + +ChangePasswordWrapper.Loading = ChangePasswordLoading; + +export default ChangePasswordWrapper; diff --git a/src/components/ChangePassword/index.ts b/src/components/ChangePassword/index.ts new file mode 100644 index 0000000..f7ec5db --- /dev/null +++ b/src/components/ChangePassword/index.ts @@ -0,0 +1 @@ +export { default } from "./ChangePasswordWrapper";