Compare commits
	
		
			No commits in common. "df7ca1ab90af081c6126d8a9c4377a3a0fafdd4f" and "3a7663124d92fcfdefb02103119e0c9aec8afed2" have entirely different histories.
		
	
	
		
			df7ca1ab90
			...
			3a7663124d
		
	
		
					 49 changed files with 96 additions and 1277 deletions
				
			
		
							
								
								
									
										7
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -6,13 +6,8 @@
 | 
				
			||||||
*.dylib
 | 
					*.dylib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bin
 | 
					bin
 | 
				
			||||||
database.txt
 | 
					 | 
				
			||||||
plantuml.jar
 | 
					 | 
				
			||||||
db.sqlite3
 | 
					db.sqlite3
 | 
				
			||||||
diagram.puml
 | 
					*.png
 | 
				
			||||||
backend/*.png
 | 
					 | 
				
			||||||
backend/*.jpg
 | 
					 | 
				
			||||||
backend/*.svg
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Test binary, built with `go test -c`
 | 
					# Test binary, built with `go test -c`
 | 
				
			||||||
*.test
 | 
					*.test
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										15
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										15
									
								
								README.md
									
										
									
									
									
								
							| 
						 | 
					@ -62,21 +62,6 @@ You should consult the [WSL documentation](https://docs.microsoft.com/en-us/wind
 | 
				
			||||||
wsl --install -d Ubuntu-22.04 # To get a somewhat recent version of Go
 | 
					wsl --install -d Ubuntu-22.04 # To get a somewhat recent version of Go
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
After this, you can open a (wsl) terminal and run the commands:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```bash
 | 
					 | 
				
			||||||
sudo apt update && sudo apt upgrade
 | 
					 | 
				
			||||||
sudo apt install -y make podman
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sudo add-apt-repository ppa:longsleep/golang-backports
 | 
					 | 
				
			||||||
sudo apt update
 | 
					 | 
				
			||||||
sudo apt install golang-go
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# For a recent version of node:
 | 
					 | 
				
			||||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
 | 
					 | 
				
			||||||
nvm install node
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
If you get any errors related to virtualization, you will need to enable virtualization in the BIOS. This is a common issue, and you can find a guide for your specific motherboard online. This is a one-time operation and will not affect your windows installation. This setting is usually called "VT-x" or "AMD-V" and is usually found in the CPU settings. If you can't find it, shoot me a message and I'll find it for you.
 | 
					If you get any errors related to virtualization, you will need to enable virtualization in the BIOS. This is a common issue, and you can find a guide for your specific motherboard online. This is a one-time operation and will not affect your windows installation. This setting is usually called "VT-x" or "AMD-V" and is usually found in the CPU settings. If you can't find it, shoot me a message and I'll find it for you.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
If you're **still dead set** on using a vanilla Windows environment, you will need the following:
 | 
					If you're **still dead set** on using a vanilla Windows environment, you will need the following:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,10 +27,6 @@ clean:
 | 
				
			||||||
	$(GOCLEAN)
 | 
						$(GOCLEAN)
 | 
				
			||||||
	rm -rf bin
 | 
						rm -rf bin
 | 
				
			||||||
	rm -f db.sqlite3
 | 
						rm -f db.sqlite3
 | 
				
			||||||
	rm -f diagram*
 | 
					 | 
				
			||||||
	rm -f plantuml.jar
 | 
					 | 
				
			||||||
	rm -f erd.png
 | 
					 | 
				
			||||||
	rm -f config.toml
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Test target
 | 
					# Test target
 | 
				
			||||||
test: db.sqlite3
 | 
					test: db.sqlite3
 | 
				
			||||||
| 
						 | 
					@ -58,9 +54,6 @@ migrate:
 | 
				
			||||||
db.sqlite3:
 | 
					db.sqlite3:
 | 
				
			||||||
	make migrate
 | 
						make migrate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dbdump:
 | 
					 | 
				
			||||||
	sqlite3 $(DB_FILE) .dump > database.txt
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
backup:
 | 
					backup:
 | 
				
			||||||
	mkdir -p backups
 | 
						mkdir -p backups
 | 
				
			||||||
	sqlite3 $(DB_FILE) .dump | gzip -9 > ./backups/BACKUP_$(DB_FILE)_$(shell date +"%Y-%m-%d_%H:%M:%S").sql.gz
 | 
						sqlite3 $(DB_FILE) .dump | gzip -9 > ./backups/BACKUP_$(DB_FILE)_$(shell date +"%Y-%m-%d_%H:%M:%S").sql.gz
 | 
				
			||||||
| 
						 | 
					@ -102,18 +95,6 @@ install-lint:
 | 
				
			||||||
	@echo "Installing golangci-lint"
 | 
						@echo "Installing golangci-lint"
 | 
				
			||||||
	@curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(shell go env GOPATH)/bin v1.42.1
 | 
						@curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(shell go env GOPATH)/bin v1.42.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Fetches the latest plantuml.jar and checks its SHA256 hash
 | 
					 | 
				
			||||||
plantuml.jar:
 | 
					 | 
				
			||||||
	curl -sSfL https://github.com/plantuml/plantuml/releases/download/v1.2024.3/plantuml.jar -o plantuml.jar \
 | 
					 | 
				
			||||||
	&& echo "519a4a7284c6a0357c369e4bb0caf72c4bfbbde851b8c6d6bbdb7af3c01fc82f plantuml.jar" | sha256sum -c
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Generate UML diagrams diagral.png & diagram.svg
 | 
					 | 
				
			||||||
.PHONY: uml
 | 
					 | 
				
			||||||
uml: plantuml.jar
 | 
					 | 
				
			||||||
	goplantuml -recursive . > diagram.puml
 | 
					 | 
				
			||||||
	java -jar plantuml.jar -tpng diagram.puml
 | 
					 | 
				
			||||||
	java -jar plantuml.jar -tsvg diagram.puml
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Convenience target to install just (requires sudo privileges)
 | 
					# Convenience target to install just (requires sudo privileges)
 | 
				
			||||||
install-just:
 | 
					install-just:
 | 
				
			||||||
	@echo "Installing just"
 | 
						@echo "Installing just"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,17 +14,18 @@ import (
 | 
				
			||||||
type Database interface {
 | 
					type Database interface {
 | 
				
			||||||
	// Insert a new user into the database, password should be hashed before calling
 | 
						// Insert a new user into the database, password should be hashed before calling
 | 
				
			||||||
	AddUser(username string, password string) error
 | 
						AddUser(username string, password string) error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	RemoveUser(username string) error
 | 
						RemoveUser(username string) error
 | 
				
			||||||
	PromoteToAdmin(username string) error
 | 
						PromoteToAdmin(username string) error
 | 
				
			||||||
	GetUserId(username string) (int, error)
 | 
						GetUserId(username string) (int, error)
 | 
				
			||||||
	AddProject(name string, description string, username string) error
 | 
						AddProject(name string, description string, username string) error
 | 
				
			||||||
	Migrate(dirname string) error
 | 
						Migrate(dirname string) error
 | 
				
			||||||
	GetProjectId(projectname string) (int, error)
 | 
						// AddTimeReport(projectname string, start time.Time, end time.Time) error
 | 
				
			||||||
	AddTimeReport(projectName string, userName string, start time.Time, end time.Time) error
 | 
						// AddUserToProject(username string, projectname string) error
 | 
				
			||||||
	AddUserToProject(username string, projectname string, role string) error
 | 
						// ChangeUserRole(username string, projectname string, role string) error
 | 
				
			||||||
	ChangeUserRole(username string, projectname string, role string) error
 | 
						// AddTimeReport(projectname string, start time.Time, end time.Time) error
 | 
				
			||||||
	GetAllUsersProject(projectname string) ([]UserProjectMember, error)
 | 
						// AddUserToProject(username string, projectname string) error
 | 
				
			||||||
	GetAllUsersApplication() ([]string, error)
 | 
						// ChangeUserRole(username string, projectname string, role string) error
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// This struct is a wrapper type that holds the database connection
 | 
					// This struct is a wrapper type that holds the database connection
 | 
				
			||||||
| 
						 | 
					@ -33,24 +34,15 @@ type Db struct {
 | 
				
			||||||
	*sqlx.DB
 | 
						*sqlx.DB
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type UserProjectMember struct {
 | 
					 | 
				
			||||||
	Username string `db:"username"`
 | 
					 | 
				
			||||||
	UserRole string `db:"p_role"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//go:embed migrations
 | 
					//go:embed migrations
 | 
				
			||||||
var scripts embed.FS
 | 
					var scripts embed.FS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: Possibly break these out into separate files bundled with the embed package?
 | 
					 | 
				
			||||||
const userInsert = "INSERT INTO users (username, password) VALUES (?, ?)"
 | 
					const userInsert = "INSERT INTO users (username, password) VALUES (?, ?)"
 | 
				
			||||||
const projectInsert = "INSERT INTO projects (name, description, owner_user_id) SELECT ?, ?, id FROM users WHERE username = ?"
 | 
					const projectInsert = "INSERT INTO projects (name, description, owner_user_id) SELECT ?, ?, id FROM users WHERE username = ?"
 | 
				
			||||||
const promoteToAdmin = "INSERT INTO site_admin (admin_id) SELECT id FROM users WHERE username = ?"
 | 
					const promoteToAdmin = "INSERT INTO site_admin (admin_id) SELECT id FROM users WHERE username = ?"
 | 
				
			||||||
const addTimeReport = `WITH UserLookup AS (SELECT id FROM users WHERE username = ?), 
 | 
					const addTimeReport = "INSERT INTO activity (report_id, activity_nbr, start_time, end_time, break, comment) VALUES (?, ?, ?, ?, ?, ?)" // WIP
 | 
				
			||||||
						ProjectLookup AS (SELECT id FROM projects WHERE name = ?)
 | 
					const addUserToProject = "INSERT INTO project_member (project_id, user_id, role) VALUES (?, ?, ?)"                                     // WIP
 | 
				
			||||||
						INSERT INTO time_reports (project_id, user_id, start, end) 
 | 
					// const changeUserRole = ""
 | 
				
			||||||
						VALUES ((SELECT id FROM ProjectLookup), (SELECT id FROM UserLookup), ?, ?);`
 | 
					 | 
				
			||||||
const addUserToProject = "INSERT INTO user_roles (user_id, project_id, p_role) VALUES (?, ?, ?)" // WIP
 | 
					 | 
				
			||||||
const changeUserRole = "UPDATE user_roles SET p_role = ? WHERE user_id = ? AND project_id = ?"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DbConnect connects to the database
 | 
					// DbConnect connects to the database
 | 
				
			||||||
func DbConnect(dbpath string) Database {
 | 
					func DbConnect(dbpath string) Database {
 | 
				
			||||||
| 
						 | 
					@ -69,8 +61,8 @@ func DbConnect(dbpath string) Database {
 | 
				
			||||||
	return &Db{db}
 | 
						return &Db{db}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *Db) AddTimeReport(projectName string, userName string, start time.Time, end time.Time) error { // WIP
 | 
					func (d *Db) AddTimeReport(projectname string, start time.Time, end time.Time, breakTime uint32) error { // WIP
 | 
				
			||||||
	_, err := d.Exec(addTimeReport, userName, projectName, start, end)
 | 
						_, err := d.Exec(addTimeReport, projectname, 0, start, end, breakTime, false)
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -87,26 +79,13 @@ func (d *Db) AddUserToProject(username string, projectname string, role string)
 | 
				
			||||||
		panic(err2)
 | 
							panic(err2)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, err3 := d.Exec(addUserToProject, userid, projectid, role)
 | 
						_, err3 := d.Exec(addUserToProject, projectid, userid, role)
 | 
				
			||||||
	return err3
 | 
						return err3
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *Db) ChangeUserRole(username string, projectname string, role string) error {
 | 
					// func (d *Db) ChangeUserRole(username string, projectname string, role string) error {
 | 
				
			||||||
	var userid int
 | 
					 | 
				
			||||||
	userid, err := d.GetUserId(username)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		panic(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var projectid int
 | 
					// }
 | 
				
			||||||
	projectid, err2 := d.GetProjectId(projectname)
 | 
					 | 
				
			||||||
	if err2 != nil {
 | 
					 | 
				
			||||||
		panic(err2)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	_, err3 := d.Exec(changeUserRole, role, userid, projectid)
 | 
					 | 
				
			||||||
	return err3
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// AddUser adds a user to the database
 | 
					// AddUser adds a user to the database
 | 
				
			||||||
func (d *Db) AddUser(username string, password string) error {
 | 
					func (d *Db) AddUser(username string, password string) error {
 | 
				
			||||||
| 
						 | 
					@ -131,9 +110,9 @@ func (d *Db) GetUserId(username string) (int, error) {
 | 
				
			||||||
	return id, err
 | 
						return id, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *Db) GetProjectId(projectname string) (int, error) {
 | 
					func (d *Db) GetProjectId(projectname string) (int, error) { // WIP, denna kan vara goof
 | 
				
			||||||
	var id int
 | 
						var id int
 | 
				
			||||||
	err := d.Get(&id, "SELECT id FROM projects WHERE name = ?", projectname)
 | 
						err := d.Get(&id, "SELECT id FROM project WHERE project_name = ?", projectname)
 | 
				
			||||||
	return id, err
 | 
						return id, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -143,69 +122,6 @@ func (d *Db) AddProject(name string, description string, username string) error
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *Db) GetAllUsersProject(projectname string) ([]UserProjectMember, error) {
 | 
					 | 
				
			||||||
	// Define the SQL query to fetch users and their roles for a given project
 | 
					 | 
				
			||||||
	query := `
 | 
					 | 
				
			||||||
        SELECT u.username, ur.p_role
 | 
					 | 
				
			||||||
        FROM users u
 | 
					 | 
				
			||||||
        INNER JOIN user_roles ur ON u.id = ur.user_id
 | 
					 | 
				
			||||||
        INNER JOIN projects p ON ur.project_id = p.id
 | 
					 | 
				
			||||||
        WHERE p.name = ?
 | 
					 | 
				
			||||||
    `
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Execute the query
 | 
					 | 
				
			||||||
	rows, err := d.Queryx(query, projectname)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer rows.Close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Iterate over the rows and populate the result slice
 | 
					 | 
				
			||||||
	var users []UserProjectMember
 | 
					 | 
				
			||||||
	for rows.Next() {
 | 
					 | 
				
			||||||
		var user UserProjectMember
 | 
					 | 
				
			||||||
		if err := rows.StructScan(&user); err != nil {
 | 
					 | 
				
			||||||
			return nil, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		users = append(users, user)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if err := rows.Err(); err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return users, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// GetAllUsersApplication retrieves all usernames from the database
 | 
					 | 
				
			||||||
func (d *Db) GetAllUsersApplication() ([]string, error) {
 | 
					 | 
				
			||||||
	// Define the SQL query to fetch all usernames
 | 
					 | 
				
			||||||
	query := `
 | 
					 | 
				
			||||||
        SELECT username FROM users
 | 
					 | 
				
			||||||
    `
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Execute the query
 | 
					 | 
				
			||||||
	rows, err := d.Queryx(query)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer rows.Close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Iterate over the rows and populate the result slice
 | 
					 | 
				
			||||||
	var usernames []string
 | 
					 | 
				
			||||||
	for rows.Next() {
 | 
					 | 
				
			||||||
		var username string
 | 
					 | 
				
			||||||
		if err := rows.Scan(&username); err != nil {
 | 
					 | 
				
			||||||
			return nil, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		usernames = append(usernames, username)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if err := rows.Err(); err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return usernames, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Reads a directory of migration files and applies them to the database.
 | 
					// Reads a directory of migration files and applies them to the database.
 | 
				
			||||||
// This will eventually be used on an embedded directory
 | 
					// This will eventually be used on an embedded directory
 | 
				
			||||||
func (d *Db) Migrate(dirname string) error {
 | 
					func (d *Db) Migrate(dirname string) error {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,6 @@ package database
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Tests are not guaranteed to be sequential
 | 
					// Tests are not guaranteed to be sequential
 | 
				
			||||||
| 
						 | 
					@ -93,196 +92,14 @@ func TestPromoteToAdmin(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestAddTimeReport(t *testing.T) {
 | 
					// func TestAddTimeReport(t *testing.T) {
 | 
				
			||||||
	db, err := setupState()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("setupState failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = db.AddUser("testuser", "password")
 | 
					// }
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("AddUser failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = db.AddProject("testproject", "description", "testuser")
 | 
					// func TestAddUserToProject(t *testing.T) {
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("AddProject failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var now = time.Now()
 | 
					// }
 | 
				
			||||||
	var then = now.Add(time.Hour)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = db.AddTimeReport("testproject", "testuser", now, then)
 | 
					// func TestChangeUserRole(t *testing.T) {
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("AddTimeReport failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestAddUserToProject(t *testing.T) {
 | 
					// }
 | 
				
			||||||
	db, err := setupState()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("setupState failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = db.AddUser("testuser", "password")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("AddUser failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = db.AddProject("testproject", "description", "testuser")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("AddProject failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var now = time.Now()
 | 
					 | 
				
			||||||
	var then = now.Add(time.Hour)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = db.AddTimeReport("testproject", "testuser", now, then)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("AddTimeReport failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = db.AddUserToProject("testuser", "testproject", "user")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("AddUserToProject failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestChangeUserRole(t *testing.T) {
 | 
					 | 
				
			||||||
	db, err := setupState()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("setupState failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = db.AddUser("testuser", "password")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("AddUser failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = db.AddProject("testproject", "description", "testuser")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("AddProject failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = db.AddUserToProject("testuser", "testproject", "user")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("AddUserToProject failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = db.ChangeUserRole("testuser", "testproject", "admin")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("ChangeUserRole failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestGetAllUsersProject(t *testing.T) {
 | 
					 | 
				
			||||||
	db, err := setupState()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("setupState failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = db.AddUser("testuser1", "password")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("AddUser failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = db.AddUser("testuser2", "password")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("AddUser failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = db.AddProject("testproject", "description", "testuser1")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("AddProject failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = db.AddUserToProject("testuser1", "testproject", "project_manager")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("AddUserToProject failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = db.AddUserToProject("testuser2", "testproject", "user")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("AddUserToProject failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	users, err := db.GetAllUsersProject("testproject")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("GetAllUsersProject failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Check if both users are returned with their roles
 | 
					 | 
				
			||||||
	if len(users) != 2 {
 | 
					 | 
				
			||||||
		t.Errorf("Expected 2 users, got %d", len(users))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Check if testuser1 has project manager role
 | 
					 | 
				
			||||||
	foundProjectManager := false
 | 
					 | 
				
			||||||
	for _, user := range users {
 | 
					 | 
				
			||||||
		if user.Username == "testuser1" && user.UserRole == "project_manager" {
 | 
					 | 
				
			||||||
			foundProjectManager = true
 | 
					 | 
				
			||||||
			break
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if !foundProjectManager {
 | 
					 | 
				
			||||||
		t.Error("Project Manager user not found")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Check if testuser2 has user role
 | 
					 | 
				
			||||||
	foundUser := false
 | 
					 | 
				
			||||||
	for _, user := range users {
 | 
					 | 
				
			||||||
		if user.Username == "testuser2" && user.UserRole == "user" {
 | 
					 | 
				
			||||||
			foundUser = true
 | 
					 | 
				
			||||||
			break
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if !foundUser {
 | 
					 | 
				
			||||||
		t.Error("User user not found")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestGetAllUsersApplication(t *testing.T) {
 | 
					 | 
				
			||||||
	db, err := setupState()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("setupState failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = db.AddUser("testuser1", "password")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("AddUser failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = db.AddUser("testuser2", "password")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("AddUser failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	users, err := db.GetAllUsersApplication()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error("GetAllUsersApplication failed:", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Check if both users are returned
 | 
					 | 
				
			||||||
	if len(users) != 2 {
 | 
					 | 
				
			||||||
		t.Errorf("Expected 2 users, got %d", len(users))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Check if the test users are included in the list
 | 
					 | 
				
			||||||
	foundTestUser1 := false
 | 
					 | 
				
			||||||
	foundTestUser2 := false
 | 
					 | 
				
			||||||
	for _, user := range users {
 | 
					 | 
				
			||||||
		if user == "testuser1" {
 | 
					 | 
				
			||||||
			foundTestUser1 = true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if user == "testuser2" {
 | 
					 | 
				
			||||||
			foundTestUser2 = true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !foundTestUser1 {
 | 
					 | 
				
			||||||
		t.Error("testuser1 not found")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if !foundTestUser2 {
 | 
					 | 
				
			||||||
		t.Error("testuser2 not found")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,11 @@
 | 
				
			||||||
CREATE TABLE IF NOT EXISTS projects (
 | 
					CREATE TABLE IF NOT EXISTS projects (
 | 
				
			||||||
  id INTEGER PRIMARY KEY,
 | 
					  id INTEGER PRIMARY KEY,
 | 
				
			||||||
 | 
					  projectId TEXT DEFAULT (HEX(RANDOMBLOB(4))) NOT NULL UNIQUE,
 | 
				
			||||||
  name VARCHAR(255) NOT NULL UNIQUE,
 | 
					  name VARCHAR(255) NOT NULL UNIQUE,
 | 
				
			||||||
  description TEXT NOT NULL,
 | 
					  description TEXT NOT NULL,
 | 
				
			||||||
  owner_user_id INTEGER NOT NULL,
 | 
					  owner_user_id INTEGER NOT NULL,
 | 
				
			||||||
  FOREIGN KEY (owner_user_id) REFERENCES users (id)
 | 
					  FOREIGN KEY (owner_user_id) REFERENCES users (id)
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CREATE INDEX IF NOT EXISTS projects_projectId_index ON projects (projectId);
 | 
				
			||||||
CREATE INDEX IF NOT EXISTS projects_user_id_index ON projects (owner_user_id);
 | 
					CREATE INDEX IF NOT EXISTS projects_user_id_index ON projects (owner_user_id);
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,10 @@
 | 
				
			||||||
CREATE TABLE IF NOT EXISTS time_reports (
 | 
					CREATE TABLE IF NOT EXISTS time_reports (
 | 
				
			||||||
  id INTEGER PRIMARY KEY,
 | 
					  id INTEGER PRIMARY KEY,
 | 
				
			||||||
 | 
					  reportId TEXT DEFAULT (HEX(RANDOMBLOB(6))) NOT NULL UNIQUE,
 | 
				
			||||||
  project_id INTEGER NOT NULL,
 | 
					  project_id INTEGER NOT NULL,
 | 
				
			||||||
  user_id INTEGER NOT NULL,
 | 
					 | 
				
			||||||
  start DATETIME NOT NULL,
 | 
					  start DATETIME NOT NULL,
 | 
				
			||||||
  end DATETIME NOT NULL,
 | 
					  end DATETIME NOT NULL,
 | 
				
			||||||
  FOREIGN KEY (project_id) REFERENCES projects (id) ON DELETE CASCADE
 | 
					  FOREIGN KEY (project_id) REFERENCES projects (id) ON DELETE CASCADE
 | 
				
			||||||
  FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
 | 
					 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CREATE TRIGGER IF NOT EXISTS time_reports_start_before_end
 | 
					CREATE TRIGGER IF NOT EXISTS time_reports_start_before_end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,5 +5,5 @@ CREATE TABLE IF NOT EXISTS project_role (
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- Insert the possible roles a user can have in a project.
 | 
					-- Insert the possible roles a user can have in a project.
 | 
				
			||||||
INSERT OR IGNORE INTO project_role (p_role) VALUES ('project_manager');
 | 
					INSERT OR IGNORE INTO project_role (p_role) VALUES ('admin');
 | 
				
			||||||
INSERT OR IGNORE INTO project_role (p_role) VALUES ('member');
 | 
					INSERT OR IGNORE INTO project_role (p_role) VALUES ('member');
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
CREATE TABLE IF NOT EXISTS user_roles (
 | 
					CREATE TABLE IF NOT EXISTS user_roles (
 | 
				
			||||||
  user_id INTEGER NOT NULL,
 | 
					  user_id INTEGER NOT NULL,
 | 
				
			||||||
  project_id INTEGER NOT NULL,
 | 
					  project_id INTEGER NOT NULL,
 | 
				
			||||||
  p_role TEXT NOT NULL, -- 'project_manager' or 'member'
 | 
					  p_role TEXT NOT NULL, -- 'admin' or 'member'
 | 
				
			||||||
  FOREIGN KEY (user_id) REFERENCES users (id)
 | 
					  FOREIGN KEY (user_id) REFERENCES users (id)
 | 
				
			||||||
  FOREIGN KEY (project_id) REFERENCES projects (id)
 | 
					  FOREIGN KEY (project_id) REFERENCES projects (id)
 | 
				
			||||||
  FOREIGN KEY (p_role) REFERENCES project_role (p_role)
 | 
					  FOREIGN KEY (p_role) REFERENCES project_role (p_role)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -71,7 +71,6 @@ func main() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	server.Post("/api/loginrenew", gs.LoginRenew)
 | 
						server.Post("/api/loginrenew", gs.LoginRenew)
 | 
				
			||||||
	server.Delete("/api/userdelete", gs.UserDelete) // Perhaps just use POST to avoid headaches
 | 
						server.Delete("/api/userdelete", gs.UserDelete) // Perhaps just use POST to avoid headaches
 | 
				
			||||||
	server.Post("/api/project", gs.CreateProject)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Announce the port we are listening on and start the server
 | 
						// Announce the port we are listening on and start the server
 | 
				
			||||||
	err = server.Listen(fmt.Sprintf(":%d", conf.Port))
 | 
						err = server.Listen(fmt.Sprintf(":%d", conf.Port))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,3 @@
 | 
				
			||||||
import { NewProject, Project } from "../Types/Project";
 | 
					 | 
				
			||||||
import { NewUser, User } from "../Types/Users";
 | 
					import { NewUser, User } from "../Types/Users";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Defines all the methods that an instance of the API must implement
 | 
					// Defines all the methods that an instance of the API must implement
 | 
				
			||||||
| 
						 | 
					@ -7,10 +6,6 @@ interface API {
 | 
				
			||||||
  registerUser(user: NewUser): Promise<User>;
 | 
					  registerUser(user: NewUser): Promise<User>;
 | 
				
			||||||
  /** Remove a user */
 | 
					  /** Remove a user */
 | 
				
			||||||
  removeUser(username: string): Promise<User>;
 | 
					  removeUser(username: string): Promise<User>;
 | 
				
			||||||
  /** Create a project */
 | 
					 | 
				
			||||||
  createProject(project: NewProject): Promise<Project>;
 | 
					 | 
				
			||||||
  /** Renew the token */
 | 
					 | 
				
			||||||
  renewToken(token: string): Promise<string>;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Export an instance of the API
 | 
					// Export an instance of the API
 | 
				
			||||||
