diff --git a/.gitignore b/.gitignore
index 3466d7bf..605f4f96 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,4 +5,5 @@ HELP.md
mvnw
mvnw.cmd
target/
-
+# Ingore intelliJ generated module settings files
+*.iml
diff --git a/.project b/.project
index b51ee30c..2f16d643 100644
--- a/.project
+++ b/.project
@@ -20,4 +20,15 @@
org.eclipse.jdt.core.javanature
org.eclipse.m2e.core.maven2Nature
+
+
+ 1613507358663
+
+ 30
+
+ org.eclipse.core.resources.regexFilterMatcher
+ node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
+
+
+
diff --git a/README.md b/README.md
index 86e4a71d..59cba1ca 100644
--- a/README.md
+++ b/README.md
@@ -5,5 +5,5 @@ The application defaults to port 8080.
To start from the IDE press F5 to run. This will open the debug and run view. You will need to create a launch configuration which Visual Studio Code will help you with.
- # Landing page (list available products)
-`https://uarkregappjava.herokuapp.com/`
\ No newline at end of file
+ # Landing page
+`https://team-sms-store.herokuapp.com/`
\ No newline at end of file
diff --git a/src/main/java/edu/uark/registerapp/commands/activeUsers/ActiveUserDeleteCommand.java b/src/main/java/edu/uark/registerapp/commands/activeUsers/ActiveUserDeleteCommand.java
new file mode 100644
index 00000000..c4e84cf6
--- /dev/null
+++ b/src/main/java/edu/uark/registerapp/commands/activeUsers/ActiveUserDeleteCommand.java
@@ -0,0 +1,70 @@
+package edu.uark.registerapp.commands.activeUsers;
+
+import java.util.Optional;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import edu.uark.registerapp.commands.VoidCommandInterface;
+import edu.uark.registerapp.models.entities.ActiveUserEntity;
+import edu.uark.registerapp.models.entities.EmployeeEntity;
+import edu.uark.registerapp.models.repositories.ActiveUserRepository;
+import edu.uark.registerapp.models.repositories.EmployeeRepository;
+
+@Service
+public class ActiveUserDeleteCommand implements VoidCommandInterface {
+
+ private String sessionKey;
+ private ActiveUserRepository activeUserRepository;
+ private EmployeeRepository employeeRepository;
+
+ public ActiveUserDeleteCommand(
+ String sessionKey,
+ ActiveUserRepository activeUserRepository,
+ EmployeeRepository employeeRepository)
+ {
+ this.sessionKey = sessionKey;
+ this.activeUserRepository = activeUserRepository;
+ this.employeeRepository = employeeRepository;
+ }
+
+ public ActiveUserDeleteCommand()
+ {
+ this.sessionKey = "";
+ }
+
+ @Override
+ @Transactional
+ public void execute()
+ {
+ if (activeUserRepository == null)
+ {
+ return;
+ }
+
+ final Optional activeUserEntity =
+ this.activeUserRepository.findBySessionKey(this.sessionKey);
+
+ if (activeUserEntity.isPresent()) // Found active user
+ {
+ if (employeeRepository != null)
+ {
+ Optional employee =
+ employeeRepository.findById(activeUserEntity.get().getEmployeeId());
+
+ if (employee.isPresent()) // Found corresponding entry in 'employee' table
+ {
+ employee.get().setIsActive(false);
+ employeeRepository.save(employee.get());
+ }
+ }
+
+ this.activeUserRepository.delete(activeUserEntity.get());
+ }
+ }
+
+ public String getSessionKey()
+ {
+ return this.sessionKey;
+ }
+}
diff --git a/src/main/java/edu/uark/registerapp/commands/employees/ActiveEmployeeExistsQuery.java b/src/main/java/edu/uark/registerapp/commands/employees/ActiveEmployeeExistsQuery.java
new file mode 100644
index 00000000..a491ac29
--- /dev/null
+++ b/src/main/java/edu/uark/registerapp/commands/employees/ActiveEmployeeExistsQuery.java
@@ -0,0 +1,24 @@
+package edu.uark.registerapp.commands.employees;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import edu.uark.registerapp.models.repositories.EmployeeRepository;
+import edu.uark.registerapp.commands.exceptions.NotFoundException;
+
+@Service
+public class ActiveEmployeeExistsQuery {
+ public void execute()
+ {
+ final Boolean activeEmployeeExists =
+ this.employeeRepository.existsByIsActive(true);
+
+ if (!activeEmployeeExists)
+ {
+ throw new NotFoundException("Employee");
+ }
+ }
+
+ @Autowired
+ private EmployeeRepository employeeRepository;
+}
diff --git a/src/main/java/edu/uark/registerapp/commands/employees/EmployeeSignInCommand.java b/src/main/java/edu/uark/registerapp/commands/employees/EmployeeSignInCommand.java
new file mode 100644
index 00000000..31db6c06
--- /dev/null
+++ b/src/main/java/edu/uark/registerapp/commands/employees/EmployeeSignInCommand.java
@@ -0,0 +1,134 @@
+package edu.uark.registerapp.commands.employees;
+
+import java.util.Optional;
+import java.util.Arrays;
+
+import org.apache.commons.lang3.StringUtils;
+
+import javax.transaction.Transactional;
+
+import edu.uark.registerapp.models.api.EmployeeSignIn;
+import edu.uark.registerapp.models.entities.ActiveUserEntity;
+import edu.uark.registerapp.models.entities.EmployeeEntity;
+import edu.uark.registerapp.models.repositories.ActiveUserRepository;
+import edu.uark.registerapp.models.repositories.EmployeeRepository;
+
+
+public class EmployeeSignInCommand {
+
+ private EmployeeSignIn employeeSignIn;
+ private String sessionKey;
+
+ public EmployeeSignInCommand(EmployeeSignIn employeeSignIn, String sessionKey)
+ {
+ this.employeeSignIn = employeeSignIn;
+ this.sessionKey = sessionKey;
+ }
+
+ EmployeeSignInCommand()
+ {
+ this.employeeSignIn = new EmployeeSignIn();
+ this.sessionKey = "";
+ }
+
+ @Transactional
+ public boolean execute()
+ {
+ if (!validateSignIn()) // Credentials are invalid
+ return false;
+
+ Optional employee = // Finds employee by employee ID
+ employeeRepository.findByEmployeeId(
+ Integer.parseInt(employeeSignIn.getId()));
+
+ if (!employee.isPresent()) // Employee does not exist
+ return false;
+
+ if (!Arrays.equals( // Passwords do NOT match
+ employeeSignIn.getPassword().getBytes(),
+ employee.get().getPassword()))
+ {
+ return false;
+ }
+
+ // NOTE: At this point, we have a valid sign in
+
+ Optional activeUser = // Finds active user by UUID
+ activeUserRepository.findByEmployeeId(employee.get().getId());
+
+ if (activeUser.isPresent()) // Updates existing active user's session key
+ {
+ ActiveUserEntity user = activeUser.get().setSessionKey(sessionKey);
+ activeUserRepository.save(user);
+ }
+ else // Creates new active user
+ {
+ ActiveUserEntity user = new ActiveUserEntity();
+
+ user.setClassification(employee.get().getClassification());
+
+ // Create full name then set active user name
+ String employeeName = employee.get().getFirstName();
+ employeeName.concat(" ").concat(employee.get().getLastName());
+
+ user.setName(employeeName);
+
+ user.setEmployeeId(employee.get().getId());
+ user.setSessionKey(sessionKey);
+
+ // New active user entry - complete
+ activeUserRepository.save(user);
+
+ // Update 'active' column on employee table to true
+ employee.get().setIsActive(true);
+ employeeRepository.save(employee.get());
+ }
+
+ return true;
+ }
+
+ private boolean validateSignIn()
+ {
+ String employeeId = employeeSignIn.getId();
+
+ if (StringUtils.isBlank(employeeId) || employeeId.length() > 5)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < employeeId.length(); i++)
+ {
+ if(!(employeeId.charAt(i) >= '0' && employeeId.charAt(i) <= '9'))
+ {
+ return false;
+ }
+ }
+
+ if(StringUtils.isBlank(employeeSignIn.getPassword()))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ /*
+ ONLY CALLED BY SignInRouteController
+ PROBABLY A BAD WAY TO DO THIS
+ I think @Autowired doesn't work because this class is not a controller...
+ ...hence SignInRouteController setting this property
+ */
+ public void setEmployeeRepository(EmployeeRepository employeeRepository)
+ {
+ this.employeeRepository = employeeRepository;
+ }
+
+ // THIS IS ALSO PROBABLY BAD FOR THE SAME REASON AS ABOVE
+ public void setActiveUserRepository(ActiveUserRepository activeUserRepository)
+ {
+ this.activeUserRepository = activeUserRepository;
+ }
+
+ private EmployeeRepository employeeRepository;
+ private ActiveUserRepository activeUserRepository;
+}
diff --git a/src/main/java/edu/uark/registerapp/controllers/EmployeeDetailRouteController.java b/src/main/java/edu/uark/registerapp/controllers/EmployeeDetailRouteController.java
new file mode 100644
index 00000000..153e7303
--- /dev/null
+++ b/src/main/java/edu/uark/registerapp/controllers/EmployeeDetailRouteController.java
@@ -0,0 +1,58 @@
+package edu.uark.registerapp.controllers;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.servlet.ModelAndView;
+
+import edu.uark.registerapp.controllers.enums.ViewNames;
+import edu.uark.registerapp.models.entities.EmployeeEntity;
+import edu.uark.registerapp.models.repositories.EmployeeRepository;
+
+@Controller
+@RequestMapping(value = "/employeeDetail")
+public class EmployeeDetailRouteController extends BaseRouteController {
+ @RequestMapping(method = RequestMethod.GET)
+ public ModelAndView showEmployeeDetail()
+ {
+ return new ModelAndView(ViewNames.EMPLOYEE_DETAIL.getViewName());
+ }
+
+ @RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+ public ModelAndView makeNewEmployee(
+ EmployeeEntity employee,
+ HttpServletRequest request
+ )
+ {
+ employee = new EmployeeEntity();
+
+ employee.setFirstName(request.getParameter("firstname"));
+ employee.setLastName(request.getParameter("lastname"));
+ employee.setPassword(request.getParameter("password").getBytes());
+ employee.setClassification(Integer.parseInt(
+ request.getParameter("classification")));
+
+ employeeRepository.save(employee);
+
+ if (this.employeeRepository.count() == 1)
+ {
+ ModelAndView modelAndView = new ModelAndView(
+ REDIRECT_PREPEND.concat(ViewNames.SIGN_IN.getRoute()));
+
+ modelAndView.addObject("Method", "GET");
+
+ return modelAndView;
+ }
+ else
+ return new ModelAndView(ViewNames.EMPLOYEE_DETAIL.getViewName());
+
+ //return new ModelAndView(ViewNames.EMPLOYEE_DETAIL.getViewName());
+ }
+
+ @Autowired
+ EmployeeRepository employeeRepository;
+}
diff --git a/src/main/java/edu/uark/registerapp/controllers/MainMenuRouteController.java b/src/main/java/edu/uark/registerapp/controllers/MainMenuRouteController.java
new file mode 100644
index 00000000..fd6487fd
--- /dev/null
+++ b/src/main/java/edu/uark/registerapp/controllers/MainMenuRouteController.java
@@ -0,0 +1,55 @@
+package edu.uark.registerapp.controllers;
+
+import java.util.Map;
+import java.util.Optional;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.servlet.ModelAndView;
+
+import edu.uark.registerapp.controllers.enums.ViewModelNames;
+import edu.uark.registerapp.controllers.enums.ViewNames;
+import edu.uark.registerapp.models.entities.ActiveUserEntity;
+import edu.uark.registerapp.models.enums.EmployeeClassification;
+
+@Controller
+@RequestMapping(value = "/mainMenu")
+public class MainMenuRouteController extends BaseRouteController {
+
+ @RequestMapping(method = RequestMethod.GET)
+ public ModelAndView start(
+ @RequestParam final Map queryParameters,
+ final HttpServletRequest request
+ ) {
+
+ final Optional activeUserEntity =
+ this.getCurrentUser(request);
+ if (!activeUserEntity.isPresent()) {
+ return this.buildInvalidSessionResponse();
+ }
+
+ ModelAndView modelAndView =
+ this.setErrorMessageFromQueryString(
+ new ModelAndView(ViewNames.MAIN_MENU.getViewName()),
+ queryParameters);
+
+ // Check if user is any kind of manager
+ if (EmployeeClassification.isElevatedUser(
+ activeUserEntity.get().getClassification()))
+ {
+ modelAndView.addObject(
+ ViewModelNames.IS_ELEVATED_USER.getValue(), true);
+ }
+ else
+ {
+ modelAndView.addObject(
+ ViewModelNames.IS_ELEVATED_USER.getValue(), false);
+ }
+
+ return modelAndView;
+ }
+}
diff --git a/src/main/java/edu/uark/registerapp/controllers/ProductListingRouteController.java b/src/main/java/edu/uark/registerapp/controllers/ProductListingRouteController.java
index 3c2a1178..e96a45fb 100644
--- a/src/main/java/edu/uark/registerapp/controllers/ProductListingRouteController.java
+++ b/src/main/java/edu/uark/registerapp/controllers/ProductListingRouteController.java
@@ -12,7 +12,7 @@
import edu.uark.registerapp.models.api.Product;
@Controller
-@RequestMapping(value = "/")
+@RequestMapping(value = "/productListing")
public class ProductListingRouteController {
@RequestMapping(method = RequestMethod.GET)
public ModelAndView showProductListing() {
diff --git a/src/main/java/edu/uark/registerapp/controllers/SignInRestController.java b/src/main/java/edu/uark/registerapp/controllers/SignInRestController.java
new file mode 100644
index 00000000..f7153d83
--- /dev/null
+++ b/src/main/java/edu/uark/registerapp/controllers/SignInRestController.java
@@ -0,0 +1,42 @@
+package edu.uark.registerapp.controllers;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import edu.uark.registerapp.commands.activeUsers.ActiveUserDeleteCommand;
+import edu.uark.registerapp.controllers.enums.ViewNames;
+import edu.uark.registerapp.models.api.ApiResponse;
+import edu.uark.registerapp.models.repositories.ActiveUserRepository;
+import edu.uark.registerapp.models.repositories.EmployeeRepository;
+
+@RestController
+@RequestMapping(value = "/api")
+public class SignInRestController extends BaseRestController {
+ @RequestMapping(value="/signOut", method = RequestMethod.DELETE)
+ public @ResponseBody ApiResponse removeActiveUser(
+ final HttpServletRequest request
+ ) {
+ ActiveUserDeleteCommand signOutCommand =
+ new ActiveUserDeleteCommand(
+ request.getSession().getId(),
+ this.activeUserRepository,
+ this.employeeRepository);
+
+ signOutCommand.execute();
+
+ return (new ApiResponse())
+ .setRedirectUrl(ViewNames.SIGN_IN.getRoute());
+ }
+
+ // Properties
+ @Autowired
+ private ActiveUserRepository activeUserRepository;
+
+ @Autowired
+ private EmployeeRepository employeeRepository;
+}
diff --git a/src/main/java/edu/uark/registerapp/controllers/SignInRouteController.java b/src/main/java/edu/uark/registerapp/controllers/SignInRouteController.java
new file mode 100644
index 00000000..47734d3f
--- /dev/null
+++ b/src/main/java/edu/uark/registerapp/controllers/SignInRouteController.java
@@ -0,0 +1,87 @@
+package edu.uark.registerapp.controllers;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.servlet.ModelAndView;
+
+import edu.uark.registerapp.commands.employees.EmployeeSignInCommand;
+import edu.uark.registerapp.commands.exceptions.NotFoundException;
+import edu.uark.registerapp.controllers.enums.ViewModelNames;
+import edu.uark.registerapp.controllers.enums.ViewNames;
+
+import edu.uark.registerapp.models.api.EmployeeSignIn;
+import edu.uark.registerapp.models.repositories.ActiveUserRepository;
+import edu.uark.registerapp.models.repositories.EmployeeRepository;
+
+
+@Controller
+@RequestMapping(value = "/")
+public class SignInRouteController extends BaseRouteController
+{
+ @RequestMapping(method = RequestMethod.GET)
+ public ModelAndView showSignIn()
+ {
+ // Check if any employees exist. If none, redirect to employeeDetail.
+ if (this.employeeRepository.count() == 0)
+ {
+ return new ModelAndView(
+ REDIRECT_PREPEND.concat(ViewNames.EMPLOYEE_DETAIL.getRoute()));
+ }
+
+ return new ModelAndView(ViewNames.SIGN_IN.getViewName());
+ }
+
+ @RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+ public ModelAndView performSignIn(
+ EmployeeSignIn signIn,
+ HttpServletRequest request)
+ {
+ signIn = new EmployeeSignIn(request.getParameter("employeeId"),
+ request.getParameter("password"));
+
+ EmployeeSignInCommand signInCommand = new EmployeeSignInCommand(signIn,
+ request.getSession().getId());
+
+ // See comments on this set method in EmployeeSignInCommand.java
+ // TLDR: I don't like doing it this way but I don't know how to do better
+ signInCommand.setEmployeeRepository(this.employeeRepository);
+ signInCommand.setActiveUserRepository(this.activeUserRepository);
+
+ /*
+ We don't need to validate the sign in information here because
+ EmployeeSignInCommand.execute() does this and returns false
+ if unsuccessful.
+ */
+
+ if (signInCommand.execute()) // Sign in is successful...
+ {
+ return new ModelAndView(
+ REDIRECT_PREPEND.concat(ViewNames.MAIN_MENU.getRoute()));
+ }
+ else
+ {
+ ModelAndView modelAndView =
+ new ModelAndView(ViewNames.SIGN_IN.getViewName());
+
+ final Exception e =
+ new NotFoundException("An employee with matching ID or password");
+
+ modelAndView.addObject(
+ ViewModelNames.ERROR_MESSAGE.getValue(),
+ e.getMessage());
+
+ return modelAndView;
+ }
+ }
+
+ @Autowired
+ EmployeeRepository employeeRepository;
+
+ @Autowired
+ ActiveUserRepository activeUserRepository;
+}
diff --git a/src/main/java/edu/uark/registerapp/controllers/enums/ViewModelNames.java b/src/main/java/edu/uark/registerapp/controllers/enums/ViewModelNames.java
index 7c39b102..6ee26935 100644
--- a/src/main/java/edu/uark/registerapp/controllers/enums/ViewModelNames.java
+++ b/src/main/java/edu/uark/registerapp/controllers/enums/ViewModelNames.java
@@ -3,6 +3,7 @@
public enum ViewModelNames {
NOT_DEFINED(""),
ERROR_MESSAGE("errorMessage"),
+ IS_ELEVATED_USER("isElevatedUser"),
PRODUCTS("products"), // Product listing
PRODUCT("product"); // Product detail
diff --git a/src/main/java/edu/uark/registerapp/models/api/EmployeeSignIn.java b/src/main/java/edu/uark/registerapp/models/api/EmployeeSignIn.java
new file mode 100644
index 00000000..f37f59ae
--- /dev/null
+++ b/src/main/java/edu/uark/registerapp/models/api/EmployeeSignIn.java
@@ -0,0 +1,35 @@
+package edu.uark.registerapp.models.api;
+
+public class EmployeeSignIn {
+
+ private String employeeId;
+ private String password;
+
+ public EmployeeSignIn(String employeeId, String password)
+ {
+ this.employeeId = employeeId;
+ this.password = password;
+ }
+
+ public EmployeeSignIn(int employeeId, String password)
+ {
+ this.employeeId = Integer.toString(employeeId);
+ this.password = password;
+ }
+
+ public EmployeeSignIn()
+ {
+ this.employeeId = "";
+ this.password = "";
+ }
+
+ public String getId()
+ {
+ return this.employeeId;
+ }
+
+ public String getPassword()
+ {
+ return this.password;
+ }
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 301f32d2..ba5527df 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,8 +1,6 @@
spring.session.store-type=HAZELCAST
-spring.datasource.url=${JDBC_DATABASE_URL}
-spring.datasource.username=${JDBC_DATABASE_USERNAME}
-spring.datasource.password=${JDBC_DATABASE_PASSWORD}
+spring.datasource.url=jdbc:postgresql://ec2-50-16-108-254.compute-1.amazonaws.com:5432/dr0tn6cgvje1i?password=71048d253b3d26369694a983c9d05a5786dd9dfbe504b3e4f0156c8e3d13fff6&sslmode=require&user=xiwltegjgspgse
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.platform=org.hibernate.dialect.PostgreSQLDialect
spring.datasource.maxActive=5
diff --git a/src/main/resources/static/images/Sign-Out.png b/src/main/resources/static/images/Sign-Out.png
new file mode 100644
index 00000000..82fe8695
Binary files /dev/null and b/src/main/resources/static/images/Sign-Out.png differ
diff --git a/src/main/resources/static/scripts/mainMenu.js b/src/main/resources/static/scripts/mainMenu.js
new file mode 100644
index 00000000..9d52c6e1
--- /dev/null
+++ b/src/main/resources/static/scripts/mainMenu.js
@@ -0,0 +1,52 @@
+window.addEventListener('DOMContentLoaded', (event) => {
+ document.getElementById("productsButton").addEventListener('click', goToProductListing);
+ document.getElementById("employeeButton").addEventListener('click', goToEmployeeDetail);
+ document.getElementById("transactionButton").addEventListener('click', displayError);
+ document.getElementById("salesButton").addEventListener('click', displayError);
+ document.getElementById("cashierButton").addEventListener('click', displayError);
+});
+
+// Hide button from users that aren't managers
+if(EmployeeClassification.isElevatedUser())
+{
+ document.getElementById("employeeButton").style.visbility="hidden";
+ document.getElementById("salesButton").style.visbility="hidden";
+ document.getElementById("cashierButton").style.visbility="hidden";
+}
+
+
+// Navigate to products listing page
+function goToProductListing(event)
+{
+ window.location.assign(
+ "/productListing/"
+ );
+}
+
+// Navigate to employee detail page
+function goToEmployeeDetail(event)
+{
+ window.location.assign("/employeeDetail/");
+}
+
+// Display error message
+function displayError(errorMessage) {
+ errorMessage = "Functionality has not yet been implemented.";
+ if ((errorMessage == null) || (errorMessage === "")) {
+ return;
+ }
+
+ const errorMessageDisplayElement = getErrorMessageDisplayElement();
+ const errorMessageContainerElement = getErrorMessageContainerElement();
+
+ if ((errorMessageContainerElement == null)
+ || (errorMessageDisplayElement == null)) {
+
+ return;
+ }
+
+ errorMessageDisplayElement.innerHTML = errorMessage;
+ if (errorMessageContainerElement.classList.contains("hidden")) {
+ errorMessageContainerElement.classList.remove("hidden");
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/static/scripts/signIn.js b/src/main/resources/static/scripts/signIn.js
new file mode 100644
index 00000000..0c420b16
--- /dev/null
+++ b/src/main/resources/static/scripts/signIn.js
@@ -0,0 +1,35 @@
+document.addEventListener("DOMContentLoaded", function(event)
+{
+});
+
+function validateForm()
+{
+ // Validate employeeId
+ let employeeId = document.forms["signIn"]["employeeId"].value;
+
+ if (employeeId.length == 0)
+ {
+ alert("Please enter your ID!");
+ return false;
+ }
+
+ /*
+ There is no need to check if the employeeId entered is an integer.
+ This is because the form entry has type="number", which means this
+ function won't even be called if the entered value isn't an integer.
+
+ This function also doesn't need to check for ID size because the
+ input's "max" attribute takes care of that.
+ */
+
+ // Validate password
+ let password = document.forms["signIn"]["password"].value;
+
+ if (password.length == 0)
+ {
+ alert("Please enter your password!");
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/main/resources/static/styles/employeeDetail.css b/src/main/resources/static/styles/employeeDetail.css
new file mode 100644
index 00000000..51251dec
--- /dev/null
+++ b/src/main/resources/static/styles/employeeDetail.css
@@ -0,0 +1,35 @@
+form {
+ width: 25%;
+ padding: 40px 30px;
+ border-radius: 7px;
+ border: 3px solid black;
+}
+
+input, select {
+ width: 100%;
+ padding: 12px 20px;
+ margin: 8px 0;
+ display: inline-block;
+ border: 1px solid #ccc;
+ box-sizing: border-box;
+ font-family: 'Times New Roman', Times, serif;
+}
+
+input[type=submit] {
+ background-color: white;
+ border: 2px solid black;
+ color: black;
+ font-family: 'Times New Roman', Times, serif;
+ font-weight: bold;
+ padding: 10px;
+ margin: 10 auto;
+ cursor: pointer;
+ width: 25%;
+ display: block;
+}
+
+input[type=submit]:hover {
+ color: white;
+ background-color: black;
+ box-shadow: 2px 2px 5px gray;
+}
\ No newline at end of file
diff --git a/src/main/resources/static/styles/mainMenu.css b/src/main/resources/static/styles/mainMenu.css
new file mode 100644
index 00000000..2f2f13c8
--- /dev/null
+++ b/src/main/resources/static/styles/mainMenu.css
@@ -0,0 +1,23 @@
+.navButtons {
+ margin-top: 20px;
+}
+
+.button {
+ background-color: white;
+ border: 4px solid black;
+ color: black;
+ font-family: 'Times New Roman', Times, serif;
+ font-weight: bold;
+ font-size: 18px;
+ padding: 24px 24px;
+ margin: 10 auto;
+ cursor: pointer;
+ width: 25%;
+ display: block;
+}
+
+.button:hover {
+ color: white;
+ background-color: black;
+ box-shadow: 2px 2px 5px gray;
+}
\ No newline at end of file
diff --git a/src/main/resources/static/styles/signIn.css b/src/main/resources/static/styles/signIn.css
new file mode 100644
index 00000000..eff8223c
--- /dev/null
+++ b/src/main/resources/static/styles/signIn.css
@@ -0,0 +1,36 @@
+form {
+ width: 25%;
+ padding: 40px 30px;
+ border-radius: 7px;
+ border: 3px solid black;
+}
+
+input[type=number], input[type=password] {
+ width: 100%;
+ padding: 12px 20px;
+ margin: 8px 0;
+ display: inline-block;
+ border: 1px solid #ccc;
+ box-sizing: border-box;
+ font-family: 'Times New Roman', Times, serif;
+}
+
+input[type=submit] {
+ background-color: white;
+ border: 2px solid black;
+ color: black;
+ font-family: 'Times New Roman', Times, serif;
+ font-weight: bold;
+ padding: 10px;
+ margin: 10 auto;
+ cursor: pointer;
+ width: 25%;
+ display: block;
+}
+
+input[type=submit]:hover {
+ color: white;
+ background-color: black;
+
+ box-shadow: 2px 2px 5px gray;
+}
\ No newline at end of file
diff --git a/src/main/resources/templates/employeeDetail.html b/src/main/resources/templates/employeeDetail.html
new file mode 100644
index 00000000..8928eca4
--- /dev/null
+++ b/src/main/resources/templates/employeeDetail.html
@@ -0,0 +1,57 @@
+
+
+
+ Employee Detail
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/templates/mainMenu.html b/src/main/resources/templates/mainMenu.html
new file mode 100644
index 00000000..28f88ee7
--- /dev/null
+++ b/src/main/resources/templates/mainMenu.html
@@ -0,0 +1,56 @@
+
+
+
+ Register - Main Menu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/templates/productDetail.html b/src/main/resources/templates/productDetail.html
index ac183115..9539e0f4 100644
--- a/src/main/resources/templates/productDetail.html
+++ b/src/main/resources/templates/productDetail.html
@@ -68,6 +68,10 @@
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/templates/productListing.html b/src/main/resources/templates/productListing.html
index c4b758ae..38141d1f 100644
--- a/src/main/resources/templates/productListing.html
+++ b/src/main/resources/templates/productListing.html
@@ -54,6 +54,10 @@
diff --git a/src/main/resources/templates/signIn.html b/src/main/resources/templates/signIn.html
new file mode 100644
index 00000000..ee30d70f
--- /dev/null
+++ b/src/main/resources/templates/signIn.html
@@ -0,0 +1,37 @@
+
+
+