diff --git a/public/LICENSE.txt b/public/LICENSE.txt
new file mode 100644
index 0000000..44c9efc
--- /dev/null
+++ b/public/LICENSE.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 Pete Pongpeauk
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/public/images/LICENSE.txt b/public/images/LICENSE.txt
new file mode 100644
index 0000000..44c9efc
--- /dev/null
+++ b/public/images/LICENSE.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 Pete Pongpeauk
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/components/CheckActivationCodeModal.tsx b/src/components/CheckActivationCodeModal.tsx
index 355a94e..35f03c6 100644
--- a/src/components/CheckActivationCodeModal.tsx
+++ b/src/components/CheckActivationCodeModal.tsx
@@ -116,15 +116,15 @@ export default function CheckActivationCodeModal({
+
-
diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx
index 684f707..4117aae 100644
--- a/src/components/Footer.tsx
+++ b/src/components/Footer.tsx
@@ -47,8 +47,9 @@ export default function Footer({ type = 'platform' }: { type?: 'public' | 'platf
fontWeight={'bold'}
letterSpacing={'tight'}
>
- PT Amperra Sambung Semesta Sentosa
+ PT Amperra Sambung Semesta Sentosa{' '}
+ under the MIT License.
diff --git a/src/components/nav/Nav.tsx b/src/components/nav/Nav.tsx
index 45f74fc..7ce6896 100644
--- a/src/components/nav/Nav.tsx
+++ b/src/components/nav/Nav.tsx
@@ -122,6 +122,7 @@ export default function Nav({ type }: { type?: string }) {
h={'6rem'}
align={'center'}
bg={useColorModeValue('white', 'gray.800')}
+ borderBottom={'1px solid'}
borderColor={useColorModeValue('gray.300', 'gray.700')}
zIndex={50}
>
@@ -149,7 +150,7 @@ export default function Nav({ type }: { type?: string }) {
>
+
+ {/* Reset Password Modal */}
+
+
+
+ Reset Password
+
+ {
+ sendPasswordResetEmail(auth, values.email)
+ .then(() => {
+ toast({
+ title: 'Password reset email sent.',
+ description: 'Please check your inbox to reset your password.',
+ status: 'success',
+ duration: 9000,
+ isClosable: true,
+ });
+ onResetModalClose();
+ })
+ .catch((error) => {
+ const errorCode = error.code;
+ let errorMessage = error.message;
+ switch (errorCode) {
+ case 'auth/invalid-email':
+ errorMessage = "The email address you've entered is invalid. Please try again.";
+ break;
+ case 'auth/user-not-found':
+ errorMessage = "No account found with that email address.";
+ break;
+ default:
+ errorMessage = 'An unknown error occurred. Please try again.';
+ }
+ toast({
+ title: 'Error sending reset email',
+ description: errorMessage,
+ status: 'error',
+ duration: 5000,
+ isClosable: true,
+ });
+ })
+ .finally(() => {
+ actions.setSubmitting(false);
+ });
+ }}
+ >
+ {(props) => (
+
+ )}
+
+
+
+
-
+ {/* Background Image */}
+
+
+ {/* Login Panel (Left Side) */}
{
- !loading && !user ?
- (
+ ) : !user ? (
+
-
- {/*
-
- */}
-
-
+
-
- Welcome!
-
- Please present your credentials to continue.
-
-
-
- {
+ Welcome!
+
+ Please present your credentials to continue.
+
+
+
+ {
+ if (isRegisterMode) {
+ // Registration Logic
+ if (values.password !== values.confirmPassword) {
+ toast({
+ title: 'Passwords do not match.',
+ description: 'Please ensure your password and confirmation match.',
+ status: 'error',
+ duration: 5000,
+ isClosable: true
+ });
+ actions.setSubmitting(false);
+ return;
+ }
+ if (!values.activationCode) {
+ toast({
+ title: 'Activation code required.',
+ description: 'Please enter your activation code.',
+ status: 'error',
+ duration: 5000,
+ isClosable: true
+ });
+ actions.setSubmitting(false);
+ return;
+ }
+ fetch(`/api/v1/activation/${values.activationCode}`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ displayName: values.displayName,
+ email: values.email,
+ username: values.username,
+ password: values.password
+ })
+ })
+ .then((res) => {
+ if (res.status === 200) {
+ return res.json();
+ } else {
+ return res.json().then((json) => {
+ throw new Error(json.message || 'Registration failed');
+ });
+ }
+ })
+ .then(() => {
+ toast({
+ title: 'Account created.',
+ description: 'You can now log in.',
+ status: 'success',
+ duration: 5000,
+ isClosable: true
+ });
+ setIsRegisterMode(false); // Switch back to login mode
+ actions.resetForm();
+ })
+ .catch((error) => {
+ toast({
+ title: 'There was an error while creating your account.',
+ description: error.message,
+ status: 'error',
+ duration: 5000,
+ isClosable: true
+ });
+ })
+ .finally(() => {
+ actions.setSubmitting(false);
+ });
+ } else {
+ // Login Logic
signInWithEmailAndPassword(auth, values.email, values.password)
.then(() => {
redirectOnAuth();
@@ -212,20 +385,17 @@ export default function Login() {
case 'auth/invalid-email':
errorMessage = 'The email address you provided is invalid.';
break;
- case 'auth/invalid-password':
+ case 'auth/invalid-credential':
+ case 'auth/user-not-found':
+ case 'auth/wrong-password':
errorMessage = "Invalid email address or password. Please try again.";
break;
case 'auth/user-disabled':
errorMessage = 'Your account has been disabled.';
break;
- case 'auth/user-not-found':
- errorMessage = "Invalid email address or password. Please try again.";
- break;
- case 'auth/wrong-password':
- errorMessage = "Invalid email address or password. Please try again.";
- break;
case 'auth/too-many-requests':
errorMessage = 'Too many attempts. Please try again later.';
+ break;
default:
errorMessage = 'An unknown error occurred.';
}
@@ -239,98 +409,219 @@ export default function Login() {
.finally(() => {
actions.setSubmitting(false);
});
- }}
+ }
+ }}
+ >
+ {(props) => (
+
+ )}
+
+
+ {isRegisterMode ? (
+
+ Already have an account?{' '}
+ setIsRegisterMode(false)} cursor="pointer" textDecor={'underline'} textUnderlineOffset={4}>
+ Login
+
+
+ ) : (
+
+ )}
+ {isRegisterMode && (
-
- Forgot your password?
-
+ By creating an account, you agree to our{' '}
+
+
+ Terms of Use
+
+ {' '}
+ and{' '}
+
+
+ Privacy Policy
+
+
+ .
-
-
- Have an activation code?
-
-
-
- Need help?{' '}
-
- View the FAQ.
-
-
-
-
+ )}
+
+
+ Forgot your password?
+
+
+
+ Need help?{' '}
+
+ View the FAQ.
+
+
+
+
+
- ) : <>
-
-
-
- >
+ ) : (
+ // User is logged in, redirectOnAuth has been called. Show spinner during transition.
+
+ )
}
-
+
>
);