| 
						 | 
					@ -34,24 +29,4 @@ export const api: API = {
 | 
				
			||||||
      body: JSON.stringify(username),
 | 
					      body: JSON.stringify(username),
 | 
				
			||||||
    }).then((res) => res.json() as Promise<User>);
 | 
					    }).then((res) => res.json() as Promise<User>);
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					 | 
				
			||||||
  async createProject(project: NewProject): Promise<Project> {
 | 
					 | 
				
			||||||
    return fetch("/api/project", {
 | 
					 | 
				
			||||||
      method: "POST",
 | 
					 | 
				
			||||||
      headers: {
 | 
					 | 
				
			||||||
        "Content-Type": "application/json",
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      body: JSON.stringify(project),
 | 
					 | 
				
			||||||
    }).then((res) => res.json() as Promise<Project>);
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async renewToken(token: string): Promise<string> {
 | 
					 | 
				
			||||||
    return fetch("/api/loginrenew", {
 | 
					 | 
				
			||||||
      method: "POST",
 | 
					 | 
				
			||||||
      headers: {
 | 
					 | 
				
			||||||
        "Content-Type": "application/json",
 | 
					 | 
				
			||||||
        Authorization: "Bearer " + token,
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    }).then((res) => res.json() as Promise<string>);
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,7 +15,7 @@ function Header({ username }: { username: string }): JSX.Element {
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <Link to="/your-projects">
 | 
					      <Link to="/your-projects">
 | 
				
			||||||
        <img
 | 
					        <img
 | 
				
			||||||
          src="/src/assets/Logo.svg"
 | 
					          src="/src/assets/TTIMElogo.png"
 | 
				
			||||||
          alt="TTIME Logo"
 | 
					          alt="TTIME Logo"
 | 
				
			||||||
          className="w-11 h-14 cursor-pointer"
 | 
					          className="w-11 h-14 cursor-pointer"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,74 +0,0 @@
 | 
				
			||||||
import { useState } from "react";
 | 
					 | 
				
			||||||
import { NewUser } from "../Types/Users";
 | 
					 | 
				
			||||||
import { api } from "../API/API";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default function Register(): JSX.Element {
 | 
					 | 
				
			||||||
  const [username, setUsername] = useState("");
 | 
					 | 
				
			||||||
  const [password, setPassword] = useState("");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleRegister = async (): Promise<void> => {
 | 
					 | 
				
			||||||
    const newUser: NewUser = { userName: username, password };
 | 
					 | 
				
			||||||
    await api.registerUser(newUser); // TODO: Handle errors
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <div>
 | 
					 | 
				
			||||||
      <div className="w-full max-w-xs">
 | 
					 | 
				
			||||||
        <form
 | 
					 | 
				
			||||||
          className="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4"
 | 
					 | 
				
			||||||
          onSubmit={(e) => {
 | 
					 | 
				
			||||||
            e.preventDefault();
 | 
					 | 
				
			||||||
            void handleRegister();
 | 
					 | 
				
			||||||
          }}
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <h3 className="pb-2">Register new user</h3>
 | 
					 | 
				
			||||||
          <div className="mb-4">
 | 
					 | 
				
			||||||
            <label
 | 
					 | 
				
			||||||
              className="block text-gray-700 text-sm font-bold mb-2"
 | 
					 | 
				
			||||||
              htmlFor="username"
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              Username
 | 
					 | 
				
			||||||
            </label>
 | 
					 | 
				
			||||||
            <input
 | 
					 | 
				
			||||||
              className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
 | 
					 | 
				
			||||||
              id="username"
 | 
					 | 
				
			||||||
              type="text"
 | 
					 | 
				
			||||||
              placeholder="Username"
 | 
					 | 
				
			||||||
              value={username}
 | 
					 | 
				
			||||||
              onChange={(e) => {
 | 
					 | 
				
			||||||
                setUsername(e.target.value);
 | 
					 | 
				
			||||||
              }}
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
          <div className="mb-6">
 | 
					 | 
				
			||||||
            <label
 | 
					 | 
				
			||||||
              className="block text-gray-700 text-sm font-bold mb-2"
 | 
					 | 
				
			||||||
              htmlFor="password"
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              Password
 | 
					 | 
				
			||||||
            </label>
 | 
					 | 
				
			||||||
            <input
 | 
					 | 
				
			||||||
              className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mb-3 leading-tight focus:outline-none focus:shadow-outline"
 | 
					 | 
				
			||||||
              id="password"
 | 
					 | 
				
			||||||
              type="password"
 | 
					 | 
				
			||||||
              placeholder="Choose your password"
 | 
					 | 
				
			||||||
              value={password}
 | 
					 | 
				
			||||||
              onChange={(e) => {
 | 
					 | 
				
			||||||
                setPassword(e.target.value);
 | 
					 | 
				
			||||||
              }}
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
          <div className="flex items-center justify-between">
 | 
					 | 
				
			||||||
            <button
 | 
					 | 
				
			||||||
              className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
 | 
					 | 
				
			||||||
              type="submit"
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              Register
 | 
					 | 
				
			||||||
            </button>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </form>
 | 
					 | 
				
			||||||
        <p className="text-center text-gray-500 text-xs"></p>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,59 +0,0 @@
 | 
				
			||||||
function NewTimeReport(): JSX.Element {
 | 
					 | 
				
			||||||
  const activities = [
 | 
					 | 
				
			||||||
    "Development",
 | 
					 | 
				
			||||||
    "Meeting",
 | 
					 | 
				
			||||||
    "Administration",
 | 
					 | 
				
			||||||
    "Own Work",
 | 
					 | 
				
			||||||
    "Studies",
 | 
					 | 
				
			||||||
    "Testing",
 | 
					 | 
				
			||||||
  ];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <div className="border-4 border-black bg-white flex flex-col justify-start min-h-[65vh] h-fit w-[50vw] rounded-3xl overflow-scroll space-y-[2vh] p-[30px] items-center">
 | 
					 | 
				
			||||||
        <input
 | 
					 | 
				
			||||||
          className="w-fill h-[5vh] font-sans text-[3vh] pl-[1vw] rounded-full text-center pt-[1vh] pb-[1vh] border-2 border-black"
 | 
					 | 
				
			||||||
          type="week"
 | 
					 | 
				
			||||||
          placeholder="Week"
 | 
					 | 
				
			||||||
          onKeyDown={(event) => {
 | 
					 | 
				
			||||||
            event.preventDefault();
 | 
					 | 
				
			||||||
          }}
 | 
					 | 
				
			||||||
          onPaste={(event) => {
 | 
					 | 
				
			||||||
            event.preventDefault();
 | 
					 | 
				
			||||||
          }}
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
        <table className="w-full text-center divide-y divide-x divide-white text-[30px]">
 | 
					 | 
				
			||||||
          <thead>
 | 
					 | 
				
			||||||
            <tr>
 | 
					 | 
				
			||||||
              <th className="w-1/2 py-2 border-b-2 border-black">Activity</th>
 | 
					 | 
				
			||||||
              <th className="w-1/2 py-2 border-b-2 border-black">
 | 
					 | 
				
			||||||
                Total Time (min)
 | 
					 | 
				
			||||||
              </th>
 | 
					 | 
				
			||||||
            </tr>
 | 
					 | 
				
			||||||
          </thead>
 | 
					 | 
				
			||||||
          <tbody className="divide-y divide-black">
 | 
					 | 
				
			||||||
            {activities.map((activity, index) => (
 | 
					 | 
				
			||||||
              <tr key={index} className="h-[10vh]">
 | 
					 | 
				
			||||||
                <td>{activity}</td>
 | 
					 | 
				
			||||||
                <td>
 | 
					 | 
				
			||||||
                  <input
 | 
					 | 
				
			||||||
                    type="number"
 | 
					 | 
				
			||||||
                    min="0"
 | 
					 | 
				
			||||||
                    className="border-2 border-black rounded-md text-center w-1/2"
 | 
					 | 
				
			||||||
                    onKeyDown={(event) => {
 | 
					 | 
				
			||||||
                      const keyValue = event.key;
 | 
					 | 
				
			||||||
                      if (!/\d/.test(keyValue) && keyValue !== "Backspace")
 | 
					 | 
				
			||||||
                        event.preventDefault();
 | 
					 | 
				
			||||||
                    }}
 | 
					 | 
				
			||||||
                  />
 | 
					 | 
				
			||||||
                </td>
 | 
					 | 
				
			||||||
              </tr>
 | 
					 | 
				
			||||||
            ))}
 | 
					 | 
				
			||||||
          </tbody>
 | 
					 | 
				
			||||||
        </table>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default NewTimeReport;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,26 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function AdminAddProject(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = <></>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Finish"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default AdminAddProject;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,26 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function AdminAddUser(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = <></>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Finish"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default AdminAddUser;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,26 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function AdminChangeUsername(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = <></>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Finish"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default AdminChangeUsername;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,26 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function AdminManageProjects(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = <></>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Add Project"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default AdminManageProjects;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,26 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function AdminManageUsers(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = <></>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Add User"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default AdminManageUsers;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,27 +0,0 @@
 | 
				
			||||||
import { Link } from "react-router-dom";
 | 
					 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function AdminMenuPage(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <h1 className="font-bold text-[30px] mb-[20px]">Administrator Menu</h1>
 | 
					 | 
				
			||||||
      <div className="border-4 border-black bg-white flex flex-col items-center justify-center min-h-[65vh] h-fit w-[50vw] rounded-3xl content-center overflow-scroll space-y-[10vh] p-[30px]">
 | 
					 | 
				
			||||||
        <Link to="/admin-users-page">
 | 
					 | 
				
			||||||
          <h1 className="font-bold underline text-[30px] cursor-pointer">
 | 
					 | 
				
			||||||
            Manage Users
 | 
					 | 
				
			||||||
          </h1>
 | 
					 | 
				
			||||||
        </Link>
 | 
					 | 
				
			||||||
        <Link to="/admin-projects-page">
 | 
					 | 
				
			||||||
          <h1 className="font-bold underline text-[30px] cursor-pointer">
 | 
					 | 
				
			||||||
            Manage Projects
 | 
					 | 
				
			||||||
          </h1>
 | 
					 | 
				
			||||||
        </Link>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = <></>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default AdminMenuPage;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,26 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function AdminProjectAddMember(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = <></>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Add"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default AdminProjectAddMember;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,26 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function AdminProjectChangeUserRole(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = <></>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Change"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default AdminProjectChangeUserRole;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,26 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function AdminProjectManageMembers(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = <></>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Add Member"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default AdminProjectManageMembers;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,26 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function AdminProjectPage(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = <></>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Delete"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default AdminProjectPage;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,20 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function AdminProjectStatistics(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = <></>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default AdminProjectStatistics;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,26 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function AdminProjectViewMemberInfo(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = <></>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Remove"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default AdminProjectViewMemberInfo;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,26 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function AdminViewUserInfo(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = <></>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Delete"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default AdminViewUserInfo;
 | 
					 | 
				
			||||||
							
								
								
									
										36
									
								
								frontend/src/Pages/Home.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								frontend/src/Pages/Home.tsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,36 @@
 | 
				
			||||||
 | 
					import reactLogo from "../assets/react.svg";
 | 
				
			||||||
 | 
					import viteLogo from "/vite.svg";
 | 
				
			||||||
 | 
					import "../index.css";
 | 
				
			||||||
 | 
					import { CountButton } from "../Components/CountButton";
 | 
				
			||||||
 | 
					import { Link } from "react-router-dom";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * The home page of the application
 | 
				
			||||||
 | 
					 * @returns {JSX.Element} The home page
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export default function HomePage(): JSX.Element {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <>
 | 
				
			||||||
 | 
					      <div>
 | 
				
			||||||
 | 
					        <a href="https://vitejs.dev" target="_blank" rel="noreferrer">
 | 
				
			||||||
 | 
					          <img src={viteLogo} className="logo h-32 p-5" alt="Vite logo" />
 | 
				
			||||||
 | 
					        </a>
 | 
				
			||||||
 | 
					        <a href="https://react.dev" target="_blank" rel="noreferrer">
 | 
				
			||||||
 | 
					          <img
 | 
				
			||||||
 | 
					            src={reactLogo}
 | 
				
			||||||
 | 
					            className="logo react h-32 p-5"
 | 
				
			||||||
 | 
					            alt="React logo"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </a>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <h1>Vite + React</h1>
 | 
				
			||||||
 | 
					      <div className="card flex flex-col items-center space-y-4">
 | 
				
			||||||
 | 
					        <CountButton />
 | 
				
			||||||
 | 
					        <Link to="/settings">To Settings</Link>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <p className="read-the-docs">
 | 
				
			||||||
 | 
					        Click on the Vite and React logos to learn more
 | 
				
			||||||
 | 
					      </p>
 | 
				
			||||||
 | 
					    </>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
import Button from "../Components/Button";
 | 
					import Button from "../Components/Button";
 | 
				
			||||||
import Logo from "/src/assets/Logo.svg";
 | 
					import Logo from "/src/assets/TTIMElogo.png";
 | 
				
			||||||
import "./LoginPage.css";
 | 
					import "./LoginPage.css";
 | 
				
			||||||
import { useEffect } from "react";
 | 
					import { useEffect } from "react";
 | 
				
			||||||
import { Link } from "react-router-dom";
 | 
					import { Link } from "react-router-dom";
 | 
				
			||||||
| 
						 | 
					@ -69,14 +69,6 @@ function LoginPage(): JSX.Element {
 | 
				
			||||||
              }}
 | 
					              }}
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
          </Link>
 | 
					          </Link>
 | 
				
			||||||
          <Link to="/register">
 | 
					 | 
				
			||||||
            <Button
 | 
					 | 
				
			||||||
              text="Register new user"
 | 
					 | 
				
			||||||
              onClick={(): void => {
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
              }}
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
          </Link>
 | 
					 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </>
 | 
					    </>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,26 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function ChangeRole(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = <></>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Save"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default ChangeRole;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,20 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function PMOtherUsersTR(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = <></>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default PMOtherUsersTR;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,32 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function PMProjectMembers(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = <></>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Time / Activity"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Time / Role"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default PMProjectMembers;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,28 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
import TimeReport from "../../Components/TimeReport";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function PMTotalTimeActivity(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <h1 className="font-bold text-[30px] mb-[20px]">
 | 
					 | 
				
			||||||
        Total Time Per Activity
 | 
					 | 
				
			||||||
      </h1>
 | 
					 | 
				
			||||||
      <TimeReport />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default PMTotalTimeActivity;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,20 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function PMTotalTimeRole(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = <></>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default PMTotalTimeRole;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,20 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function PMUnsignedReports(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = <></>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default PMUnsignedReports;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,40 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
import TimeReport from "../../Components/TimeReport";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function PMViewUnsignedReport(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <h1 className="font-bold text-[30px] mb-[20px]">
 | 
					 | 
				
			||||||
        Username's Time Report
 | 
					 | 
				
			||||||
      </h1>
 | 
					 | 
				
			||||||
      <TimeReport />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Sign"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Save"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default PMViewUnsignedReport;
 | 
					 | 
				
			||||||
							
								
								
									
										17
									
								
								frontend/src/Pages/Settings.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								frontend/src/Pages/Settings.tsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					import "../index.css";
 | 
				
			||||||
 | 
					import { Link } from "react-router-dom";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * The settings page of the application
 | 
				
			||||||
 | 
					 * @returns {JSX.Element} The settings page
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export default function SettingsPage(): JSX.Element {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <>
 | 
				
			||||||
 | 
					      <h1>Very Fancy Settings Page</h1>
 | 
				
			||||||
 | 
					      <div className="card">
 | 
				
			||||||
 | 
					        <Link to="/">To Home</Link>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,32 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
import NewTimeReport from "../../Components/TimeReport";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function UserEditTimeReportPage(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <h1 className="font-bold text-[30px] mb-[20px]">Edit Time Report</h1>
 | 
					 | 
				
			||||||
      <NewTimeReport />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Save"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default UserEditTimeReportPage;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,35 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
import NewTimeReport from "../../Components/TimeReport";
 | 
					 | 
				
			||||||
import { Link } from "react-router-dom";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function UserNewTimeReportPage(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <h1 className="font-bold text-[30px] mb-[20px]">New Time Report</h1>
 | 
					 | 
				
			||||||
      <NewTimeReport />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Submit"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <Link to="/project">
 | 
					 | 
				
			||||||
        <Button
 | 
					 | 
				
			||||||
          text="Back"
 | 
					 | 
				
			||||||
          onClick={(): void => {
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
          }}
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
      </Link>
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default UserNewTimeReportPage;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -5,16 +5,16 @@ import Button from "../../Components/Button";
 | 
				
			||||||
function UserProjectPage(): JSX.Element {
 | 
					function UserProjectPage(): JSX.Element {
 | 
				
			||||||
  const content = (
 | 
					  const content = (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
 | 
					      <Link to="/settingsPage">
 | 
				
			||||||
        <h1 className="font-bold text-[30px] mb-[20px]">ProjectNameExample</h1>
 | 
					        <h1 className="font-bold text-[30px] mb-[20px]">ProjectNameExample</h1>
 | 
				
			||||||
 | 
					      </Link>
 | 
				
			||||||
      <div className="border-4 border-black bg-white flex flex-col items-center justify-center min-h-[65vh] h-fit w-[50vw] rounded-3xl content-center overflow-scroll space-y-[10vh] p-[30px]">
 | 
					      <div className="border-4 border-black bg-white flex flex-col items-center justify-center min-h-[65vh] h-fit w-[50vw] rounded-3xl content-center overflow-scroll space-y-[10vh] p-[30px]">
 | 
				
			||||||
        <h1 className="font-bold underline text-[30px] cursor-pointer">
 | 
					        <h1 className="font-bold underline text-[30px] cursor-pointer">
 | 
				
			||||||
          Your Time Reports
 | 
					          Your Time Reports
 | 
				
			||||||
        </h1>
 | 
					        </h1>
 | 
				
			||||||
        <Link to="/new-time-report">
 | 
					 | 
				
			||||||
        <h1 className="font-bold underline text-[30px] cursor-pointer">
 | 
					        <h1 className="font-bold underline text-[30px] cursor-pointer">
 | 
				
			||||||
          New Time Report
 | 
					          New Time Report
 | 
				
			||||||
        </h1>
 | 
					        </h1>
 | 
				
			||||||
        </Link>
 | 
					 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </>
 | 
					    </>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,20 +0,0 @@
 | 
				
			||||||
import BasicWindow from "../../Components/BasicWindow";
 | 
					 | 
				
			||||||
import Button from "../../Components/Button";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function UserViewTimeReportsPage(): JSX.Element {
 | 
					 | 
				
			||||||
  const content = <></>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const buttons = (
 | 
					 | 
				
			||||||
    <>
 | 
					 | 
				
			||||||
      <Button
 | 
					 | 
				
			||||||
        text="Back"
 | 
					 | 
				
			||||||
        onClick={(): void => {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return <BasicWindow username="Admin" content={content} buttons={buttons} />;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export default UserViewTimeReportsPage;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -12,13 +12,13 @@ function YourProjectsPage(): JSX.Element {
 | 
				
			||||||
          </h1>
 | 
					          </h1>
 | 
				
			||||||
        </Link>
 | 
					        </Link>
 | 
				
			||||||
        <h1 className="underline text-[24px] cursor-pointer font-bold">
 | 
					        <h1 className="underline text-[24px] cursor-pointer font-bold">
 | 
				
			||||||
          ProjectNameExample2
 | 
					          ProjectNameExample
 | 
				
			||||||
        </h1>
 | 
					        </h1>
 | 
				
			||||||
        <h1 className="underline text-[24px] cursor-pointer font-bold">
 | 
					        <h1 className="underline text-[24px] cursor-pointer font-bold">
 | 
				
			||||||
          ProjectNameExample3
 | 
					          ProjectNameExample
 | 
				
			||||||
        </h1>
 | 
					        </h1>
 | 
				
			||||||
        <h1 className="underline text-[24px] cursor-pointer font-bold">
 | 
					        <h1 className="underline text-[24px] cursor-pointer font-bold">
 | 
				
			||||||
          ProjectNameExample4
 | 
					          ProjectNameExample
 | 
				
			||||||
        </h1>
 | 
					        </h1>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </>
 | 
					    </>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +0,0 @@
 | 
				
			||||||
export interface Project {
 | 
					 | 
				
			||||||
  id: number;
 | 
					 | 
				
			||||||
  name: string;
 | 
					 | 
				
			||||||
  description: string;
 | 
					 | 
				
			||||||
  owner: string;
 | 
					 | 
				
			||||||
  created: string; // This is a date
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface NewProject {
 | 
					 | 
				
			||||||
  name: string;
 | 
					 | 
				
			||||||
  description: string;
 | 
					 | 
				
			||||||
  owner: string;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,11 @@
 | 
				
			||||||
// This is how the API responds
 | 
					// This is how the API responds
 | 
				
			||||||
export interface User {
 | 
					export interface User {
 | 
				
			||||||
  id: number;
 | 
					  id: number;
 | 
				
			||||||
  userName: string;
 | 
					  name: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Used to create a new user
 | 
					// Used to create a new user
 | 
				
			||||||
export interface NewUser {
 | 
					export interface NewUser {
 | 
				
			||||||
  userName: string;
 | 
					  name: string;
 | 
				
			||||||
  password: string;
 | 
					  password: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
		 Before Width: | Height: | Size: 348 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								frontend/src/assets/TTIMElogo.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								frontend/src/assets/TTIMElogo.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 261 KiB  | 
							
								
								
									
										1
									
								
								frontend/src/assets/react.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								frontend/src/assets/react.svg
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 4 KiB  | 
| 
						 | 
					@ -5,31 +5,6 @@ import { createBrowserRouter, RouterProvider } from "react-router-dom";
 | 
				
			||||||
import LoginPage from "./Pages/LoginPage.tsx";
 | 
					import LoginPage from "./Pages/LoginPage.tsx";
 | 
				
			||||||
import YourProjectsPage from "./Pages/YourProjectsPage.tsx";
 | 
					import YourProjectsPage from "./Pages/YourProjectsPage.tsx";
 | 
				
			||||||
import UserProjectPage from "./Pages/UserPages/UserProjectPage.tsx";
 | 
					import UserProjectPage from "./Pages/UserPages/UserProjectPage.tsx";
 | 
				
			||||||
import Register from "./Components/Register.tsx";
 | 
					 | 
				
			||||||
import AdminMenuPage from "./Pages/AdminPages/AdminMenuPage.tsx";
 | 
					 | 
				
			||||||
import UserEditTimeReportPage from "./Pages/UserPages/UserEditTimeReportPage.tsx";
 | 
					 | 
				
			||||||
import UserNewTimeReportPage from "./Pages/UserPages/UserNewTimeReportPage.tsx";
 | 
					 | 
				
			||||||
import UserViewTimeReportsPage from "./Pages/UserPages/UserViewTimeReportsPage.tsx";
 | 
					 | 
				
			||||||
import PMChangeRole from "./Pages/ProjectManagerPages/PMChangeRole.tsx";
 | 
					 | 
				
			||||||
import PMOtherUsersTR from "./Pages/ProjectManagerPages/PMOtherUsersTR.tsx";
 | 
					 | 
				
			||||||
import PMProjectMembers from "./Pages/ProjectManagerPages/PMProjectMembers.tsx";
 | 
					 | 
				
			||||||
import PMProjectPage from "./Pages/ProjectManagerPages/PMProjectPage.tsx";
 | 
					 | 
				
			||||||
import PMTotalTimeActivity from "./Pages/ProjectManagerPages/PMTotalTimeActivity.tsx";
 | 
					 | 
				
			||||||
import PMTotalTimeRole from "./Pages/ProjectManagerPages/PMTotalTimeRole.tsx";
 | 
					 | 
				
			||||||
import PMUnsignedReports from "./Pages/ProjectManagerPages/PMUnsignedReports.tsx";
 | 
					 | 
				
			||||||
import PMViewUnsignedReport from "./Pages/ProjectManagerPages/PMViewUnsignedReport.tsx";
 | 
					 | 
				
			||||||
import AdminManageUsers from "./Pages/AdminPages/AdminManageUsers.tsx";
 | 
					 | 
				
			||||||
import AdminViewUserInfo from "./Pages/AdminPages/AdminViewUserInfo.tsx";
 | 
					 | 
				
			||||||
import AdminManageProjects from "./Pages/AdminPages/AdminManageProjects.tsx";
 | 
					 | 
				
			||||||
import AdminAddProject from "./Pages/AdminPages/AdminAddProject.tsx";
 | 
					 | 
				
			||||||
import AdminAddUser from "./Pages/AdminPages/AdminAddUser.tsx";
 | 
					 | 
				
			||||||
import AdminChangeUsername from "./Pages/AdminPages/AdminChangeUsername.tsx";
 | 
					 | 
				
			||||||
import AdminProjectAddMember from "./Pages/AdminPages/AdminProjectAddMember.tsx";
 | 
					 | 
				
			||||||
import AdminProjectChangeUserRole from "./Pages/AdminPages/AdminProjectChangeUserRole.tsx";
 | 
					 | 
				
			||||||
import AdminProjectManageMembers from "./Pages/AdminPages/AdminProjectManageMembers.tsx";
 | 
					 | 
				
			||||||
import AdminProjectStatistics from "./Pages/AdminPages/AdminProjectStatistics.tsx";
 | 
					 | 
				
			||||||
import AdminProjectViewMemberInfo from "./Pages/AdminPages/AdminProjectViewMemberInfo.tsx";
 | 
					 | 
				
			||||||
import AdminProjectPage from "./Pages/AdminPages/AdminProjectPage.tsx";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// This is where the routes are mounted
 | 
					// This is where the routes are mounted
 | 
				
			||||||
const router = createBrowserRouter([
 | 
					const router = createBrowserRouter([
 | 
				
			||||||
| 
						 | 
					@ -41,114 +16,10 @@ const router = createBrowserRouter([
 | 
				
			||||||
    path: "/your-projects",
 | 
					    path: "/your-projects",
 | 
				
			||||||
    element: <YourProjectsPage />,
 | 
					    element: <YourProjectsPage />,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/edit-time-report",
 | 
					 | 
				
			||||||
    element: <UserEditTimeReportPage />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/new-time-report",
 | 
					 | 
				
			||||||
    element: <UserNewTimeReportPage />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    path: "/project",
 | 
					    path: "/project",
 | 
				
			||||||
    element: <UserProjectPage />,
 | 
					    element: <UserProjectPage />,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/register",
 | 
					 | 
				
			||||||
    element: <Register />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/admin-menu",
 | 
					 | 
				
			||||||
    element: <AdminMenuPage />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/project-page",
 | 
					 | 
				
			||||||
    element: <UserViewTimeReportsPage />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/change-role",
 | 
					 | 
				
			||||||
    element: <PMChangeRole />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/other-users-time-reports",
 | 
					 | 
				
			||||||
    element: <PMOtherUsersTR />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/project-members",
 | 
					 | 
				
			||||||
    element: <PMProjectMembers />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/PM-project-page",
 | 
					 | 
				
			||||||
    element: <PMProjectPage />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/PM-time-activity",
 | 
					 | 
				
			||||||
    element: <PMTotalTimeActivity />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/PM-time-role",
 | 
					 | 
				
			||||||
    element: <PMTotalTimeRole />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/PM-unsigned-reports",
 | 
					 | 
				
			||||||
    element: <PMUnsignedReports />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/PM-view-unsigned-report",
 | 
					 | 
				
			||||||
    element: <PMViewUnsignedReport />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/admin-add-project",
 | 
					 | 
				
			||||||
    element: <AdminAddProject />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/admin-add-user",
 | 
					 | 
				
			||||||
    element: <AdminAddUser />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/admin-change-username",
 | 
					 | 
				
			||||||
    element: <AdminChangeUsername />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/admin-manage-projects",
 | 
					 | 
				
			||||||
    element: <AdminManageProjects />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/admin-manage-users",
 | 
					 | 
				
			||||||
    element: <AdminManageUsers />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/admin-menu",
 | 
					 | 
				
			||||||
    element: <AdminMenuPage />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/admin-project-add-member",
 | 
					 | 
				
			||||||
    element: <AdminProjectAddMember />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/admin-project-change-user-role",
 | 
					 | 
				
			||||||
    element: <AdminProjectChangeUserRole />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/admin-project-manage-members",
 | 
					 | 
				
			||||||
    element: <AdminProjectManageMembers />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/admin-project-page",
 | 
					 | 
				
			||||||
    element: <AdminProjectPage />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/admin-project-statistics",
 | 
					 | 
				
			||||||
    element: <AdminProjectStatistics />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/admin-project-view-members",
 | 
					 | 
				
			||||||
    element: <AdminProjectViewMemberInfo />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    path: "/admin-view-user",
 | 
					 | 
				
			||||||
    element: <AdminViewUserInfo />,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
]);
 | 
					]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Semi-hacky way to get the root element
 | 
					// Semi-hacky way to get the root element
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										6
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							| 
						 | 
					@ -1,6 +0,0 @@
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  "name": "TTime",
 | 
					 | 
				
			||||||
  "lockfileVersion": 3,
 | 
					 | 
				
			||||||
  "requires": true,
 | 
					 | 
				
			||||||
  "packages": {}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue