Merged CEO and Client App

This commit is contained in:
andrei-mihnea-cerbu
2025-02-06 10:25:13 +02:00
parent eda2e2d2a0
commit 23802acd98
186 changed files with 365 additions and 11234 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

+133
View File
@@ -0,0 +1,133 @@
body, html {
height: 100vh;
width: 100vw;
margin: 0;
padding: 0;
font-family: "Pridi", sans-serif;
background-color: #4A628A;
}
h4, h1 {
margin: 0;
}
.page {
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
.container {
border-radius: 10px;
background: linear-gradient(to bottom, rgba(74, 98, 138, 0.0) 30%, rgba(186, 237, 255, 0.7));
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-evenly;
height: 90%;
width: 35%;
}
.header {
text-align: center;
padding: 16px;
}
.title {
font-size: 48px;
font-weight: 500;
color: white;
}
.subheading {
padding-top: 8px;
font-size: 16px;
color: rgba(255, 255, 255, 0.8);
}
.announcement-form {
display: flex;
flex-direction: column;
align-items: center;
width: 80%;
}
textarea {
height: 230px;
width: 100%;
padding: 15px;
font-size: 1em;
border-radius: 8px;
border: 1px solid #ccc;
resize: none;
background-color: #3A4A6C; /* Darker background for the textarea */
color: #f0f0f0; /* Light text color */
transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
textarea::placeholder {
opacity: 0.7;
color: white;
}
/* Customize the textarea scrollbar */
textarea::-webkit-scrollbar {
width: 10px; /* Width of the scrollbar */
}
textarea::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.1); /* Track background color */
border-radius: 10px; /* Rounded corners for the track */
}
textarea::-webkit-scrollbar-thumb {
background-color: rgba(74, 98, 138, 0.8); /* Scrollbar handle color */
border-radius: 10px; /* Rounded corners for the scrollbar handle */
}
textarea::-webkit-scrollbar-thumb:hover {
background-color: rgba(74, 98, 138, 1); /* Darker color on hover */
}
textarea:focus {
outline: none;
border-color: #4A628A;
box-shadow: 0 0 5px rgba(74, 98, 138, 0.5);
background-color: #334466; /* Slightly brighter background on focus */
}
.announcement-form-footer {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
margin-top: 20px;
gap: 10px; /* Space between buttons */
}
button#submitAnnouncement {
width: 100%;
padding: 16px;
font-weight: 300;
background-color: #4A628A;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.2s ease;
}
button#backButton {
background-color: transparent; /* No background */
border: none; /* Remove default button border */
color: #4A628A; /* Set text color */
font-size: 1em; /* Set font size */
cursor: pointer; /* Add pointer cursor for interactivity */
text-decoration: underline; /* Underline text */
padding: 0; /* Remove default padding */
}
+59
View File
@@ -0,0 +1,59 @@
body, html {
height: 100vh;
width: 100vw;
margin: 0;
padding: 0;
font-family: "Pridi", sans-serif; /* Use sans-serif fallback */
background-color: #4A628A;
}
h4, h2, h1{
margin: 0;
}
.container{
height: 100vh;
width: 100vw;
display: flex;
flex-direction: column;
justify-content: space-evenly;
align-items: center;
}
.title{
font-size: 48px;
font-weight: 500;
letter-spacing: -1px;
color: white;
}
img{
width: 200px;
height: 200px;
}
p{
color: white;
}
.loading-section{
display: flex;
flex-direction: column;
align-items: center;
}
.spinner {
margin-bottom: 8px;
width: 15px;
height: 15px;
border: 3px solid #f3f3f3;
border-top: 3px solid #2196F3;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
+143
View File
@@ -0,0 +1,143 @@
body, html {
height: 100vh;
width: 100vw;
margin: 0;
padding: 0;
font-family: "Pridi", sans-serif; /* Use sans-serif fallback */
background-color: #4A628A;
}
h4, h2, h1{
margin: 0;
}
.page{
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
.container {
border-radius: 10px;
background: linear-gradient(to bottom, rgba(74, 98, 138, 0.0) 30%, rgba(186, 237, 255, 0.7));
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-evenly;
height: 90%;
width: 35%;
}
.header{
text-align: center;
padding-bottom: 16px;
padding-top: 16px;
}
.title{
font-size: 48px;
font-weight: 500;
letter-spacing: -1px;
color: white;
}
.subheading{
padding-top: 8px;
font-size: 16px;
letter-spacing: -0.5px;
color: rgba(255,255,255, 0.8);
}
.login-form{
display: flex;
flex-direction: column;
align-items: center;
width: 80%;
}
.login-title {
font-size: 24px;
font-weight: 500;
color: white;
margin-bottom: 16px;
}
.login-form-content input {
width: 100%;
padding: 15px;
margin: 10px 0;
border: 1px solid #ccc; /* Light gray border */
border-radius: 8px; /* Rounded corners */
font-size: 1em;
font-family: inherit;
box-sizing: border-box;
background-color: #f9f9f9; /* Light background */
color: #333; /* Dark text color */
transition: border-color 0.3s ease, box-shadow 0.3s ease; /* Smooth transition for interaction */
}
/* Placeholder Text Styling */
.login-form-content input::placeholder {
color: #aaa; /* Lighter color for placeholders */
}
/* Focus State Styling */
.login-form-content input:focus {
outline: none; /* Remove default focus outline */
border-color: #4A628A; /* Blue border on focus */
box-shadow: 0 0 5px rgba(74, 98, 138, 0.5); /* Subtle shadow for focus */
background-color: #fff; /* Slightly brighter background on focus */
}
/* Input Field Hover Effect */
.login-form-content input:hover {
border-color: #888; /* Darker gray border on hover */
}
/* Disabled Input Styling */
.login-form-content input:disabled {
background-color: #e0e0e0; /* Light gray background for disabled input */
cursor: not-allowed; /* Show "not allowed" cursor */
opacity: 0.7; /* Slight transparency */
}
.login-form-footer {
display: flex;
width: 100%;
flex-direction: column;
justify-content: space-between; /* Align buttons next to each other */
align-items: center;
gap: 10px; /* Space between buttons */
margin-top: 20px;
}
/* Styling for buttons */
.login-form-footer button {
flex: 1; /* Ensure buttons are equal width */
padding: 16px;
font-weight: 300;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.2s ease;
}
button[name="underline"] {
background-color: transparent; /* No background */
border: none; /* Remove default button border */
color: #4A628A; /* Set text color */
font-size: 1em; /* Set font size */
cursor: pointer; /* Add pointer cursor for interactivity */
text-decoration: underline; /* Underline text */
padding: 0; /* Remove default padding */
}
button[name="submit"] {
width: 100%;
background-color: #4A628A; /* Blue background */
color: white; /* White text color */
}
+208
View File
@@ -0,0 +1,208 @@
body, html {
height: 100vh;
width: 100vw;
margin: 0;
padding: 0;
font-family: "Pridi", sans-serif; /* Use sans-serif fallback */
background-color: #4A628A;
}
h4, h2, h1{
margin: 0;
}
.title{
font-size: 32px;
font-weight: 500;
letter-spacing: -1px;
color: white;
}
.user{
display: inline;
color: white;
}
.navbar{
padding-top: 8px;
padding-right: 32px;
padding-left: 32px;
height: 10%;
display:flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.welcome{
display: flex;
flex-direction: row;
align-items: center;
}
img{
padding-right: 8px;
width:25px;
height: auto;
}
.page{
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
.container{
width:100%;
height:100%;
display: flex;
flex-direction: row;
justify-content: center;
}
.left_block{
background: linear-gradient(to bottom, #131A24, #4A628A);
width: 25%;
display: flex;
flex-direction: column;
}
.notification-title{
padding-top: 16px;
padding-bottom: 16px;
text-align: center;
height: 10%;
display: flex;
justify-content: center;
align-items: center;
}
.notifications{
overflow-y: auto;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
flex-grow: 1; /* Allow it to take available space */
max-height: calc(90% - 80px);
}
.right_block_content button:last-child {
background-color: #FF6347;
}
.right_block_content button:nth-child(8) {
background-color: #FF6347;
}
.right_block_content button:last-child:hover {
background-color: #fd4c29;
}
.alert, .logout-button{
cursor: pointer;
border-radius: 15px;
width: 80%;
min-height: 64px;
height: auto;
padding:12px;
background: #FF6347;
font-weight: bold;
font-size: 12px;
}
.notification{
cursor: pointer;
border-radius: 15px;
width: 80%;
min-height: 64px;
height: auto;
padding:12px;
background: rgba(186, 229, 255);
font-weight: bold;
font-size: 12px;
}
.notification:hover{
background: #d9efff;
}
.alert:hover, .logout-button:hover{
background: rgb(244, 44, 44);
}
.notif-title{
font-size: 24px;
font-weight: 300;
letter-spacing: -1px;
color: white;
}
.left-content{
height: 90%;
width: 100%;
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
}
.left_block_footer{
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding-bottom: 16px;
}
.right_block_content{
height: 90%;
}
.right_block{
width: 75%;
display:flex;
flex-direction: column;
justify-content: center;
}
.right_block_content {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 3 equal-width columns */
gap: 8px; /* Spacing between buttons */
padding: 32px; /* Optional padding */
}
button[name="menu_button"] {
padding: 10px 20px;
font-size: 16px;
background-color: rgba(186,229,244,0.4); /* Button background */
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.2s ease;
}
button[name="menu_button"]:hover {
background-color: #3B5173; /* Darker background on hover */
}
.notifications::-webkit-scrollbar {
width: 4px; /* Width of the scrollbar */
}
.notifications::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.1); /* Track background color */
border-radius: 10px; /* Rounded corners for the track */
}
.notifications::-webkit-scrollbar-thumb {
background-color: rgba(74, 98, 138, 0.8); /* Scrollbar handle color */
border-radius: 10px; /* Rounded corners for the scrollbar handle */
}
.notifications::-webkit-scrollbar-thumb:hover {
background-color: rgba(74, 98, 138, 1); /* Darker color on hover */
}
+41
View File
@@ -0,0 +1,41 @@
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre, hr
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
@@ -0,0 +1,215 @@
body, html {
height: 100vh;
width: 100vw;
margin: 0;
padding: 0;
font-family: "Pridi", sans-serif; /* Use sans-serif fallback */
background-color: #4A628A;
}
h4, h2, h1{
margin: 0;
}
.page{
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
.container {
border-radius: 10px;
background: linear-gradient(to bottom, rgba(74, 98, 138, 0.0) 30%, rgba(186, 237, 255, 0.7));
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-evenly;
height: 90%;
width: 35%;
}
.header{
text-align: center;
padding-bottom: 16px;
padding-top: 32px;
}
.title{
font-size: 24px;
font-weight: 500;
color: white;
margin-bottom: 32px;
}
.departments-container{
overflow-y: hidden;
width: 100%;
height: 370px;
max-height: 370px;
display: flex;
flex-direction: column;
gap: 8px;
align-items: center;
}
.department-name{
width:70%;
font-size: 16px;
letter-spacing: -0.5px;
color: rgba(255,255,255, 1);
}
.user-management-container{
display: flex;
flex-direction: column;
align-items: center;
width: 80%;
}
.footer {
display: flex;
width: 100%;
flex-direction: row;
justify-content: space-between; /* Align buttons next to each other */
align-items: center;
gap: 10px; /* Space between buttons */
margin-top: 20px;
}
/* Styling for buttons */
.user-management-container button, .modal button {
flex: 1; /* Ensure buttons are equal width */
padding: 8px 16px 8px 16px;
font-weight: 300;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.2s ease;
}
button[name="underline"] {
background-color: transparent; /* No background */
border: none; /* Remove default button border */
color: #4A628A; /* Set text color */
font-size: 1em; /* Set font size */
cursor: pointer; /* Add pointer cursor for interactivity */
text-decoration: underline; /* Underline text */
padding: 0; /* Remove default padding */
}
.department-card{
width: 100%;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 8px;
}
.delete-button {
width: auto;
margin-right: 8px;
background-color: #ED4B4B; /* Blue background */
color: white; /* White text color */
}
button[name="submit"] {
width: 100%;
background-color: #4A628A; /* Blue background */
color: white; /* White text color */
}
.departments-container::-webkit-scrollbar {
width: 4px; /* Width of the scrollbar */
}
.departments-container::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.1); /* Track background color */
border-radius: 10px; /* Rounded corners for the track */
}
.departments-container::-webkit-scrollbar-thumb {
background-color: rgba(74, 98, 138, 0.8); /* Scrollbar handle color */
border-radius: 10px; /* Rounded corners for the scrollbar handle */
}
.departments-container::-webkit-scrollbar-thumb:hover {
background-color: rgba(74, 98, 138, 1); /* Darker color on hover */
}
.departments-container:empty {
overflow-y: hidden;
}
.user-name{
padding-top: 8px;
font-size: 20px;
letter-spacing: -0.5px;
color: rgba(255,255,255, 1);
}
.user-department{
font-weight: lighter;
padding-top: 8px;
font-size: 14px;
letter-spacing: -0.5px;
color: rgba(255,255,255, 0.8);
}
.modal {
display: none; /* Hidden by default */
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(5px);/* Black with opacity */
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 16px;
border: 1px solid #888;
width: 100%;
max-width: 400px;
border-radius: 8px;
text-align: center;
}
.close-button {
float: right;
font-size: 24px;
font-weight: bold;
cursor: pointer;
color: #aaa;
}
.close-button:hover,
.close-button:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
input{
width: 100%;
padding: 15px;
margin-bottom: 16px;
border: 1px solid #ccc; /* Light gray border */
border-radius: 8px; /* Rounded corners */
font-size: 12px;
font-family: inherit;
box-sizing: border-box;
background-color: #f9f9f9; /* Light background */
color: #333; /* Dark text color */
transition: border-color 0.3s ease, box-shadow 0.3s ease; /* Smooth transition for interaction */
}
@@ -0,0 +1,153 @@
body, html {
height: 100vh;
width: 100vw;
margin: 0;
padding: 0;
font-family: "Pridi", sans-serif; /* Use sans-serif fallback */
background-color: #4A628A;
}
h4, h2, h1{
margin: 0;
}
.page{
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
.container {
border-radius: 10px;
background: linear-gradient(to bottom, rgba(74, 98, 138, 0.0) 30%, rgba(186, 237, 255, 0.7));
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-evenly;
height: 90%;
width: 35%;
}
.header{
text-align: center;
padding-bottom: 16px;
padding-top: 32px;
}
.title{
font-size: 24px;
font-weight: 500;
color: white;
margin-bottom: 32px;
}
.users-container{
overflow-y: hidden;
width: 100%;
height: 370px;
max-height: 370px;
display: flex;
flex-direction: column;
gap: 8px;
align-items: center;
}
.user-management-container{
display: flex;
flex-direction: column;
align-items: center;
width: 80%;
}
.footer {
display: flex;
width: 100%;
flex-direction: column;
justify-content: space-between; /* Align buttons next to each other */
align-items: center;
gap: 10px; /* Space between buttons */
margin-top: 20px;
}
/* Styling for buttons */
.user-management-container button {
flex: 1; /* Ensure buttons are equal width */
padding: 16px;
font-weight: 300;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.2s ease;
}
button[name="underline"] {
background-color: transparent; /* No background */
border: none; /* Remove default button border */
color: #4A628A; /* Set text color */
font-size: 1em; /* Set font size */
cursor: pointer; /* Add pointer cursor for interactivity */
text-decoration: underline; /* Underline text */
padding: 0; /* Remove default padding */
}
.user-info{
display: flex;
flex-direction: column;
width: 70%;
}
.user-card{
width: 100%;
display: flex;
flex-direction: row;
justify-content: center;
align-items: stretch;
}
.delete-button {
width: auto;
margin-right: 8px;
background-color: #ED4B4B; /* Blue background */
color: white; /* White text color */
}
.users-container::-webkit-scrollbar {
width: 4px; /* Width of the scrollbar */
}
.users-container::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.1); /* Track background color */
border-radius: 10px; /* Rounded corners for the track */
}
.users-container::-webkit-scrollbar-thumb {
background-color: rgba(74, 98, 138, 0.8); /* Scrollbar handle color */
border-radius: 10px; /* Rounded corners for the scrollbar handle */
}
.users-container::-webkit-scrollbar-thumb:hover {
background-color: rgba(74, 98, 138, 1); /* Darker color on hover */
}
.users-container:empty {
overflow-y: hidden;
}
.user-name{
padding-top: 8px;
font-size: 20px;
letter-spacing: -0.5px;
color: rgba(255,255,255, 1);
}
.user-department{
font-weight: lighter;
padding-top: 8px;
font-size: 14px;
letter-spacing: -0.5px;
color: rgba(255,255,255, 0.8);
}
+136
View File
@@ -0,0 +1,136 @@
body, html {
height: 100vh;
width: 100vw;
margin: 0;
padding: 0;
font-family: "Pridi", sans-serif; /* Use sans-serif fallback */
background-color: #4A628A;
}
h4, h2, h1{
margin: 0;
}
.page{
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
.container {
border-radius: 10px;
background: linear-gradient(to bottom, rgba(74, 98, 138, 0.0) 30%, rgba(186, 237, 255, 0.7));
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-evenly;
height: 90%;
width: 35%;
}
.header{
text-align: center;
padding-bottom: 16px;
padding-top: 16px;
}
.title{
font-size: 48px;
font-weight: 500;
letter-spacing: -1px;
color: white;
}
.subheading{
padding-top: 8px;
font-size: 16px;
letter-spacing: -0.5px;
color: rgba(255,255,255, 0.8);
}
.profile-form{
display: flex;
flex-direction: column;
align-items: center;
width: 80%;
}
.profile-form-content input {
width: 100%;
padding: 15px;
margin: 10px 0;
border: 1px solid #ccc; /* Light gray border */
border-radius: 8px; /* Rounded corners */
font-size: 1em;
font-family: inherit;
box-sizing: border-box;
background-color: #f9f9f9; /* Light background */
color: #333; /* Dark text color */
transition: border-color 0.3s ease, box-shadow 0.3s ease; /* Smooth transition for interaction */
}
/* Placeholder Text Styling */
.profile-form-content input::placeholder {
color: #aaa; /* Lighter color for placeholders */
}
/* Focus State Styling */
.profile-form-content input:focus {
outline: none; /* Remove default focus outline */
border-color: #4A628A; /* Blue border on focus */
box-shadow: 0 0 5px rgba(74, 98, 138, 0.5); /* Subtle shadow for focus */
background-color: #fff; /* Slightly brighter background on focus */
}
/* Input Field Hover Effect */
.profile-form-content input:hover {
border-color: #888; /* Darker gray border on hover */
}
/* Disabled Input Styling */
.profile-form-content input:disabled {
background-color: #e0e0e0; /* Light gray background for disabled input */
cursor: not-allowed; /* Show "not allowed" cursor */
opacity: 0.7; /* Slight transparency */
}
.profile-form-footer {
display: flex;
width: 100%;
flex-direction: column;
justify-content: space-between; /* Align buttons next to each other */
align-items: center;
gap: 10px; /* Space between buttons */
margin-top: 20px;
}
/* Styling for buttons */
.profile-form button {
flex: 1; /* Ensure buttons are equal width */
padding: 16px;
font-weight: 300;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.2s ease;
}
button[name="underline"] {
background-color: transparent; /* No background */
border: none; /* Remove default button border */
color: #4A628A; /* Set text color */
font-size: 1em; /* Set font size */
cursor: pointer; /* Add pointer cursor for interactivity */
text-decoration: underline; /* Underline text */
padding: 0; /* Remove default padding */
}
button[name="submit"] {
width: 100%;
background-color: #4A628A; /* Blue background */
color: white; /* White text color */
}
@@ -0,0 +1,151 @@
body, html {
height: 100vh;
width: 100vw;
margin: 0;
padding: 0;
font-family: "Pridi", sans-serif; /* Use sans-serif fallback */
background-color: #4A628A;
}
h4, h2, h1{
margin: 0;
}
.page{
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
.container {
border-radius: 10px;
background: linear-gradient(to bottom, rgba(74, 98, 138, 0.0) 30%, rgba(186, 237, 255, 0.7));
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
height: 90%;
width: 35%;
}
.header{
display: flex;
width: 80%;
flex-direction: column;
align-items: center;
justify-content: center;
height: 20%;
text-align: center;
padding-bottom: 16px;
padding-top: 16px;
}
.title{
font-size: 48px;
font-weight: 500;
letter-spacing: -1px;
color: white;
}
.subheading{
font-size: 16px;
letter-spacing: -0.5px;
padding-top: 8px;
color: rgba(255,255,255, 0.8);
}
.login-form{
height: 80%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
width: 80%;
}
.login-title {
font-size: 24px;
font-weight: 500;
color: white;
margin-bottom: 16px;
}
.login-form-content input {
width: 100%;
padding: 15px;
margin: 10px 0;
border: 1px solid #ccc; /* Light gray border */
border-radius: 8px; /* Rounded corners */
font-size: 1em;
font-family: inherit;
box-sizing: border-box;
background-color: #f9f9f9; /* Light background */
color: #333; /* Dark text color */
transition: border-color 0.3s ease, box-shadow 0.3s ease; /* Smooth transition for interaction */
}
/* Placeholder Text Styling */
.login-form-content input::placeholder {
color: #aaa; /* Lighter color for placeholders */
}
/* Focus State Styling */
.login-form-content input:focus {
outline: none; /* Remove default focus outline */
border-color: #4A628A; /* Blue border on focus */
box-shadow: 0 0 5px rgba(74, 98, 138, 0.5); /* Subtle shadow for focus */
background-color: #fff; /* Slightly brighter background on focus */
}
/* Input Field Hover Effect */
.login-form-content input:hover {
border-color: #888; /* Darker gray border on hover */
}
/* Disabled Input Styling */
.login-form-content input:disabled {
background-color: #e0e0e0; /* Light gray background for disabled input */
cursor: not-allowed; /* Show "not allowed" cursor */
opacity: 0.7; /* Slight transparency */
}
.login-form-footer {
display: flex;
width: 100%;
flex-direction: column;
justify-content: space-between; /* Align buttons next to each other */
align-items: center;
gap: 10px; /* Space between buttons */
margin-top: 20px;
}
/* Styling for buttons */
.login-form-footer button {
flex: 1; /* Ensure buttons are equal width */
padding: 16px;
font-weight: 300;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.2s ease;
}
button[name="underline"] {
background-color: transparent; /* No background */
border: none; /* Remove default button border */
color: #4A628A; /* Set text color */
font-size: 1em; /* Set font size */
cursor: pointer; /* Add pointer cursor for interactivity */
text-decoration: underline; /* Underline text */
padding: 0; /* Remove default padding */
}
button[name="submit"] {
width: 100%;
background-color: #4A628A; /* Blue background */
color: white; /* White text color */
}
+162
View File
@@ -0,0 +1,162 @@
body, html {
height: 100vh;
width: 100vw;
margin: 0;
padding: 0;
font-family: "Pridi", sans-serif; /* Use sans-serif fallback */
background-color: #4A628A;
}
h4, h2, h1{
margin: 0;
}
.page{
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
.container {
border-radius: 10px;
background: linear-gradient(to bottom, rgba(74, 98, 138, 0.0) 30%, rgba(186, 237, 255, 0.7));
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
align-items: center;
height: 90%;
width: 35%;
}
.header{
text-align: center;
padding-bottom: 16px;
padding-top: 32px;
}
.title{
font-size: 48px;
font-weight: 500;
letter-spacing: -1px;
color: white;
}
.subheading{
padding-top: 8px;
font-size: 16px;
letter-spacing: -0.5px;
color: rgba(255,255,255, 0.8);
}
.form{
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
width: 80%;
height: 100%;
overflow: hidden;
}
.footer {
padding-bottom: 16px;
display: flex;
width: 100%;
flex-direction: row;
justify-content: space-between; /* Align buttons next to each other */
align-items: center;
gap: 10px; /* Space between buttons */
}
.filename-title{
font-size: 16px;
font-weight: 300;
color: white;
padding: 48px 24px 48px 24px;
background-color: rgba(0,0,0,0.25);
border-radius: 10px;
margin-top: 16px;
box-shadow: 2px 2px 2px 1px rgb(0 0 0 / 20%);
}
.users_block{
padding-top: 16px;
}
label{
margin-top: 8px;
color: white;
}
.choose_user_form_content {
overflow-y: hidden;
width: 100%;
height: auto;
max-height: 180px;
display: flex;
flex-direction: column;
align-items: flex-start;
}
h5{
font-size: 20px;
font-weight: 300;
text-align: center;
color: white;
}
/* Styling for buttons */
.form button {
flex: 1; /* Ensure buttons are equal width */
padding: 16px;
font-weight: 300;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.2s ease;
}
button[name="underline"] {
background-color: transparent; /* No background */
border: none; /* Remove default button border */
color: #4A628A; /* Set text color */
font-size: 1em; /* Set font size */
cursor: pointer; /* Add pointer cursor for interactivity */
text-decoration: underline; /* Underline text */
padding: 0; /* Remove default padding */
}
button[name="submit"] {
width: 100%;
background-color: #4A628A; /* Blue background */
color: white; /* White text color */
}
button[name="submit"]:hover {
background-color: #3B5173; /* Darker background on hover */
}
.choose_user_form_content::-webkit-scrollbar {
width: 4px; /* Width of the scrollbar */
}
.choose_user_form_content::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.1); /* Track background color */
border-radius: 10px; /* Rounded corners for the track */
}
.choose_user_form_content::-webkit-scrollbar-thumb {
background-color: rgba(74, 98, 138, 0.8); /* Scrollbar handle color */
border-radius: 10px; /* Rounded corners for the scrollbar handle */
}
.choose_user_form_content::-webkit-scrollbar-thumb:hover {
background-color: rgba(74, 98, 138, 1); /* Darker color on hover */
}
.choose_user_form_content:empty {
overflow-y: hidden;
}
+25
View File
@@ -0,0 +1,25 @@
.fade-in {
animation: fadeInAnimation 0.5s ease-in forwards;
}
.fade-out {
animation: fadeOutAnimation 0.5s ease-out forwards;
}
@keyframes fadeInAnimation {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fadeOutAnimation {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="../assets/hard-disk.ico" rel="icon" type="image/x-icon">
<link href="../css/normalizer.css" rel="stylesheet">
<link href="../css/announcement.css" rel="stylesheet">
<link href="../css/transition.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Pridi:wght@200;300;400;500;600;700&display=swap" rel="stylesheet">
<title>Send Announcement</title>
</head>
<body onload="fadeIn()">
<div class="page">
<div class="container">
<div class="header">
<h1 class="title">TeamVault</h1>
<h4 class="subheading">Send an Important Announcement</h4>
</div>
<form class="announcement-form" id="announcementForm">
<textarea name="message" id="announcementMessage" placeholder="Type your announcement here..." rows="8"></textarea>
<div class="announcement-form-footer">
<button id="backButton" type="button">Back</button>
<button id="submitAnnouncement" type="button">Send Announcement</button>
</div>
</form>
</div>
</div>
<script src="../js/announcement.js"></script>
<script src="../js/helpers.js"></script>
</body>
</html>
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<link href="../assets/hard-disk.ico" rel="icon" type="image/x-icon">
<link href="../css/normalizer.css" rel="stylesheet">
<!-- Reuse the same CSS files as UC Not Found -->
<link href="../css/loading.css" rel="stylesheet">
<link href="../css/transition.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Pridi:wght@200;300;400;500;600;700&display=swap" rel="stylesheet">
<script src="../js/helpers.js"></script>
<title>Welcome</title>
</head>
<body onload="fadeIn()">
<div class="container">
<div class="header">
<h1 class="title">Team Vault</h1>
</div>
<img src="../assets/refresh-data.webp" alt="Backup Fetcher" class="backup-img">
<div class="loading-section">
<div class="spinner"></div>
<p>Backup is not searched, please wait...</p>
</div>
</div>
</body>
</html>
+43
View File
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<link href="../assets/hard-disk.ico" rel="icon" type="image/x-icon">
<link href="../css/normalizer.css" rel="stylesheet">
<link href="../css/login.css" rel="stylesheet">
<link href="../css/transition.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Pridi:wght@200;300;400;500;600;700&display=swap" rel="stylesheet">
<title>Login</title>
</head>
<body onload="fadeIn()">
<div class="page">
<div class="container">
<div class="header">
<h1 class="title">TeamVault</h1>
<h4 class="subheading">Do we know each other?</h4>
</div>
<form class="login-form" id="loginForm">
<div class="login-form-title">
<h2 class="login-title">Login</h2>
</div>
<div class="login-form-content">
<input name="email" placeholder="Email" type="email">
<input name="password" placeholder="Password" type="password">
</div>
<div class="login-form-footer">
<div>
<button id="resetPassword" name="underline" type="button">Reset Password</button>
</div>
<button id="submit" name="submit" type="submit">Submit</button>
</div>
</form>
</div>
</div>
<script src="../js/login.js"></script>
<script src="../js/helpers.js"></script>
</body>
</html>
@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<link href="../assets/hard-disk.ico" rel="icon" type="image/x-icon">
<link href="../css/normalizer.css" rel="stylesheet">
<link href="../css/main_menu.css" rel="stylesheet">
<link href="../css/transition.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Pridi:wght@200;300;400;500;600;700&display=swap" rel="stylesheet">
<script src="../js/main_menu.js"></script>
<script src="../js/helpers.js"></script>
<title>Main Page</title>
</head>
<body onload="initialSetup(); fadeIn()">
<div class="page">
<div class="container">
<div class="left_block">
<div class="notification-title">
<h1 class="notif-title">Notifications</h1>
</div>
<div class=left-content>
<div class="notifications" id="notifications">
<!--Notifications are generated here-->
</div>
<div class="left_block_footer">
<button class="logout-button" id="logout" name="logout">Logout</button>
</div>
</div>
</div>
<div class="right_block">
<div class="navbar">
<div class="welcome">
<img alt="" src="../assets/user_1144760.png">
<h3 class="user">Welcome Back,&nbsp; </h3>
<h3 class="user" id="username-field"></h3>
<h3 class="user">!</h3>
</div>
<h1 class="title">TeamVault</h1>
</div>
<div class="right_block_content">
<button id="change-info" name="menu_button">Change your info</button>
<button id="share-file" name="menu_button">Share a file</button>
<button id="send-announcement" name="menu_button">Send an announcement</button>
<button id="backup-dir" name="menu_button">Set backup directory</button>
<button id="share-dir" name="menu_button">Set share directory</button>
<button id="overview-departments" name="menu_button">Overview departments</button>
<button id="overview-users" name="menu_button">Overview users</button>
<button id="reset-database" name="menu_button">Reset database</button>
<button id="restore-backup" name="menu_button">Restore backup</button>
</div>
</div>
</div>
</div>
</body>
</html>
@@ -0,0 +1,57 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<link href="../assets/hard-disk.ico" rel="icon" type="image/x-icon">
<link href="../css/normalizer.css" rel="stylesheet">
<link href="../css/overview_departments.css" rel="stylesheet">
<link href="../css/transition.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Pridi:wght@200;300;400;500;600;700&display=swap" rel="stylesheet">
<script src="../js/helpers.js"></script>
<script src="../js/overview_departments.js"></script>
<title>Manage Departments</title>
</head>
<body onload="fetchDepartments(); fadeIn()">
<div class="page">
<div class="container">
<div class="user-management-container">
<h1 class="title">Manage Departments</h1>
<div id="departments-container" class="departments-container">
<!-- Department divs will be dynamically inserted here -->
</div>
<div class="footer">
<button id="backButton" name="underline" type="button">Back</button>
<button id="createDepartmentButton" name="submit" type="button">Create</button>
</div>
</div>
</div>
</div>
<!-- Create Department Modal -->
<div id="createDepartmentModal" class="modal">
<div class="modal-content">
<span id="closeCreateModal" class="close-button">&times;</span>
<h2 class="title" style="color: black; margin-bottom: 16px;">Create Department</h2>
<input type="text" id="newDepartmentName" placeholder="Department Name" />
<button id="confirmCreateButton" name="submit" type="button"
style="width: 30%;"
>Create</button>
</div>
</div>
<!-- Modify Department Modal -->
<div id="modifyDepartmentModal" class="modal">
<div class="modal-content">
<span id="closeModifyModal" class="close-button">&times;</span>
<h2 class="title" style="color: black; margin-bottom: 16px;">Modify Department</h2>
<input type="text" id="modifiedDepartmentName" placeholder="New Department Name" />
<button id="confirmModifyButton" name="submit" type="button"
style="width: 30%;"
>Modify</button>
</div>
</div>
</body>
</html>
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<link href="../assets/hard-disk.ico" rel="icon" type="image/x-icon">
<link href="../css/normalizer.css" rel="stylesheet">
<link href="../css/overview_users.css" rel="stylesheet">
<link href="../css/transition.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Pridi:wght@200;300;400;500;600;700&display=swap" rel="stylesheet">
<script src="../js/helpers.js"></script>
<script src="../js/overview_users.js"></script>
<title>Manage Users</title>
</head>
<body onload="fetchData(); fadeIn()">
<div class="page">
<div class="container">
<div class="user-management-container">
<h1 class="title">Manage Users</h1>
<div id="users-container" class="users-container">
<!-- User divs will be dynamically inserted here -->
</div>
<div class="footer">
<button id="backButton" name="underline" type="button">Back</button>
</div>
</div>
</div>
</div>
</body>
</html>
+40
View File
@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<link href="../assets/hard-disk.ico" rel="icon" type="image/x-icon">
<link href="../css/normalizer.css" rel="stylesheet">
<link href="../css/profile.css" rel="stylesheet">
<link href="../css/transition.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Pridi:wght@200;300;400;500;600;700&display=swap" rel="stylesheet">
<script src="../js/profile.js"></script>
<script src="../js/helpers.js"></script>
<title>Profile</title>
</head>
<body onload="fadeIn()">
<div class="page">
<div class="container">
<form class="profile-form" id="profileForm">
<div class="header">
<h1 class="title">Profile</h1>
<h3 class="subheading">Who are you?</h3>
</div>
<div class="profile-form-content">
<input name="email" placeholder="Email" type="email">
<input name="username" placeholder="Username" type="text">
<input name="password" placeholder="Password" type="password">
</div>
<div class="profile-form-footer">
<button id="back" name="underline" type="button">Back</button>
<button id="submit" name="submit" type="submit">Submit</button>
</div>
</form>
</div>
</div>
</body>
</html>
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<link href="../assets/hard-disk.ico" rel="icon" type="image/x-icon">
<link href="../css/normalizer.css" rel="stylesheet">
<link href="../css/loading.css" rel="stylesheet">
<link href="../css/transition.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Pridi:wght@200;300;400;500;600;700&display=swap" rel="stylesheet">
<script src="../js/helpers.js"></script>
<script src="../js/reset_database.js"></script>
<title>UC Not Found</title>
</head>
<body onload="fadeIn()">
<div class="container">
<div class="header">
<h1 class="title">TeamVault</h1>
</div>
<img src="../assets/2581896.png" style="margin-left: 20px" alt="Connecting to server" class="server-img">
<div class="loading-section">
<div class="spinner"></div>
<p>Please wait while we reset the database.</p>
</div>
</div>
</body>
</html>
@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<link href="../css/normalizer.css" rel="stylesheet">
<link href="../assets/hard-disk.ico" rel="icon" type="image/x-icon">
<link href="../css/reset_password.css" rel="stylesheet">
<link href="../css/transition.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Pridi:wght@200;300;400;500;600;700&display=swap" rel="stylesheet">
<title>Reset Password</title>
</head>
<body onload="fadeIn()">
<div class="page">
<div class="container">
<div class="header">
<h1 class="title">TeamVault</h1>
<h3 class="subheading">Forgot your password? No worries, it happens to the best of us!</h3>
</div>
<form class="login-form" id="resetPasswordForm">
<div class="login-form-title">
<h2 class="login-title">Reset Password</h2>
</div>
<div class="login-form-content">
<input name="email" placeholder="Email" type="email" required>
<input name="newPassword" placeholder="New Password" type="password" required>
</div>
<div class="login-form-footer">
<button id="backToLogin" name="underline" type="button">Back to Login</button>
<button id="resetPassword" name="submit" type="submit">Reset Password</button>
</div>
</form>
</div>
</div>
<script src="../js/reset_password.js"></script>
<script src="../js/helpers.js"></script>
</body>
</html>
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="../assets/hard-disk.ico" rel="icon" type="image/x-icon">
<link href="../css/normalizer.css" rel="stylesheet">
<link href="../css/loading.css" rel="stylesheet">
<link href="../css/transition.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Pridi:wght@200;300;400;500;600;700&display=swap" rel="stylesheet">
<script src="../js/helpers.js"></script>
<title>Sending Announcement</title>
</head>
<body onload="fadeIn()">
<div class="container">
<div class="header">
<h1 class="title">TeamVault</h1>
</div>
<img src="../assets/mail_2772213.png" alt="Sending announcement" class="announcement-img">
<div class="loading-section">
<div class="spinner"></div>
<p>Sending announcement to all users. Please wait...</p>
</div>
</div>
</body>
</html>
@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<link href="../assets/hard-disk.ico" rel="icon" type="image/x-icon">
<link href="../css/normalizer.css" rel="stylesheet">
<link href="../css/share_file.css" rel="stylesheet">
<link href="../css/transition.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Pridi:wght@200;300;400;500;600;700&display=swap" rel="stylesheet">
<script src="../js/share_file.js"></script>
<script src="../js/helpers.js"></script>
<title>Share File</title>
</head>
<body onload="fetchUsersAndCreateCheckboxes(); updateFileName(); fadeIn()">
<div class="page">
<div class="container">
<div class="form">
<div class="header">
<h1 class="title">Share a File</h1>
<h3 class="subheading">First select the file you want to share.</h3>
<button class="filename-title" id="selectFile" name="submit" type="button">Select</button>
<form class="users_block" id="userDestForm">
<h5>Users</h5>
<h3 class="subheading">Select the users you want to share the file with.</h3>
<div id="choose_user_form_content" class="choose_user_form_content">
<!-- Insert the users from the database -->
</div>
</form>
</div>
<div class="footer">
<button id="backButton" name="underline" type="button">Back</button>
<button id="submitButton" name="submit" type="submit">Submit</button>
</div>
</div>
</div>
</div>
</body>
</html>
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<link href="../assets/hard-disk.ico" rel="icon" type="image/x-icon">
<link href="../css/normalizer.css" rel="stylesheet">
<link href="../css/loading.css" rel="stylesheet">
<link href="../css/transition.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Pridi:wght@200;300;400;500;600;700&display=swap" rel="stylesheet">
<script src="../js/helpers.js"></script>
<title>UC Not Found</title>
</head>
<body onload="fadeIn()">
<div class="container">
<div class="header">
<h1 class="title">TeamVault</h1>
</div>
<img src="../assets/cloud-computing.webp" alt="Connecting to server" class="server-img">
<div class="loading-section">
<div class="spinner"></div>
<p>Please wait while we try to connect to the server.</p>
</div>
</div>
</body>
</html>
+29
View File
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<link href="../assets/hard-disk.ico" rel="icon" type="image/x-icon">
<link href="../css/normalizer.css" rel="stylesheet">
<!-- Reuse the same CSS files as UC Not Found -->
<link href="../css/loading.css" rel="stylesheet">
<link href="../css/transition.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Pridi:wght@200;300;400;500;600;700&display=swap" rel="stylesheet">
<script src="../js/helpers.js"></script>
<title>Welcome</title>
</head>
<body onload="fadeIn()">
<div class="container">
<div class="header">
<h1 class="title">Welcome to TeamVault</h1>
</div>
<div class="loading-section">
<div class="spinner"></div>
<p>Initializing the application, please wait...</p>
</div>
</div>
</body>
</html>
+22
View File
@@ -0,0 +1,22 @@
document.addEventListener('DOMContentLoaded', function () {
const submitButton = document.getElementById('submitAnnouncement');
const buttonBack = document.getElementById('backButton');
const announcementTextarea = document.getElementById('announcementMessage');
buttonBack.addEventListener('click', function () {
fadeOut('main_menu');
});
submitButton.addEventListener('click', async function () {
const message = announcementTextarea.value.trim();
if (message === '') {
await window.uiAPI.showAlert('Please enter a message before sending.');
return;
}
// Send the announcement message via the electronAPI
window.workersAPI.startAnnouncementWorker(message);
fadeOut('send_announcement');
});
});
+47
View File
@@ -0,0 +1,47 @@
function fadeIn() {
document.querySelector('.container').classList.remove('fade-out');
document.querySelector('.container').classList.add('fade-in');
}
function fadeOut(destination) {
const container = document.querySelector('.container');
container.classList.remove('fade-in');
container.classList.add('fade-out');
console.log(destination);
setTimeout(() => {}, 5000);
container.addEventListener('animationend', async () => {
try {
await window.uiAPI.changeContent(destination);
console.log('Navigated to', destination);
} catch (error) {
console.error('Error navigating:', error);
}
});
}
async function waitForResponse() {
return new Promise((resolve) => {
const idResponseCheck = setInterval(async () => {
if (await window.networkAPI.hasResponseArrived()) {
clearInterval(idResponseCheck);
resolve(await window.networkAPI.getLastUcResult()); // Resolve the response or null if not available
}
}, 100); // Check every 100 milliseconds if the response has arrived
});
}
function toggleScroll(idComponent, scrollHeight = 180) {
const element = document.getElementById(idComponent); // Using getElementById
if (!element) {
console.error(`Element with ID '${idComponent}' not found.`);
return;
}
if (element.scrollHeight > scrollHeight) {
element.style.overflowY = 'auto'; // Enable scroll if content overflows
} else {
element.style.overflowY = 'hidden'; // Disable scroll if content fits
}
}
+147
View File
@@ -0,0 +1,147 @@
let codeLogin = '';
let codeFindByEmail = '';
let codeFindKeyByUser = '';
let codeOk = '';
document.addEventListener('DOMContentLoaded', async function () {
const submitButton = document.getElementById('submit');
const resetPasswordButton = document.getElementById('resetPassword');
// Retrieve the operation codes via IPC
const operationCodes = await window.networkAPI.getOperationsCodes();
if (!operationCodes) {
await window.uiAPI.showAlert('Internal error of the application. Failed to retrieve operation codes.');
return;
}
codeLogin = operationCodes.LOGIN;
codeFindByEmail = operationCodes.FIND_BY_EMAIL;
codeFindKeyByUser = operationCodes.FIND_KEY_BY_USER_ID;
codeOk = operationCodes.OK;
resetPasswordButton.addEventListener('click', function (e) {
e.preventDefault();
window.uiAPI.changeContent('reset_password');
});
// Submit button logic (handle login)
submitButton.addEventListener('click', async function (e) {
e.preventDefault();
console.log('Submit button clicked');
const form = document.getElementById('loginForm');
const formData = new FormData(form);
const email = formData.get('email');
const password = formData.get('password');
// Open a TCP socket to the stored IP
if (!await window.networkAPI.openUcSocket()) {
await window.uiAPI.showAlert('Internal error of the application. Unable to open socket.');
return;
}
// Attempt login
if (!await attemptLogin(email, password)) {
await window.networkAPI.closeUcSocket();
return;
}
// Fetch and store user info
if (!await fetchAndStoreUserInfo(email)) {
await window.networkAPI.closeUcSocket();
return;
}
// Fetch user info from local storage
const userInfo = await window.databaseAPI.getUserInfo('user_info');
if (!userInfo) {
await window.networkAPI.closeUcSocket();
await window.uiAPI.showAlert('Failed to fetch user info.');
return;
}
// Fetch and store encryption key
if (!await fetchAndStoreEncryptionKey(userInfo.id)) {
await window.networkAPI.closeUcSocket();
return;
}
// Close the socket and navigate to main menu after success
await window.networkAPI.closeUcSocket();
await window.workersAPI.startWorkers();
await window.databaseAPI.setLoginStatus(true);
await window.uiAPI.changeContent('main_menu');
});
});
async function attemptLogin(email, password) {
const app_type = await window.databaseAPI.getAppType();
const messageData = {email, password, app_type};
// Send the login message to the server
if (!await window.networkAPI.sendUcMessage(codeLogin, messageData)) {
await window.uiAPI.showAlert('Failed to send login request.');
return false;
}
// Wait for the response using waitForResponse
const response = await waitForResponse();
if (!response) {
await window.uiAPI.showAlert('No response from server.');
return false;
}
if (response.operationCode !== codeOk) {
await window.uiAPI.showAlert(response.metaInfo.message);
return false;
}
return true;
}
async function fetchAndStoreUserInfo(userEmail) {
if (!await window.networkAPI.sendUcMessage(codeFindByEmail, {email: userEmail})) {
await window.uiAPI.showAlert('Failed to send request to fetch user info.');
return false;
}
// Wait for the response using waitForResponse
const response = await waitForResponse();
if (response && response.operationCode === codeOk) {
const userInfo = {};
userInfo.id = response.metaInfo.id;
userInfo.email = response.metaInfo.email;
userInfo.departmentId = response.metaInfo.departmentId;
userInfo.name = response.metaInfo.name || 'User';
await window.databaseAPI.writeUserInfo(userInfo);
return true;
}
await window.uiAPI.showAlert('Failed to fetch user info from server.');
return false;
}
async function fetchAndStoreEncryptionKey(userId) {
if (!await window.networkAPI.sendUcMessage(codeFindKeyByUser, {userId})) {
await window.uiAPI.showAlert('Failed to send request to fetch encryption key.');
return false;
}
// Wait for the response using waitForResponse
const response = await waitForResponse();
if (response && response.operationCode === codeOk) {
const encryptionKey = {
key: response.metaInfo.key.key,
iv: response.metaInfo.key.iv,
};
await window.databaseAPI.writeEncryptionKey(encryptionKey);
return true;
}
await window.uiAPI.showAlert('Failed to fetch encryption key from server.');
return false;
}
+203
View File
@@ -0,0 +1,203 @@
document.addEventListener('DOMContentLoaded', async function () {
setInterval(loadReceivedFiles, 3000); // Call loadReceivedFiles every 3000 ms (3 seconds)
const backupButton = document.getElementById('backup-dir');
const shareButton = document.getElementById('share-dir');
const changeInfoButton = document.getElementById('change-info');
const shareFileButton = document.getElementById('share-file');
const logoutButton = document.getElementById('logout');
const restoreBackupButton = document.getElementById('restore-backup');
const buttonOverviewDepartments = document.getElementById('overview-departments');
const buttonOverviewUsers = document.getElementById('overview-users');
const buttonResetDatabase = document.getElementById('reset-database');
const buttonSendAnnouncement = document.getElementById('send-announcement');
backupButton.addEventListener('click', async function () {
await setPath('backupDirectory');
});
shareButton.addEventListener('click', async function () {
await setPath('shareDirectory');
});
buttonResetDatabase.addEventListener('click', async function () {
// Show a confirmation dialog
const userConfirmed = await showConfirmationDialog("Are you sure you want to reset the database? This action cannot be undone.");
// If the user confirms, perform the database reset
if (userConfirmed) {
await resetDatabase();
} else {
window.uiAPI.showAlert("Database reset canceled.");
}
});
buttonSendAnnouncement.addEventListener('click', async function () {
fadeOut('announcement');
});
buttonOverviewDepartments.addEventListener('click', async function () {
fadeOut('overview_departments');
});
buttonOverviewUsers.addEventListener('click', async function () {
fadeOut('overview_users');
});
changeInfoButton.addEventListener('click', function () {
fadeOut('profile');
});
shareFileButton.addEventListener('click', function () {
fadeOut('share_file');
});
logoutButton.addEventListener('click', async function () {
fadeOut('login');
});
// Add event listener for the restore backup button
restoreBackupButton.addEventListener('click', async function () {
await restoreBackup();
});
});
async function initialSetup(){
await checkAndSetAllDirectories();
await loadReceivedFiles();
await fetchUserInfo();
}
async function restoreBackup() {
const backupDirectory = await window.databaseAPI.isBackupSet();
if (backupDirectory) {
await window.uiAPI.showAlert('You have already set a backup directory. You cannot restore again.');
return;
}
// Prompt the user to choose the destination for the restored backup
const destinationPath = await window.uiAPI.selectDirectory();
if (!destinationPath) {
return; // User canceled the directory selection
}
// Call the IPC method to initiate the backup retrieval process
window.workersAPI.startBackupRetrieval(destinationPath);
// Switch the content to the 'backup_retrieve' page
fadeOut('backup_retrieve');
}
async function checkAndSetAllDirectories() {
const directorySchemes = await window.databaseAPI.getLocalResources();
backupDirId = directorySchemes.backup.id;
shareDirId = directorySchemes.shared.id;
departmentDirId = directorySchemes.department.id;
await attachNotificationButton(backupDirId, 'Set your backup directory!', 'backup_alert', 'alert');
await attachNotificationButton(shareDirId, 'Set your share directory!', 'share_alert', 'alert');
await attachNotificationButton(departmentDirId, 'Set your department directory!', 'department_alert', 'alert');
}
async function checkPathExistence(id) {
const dirInfo = await window.databaseAPI.getDirectoryInfo(id);
return dirInfo.path !== ''
}
async function setPath(id){
const path = await window.uiAPI.selectDirectory();
if (path === undefined) return false;
return await window.databaseAPI.writeDirectoryPath(id, path);
}
async function attachNotificationButton(entryId, buttonText, buttonId, buttonName) {
const path = await checkPathExistence(entryId);
if (!path) {
const notificationsDiv = document.getElementById('notifications');
const button = document.createElement('button');
button.className='alert';
button.id = buttonId;
button.name = buttonName;
button.textContent = buttonText;
button.addEventListener('click', async function () {
if(await setPath(entryId)) button.remove();
});
notificationsDiv.appendChild(button);
}
}
async function fetchUserInfo() {
const usernameField = document.getElementById('username-field');
// Read the user credentials from the userConfig
let userInfo = await window.databaseAPI.getUserInfo();
if (userInfo && userInfo.name) {
usernameField.textContent = userInfo.name;
return;
}
// Update the greeting with the fetched user's name
if (usernameField) {
usernameField.textContent = userInfo.name;
} else {
console.error("Username field is not available in the DOM.");
}
}
async function loadReceivedFiles() {
// Read the shareDirectory from applicationInfo
const shareDirData = await window.databaseAPI.getDirectoryInfo(shareDirId);
console.log('Loading received files:', shareDirData);
const notificationsDiv = document.getElementById('notifications');
const existingButtons = Array.from(notificationsDiv.children).map(button => button.getAttribute('data-filepath'));
// Iterate over each user and their files in the structure
Object.keys(shareDirData.structure).forEach(userName => {
const userFiles = shareDirData.structure[userName];
// Iterate over each file of the user
Object.keys(userFiles).forEach(fileName => {
const filePath = userFiles[fileName];
// Check if a button for this file path already exists
if (!existingButtons.includes(filePath)) {
const button = document.createElement('button');
button.setAttribute('data-filepath', filePath); // Set a custom attribute to track the file path
button.className = 'notification';
button.name = 'notification';
button.textContent = `You received a file "${fileName}" from ${userName}`; // Display the userName and file name
button.addEventListener('click', () => handleFileReceivedButtonPressed(filePath, button));
notificationsDiv.appendChild(button);
}
});
});
}
async function handleFileReceivedButtonPressed(filePath, button) {
console.log('Notification button clicked!');
// Open the file in the file explorer
await window.uiAPI.showFileInExplorer(filePath)
.then(() => console.log('File explorer opened for: ' + filePath))
.catch(error => console.error('Error opening file explorer:', error));
// Remove the button after opening the file
button.remove();
}
async function showConfirmationDialog(message) {
return new Promise((resolve) => {
const userResponse = window.confirm(message); // Show native confirmation dialog
resolve(userResponse); // Resolve with true (OK) or false (Cancel)
});
}
async function resetDatabase(){
fadeOut('reset_database');
}
@@ -0,0 +1,209 @@
let codeOk = '';
let codeGetDepartments = '';
let codeCreateDepartment = '';
let codeModifyDepartment = '';
let codeDeleteDepartment = '';
document.addEventListener('DOMContentLoaded', async () => {
const backButton = document.getElementById('backButton');
const createButton = document.getElementById('createDepartmentButton');
const closeCreateModalButton = document.getElementById('closeCreateModal');
const confirmCreateButton = document.getElementById('confirmCreateButton');
if (!await window.networkAPI.openUcSocket()) {
await window.uiAPI.showAlert('Internal error of the application. Unable to open socket.');
return;
}
backButton.addEventListener('click', async () => {
await window.networkAPI.closeUcSocket();
fadeOut('main_menu');
});
// Show the Create Department Modal
createButton.addEventListener('click', () => {
document.getElementById('createDepartmentModal').style.display = 'block';
});
// Close Modals
closeCreateModalButton.addEventListener('click', () => {
document.getElementById('createDepartmentModal').style.display = 'none';
});
// Confirm Create Department
confirmCreateButton.addEventListener('click', async () => {
const departmentName = document.getElementById('newDepartmentName').value.trim();
if (!departmentName) {
window.uiAPI.showAlert("Please enter a department name.");
return;
}
await createDepartment(departmentName);
document.getElementById('createDepartmentModal').style.display = 'none';
});
});
// Example usage to render these dummy departments
async function fetchDepartments() {
const departmentsContainer = document.getElementById('departments-container');
departmentsContainer.innerHTML = ''; // Clear any existing data
// Retrieve the operation codes via IPC
const operationCodes = await window.networkAPI.getOperationsCodes();
if (!operationCodes) {
await window.uiAPI.showAlert('Internal error of the application. Failed to retrieve operation codes.');
return;
}
codeOk = operationCodes.OK;
codeGetDepartments = operationCodes.GET_DEPARTMENTS;
codeCreateDepartment = operationCodes.CREATE_DEPARTMENT;
codeModifyDepartment = operationCodes.MODIFY_DEPARTMENT;
codeDeleteDepartment = operationCodes.DELETE_DEPARTMENT;
// Send the login message to the server
if (!await window.networkAPI.sendUcMessage(codeGetDepartments)) {
await window.uiAPI.showAlert('Failed to send login request.');
return false;
}
// Wait for the response using waitForResponse
const response = await waitForResponse();
if(!response || response.operationCode !== codeOk){
await window.uiAPI.showAlert('Could not fetch departments.');
return false;
}
const departments = response.metaInfo.departments;
const filteredDepartments = departments.filter(department => department.name.toLowerCase() !== 'ceo');
if (!filteredDepartments.length) {
const noDepartmentsMessage = document.createElement('p');
noDepartmentsMessage.textContent = 'No departments exist.';
noDepartmentsMessage.classList.add('no-departments-message');
departmentsContainer.appendChild(noDepartmentsMessage);
return;
}
filteredDepartments.forEach(department => {
const departmentDiv = document.createElement('div');
departmentDiv.classList.add('department-card');
const nameDiv = document.createElement('div');
nameDiv.classList.add('department-name');
nameDiv.textContent = department.name;
// Create and add Modify button
const modifyButton = document.createElement('button');
modifyButton.textContent = 'Modify';
modifyButton.classList.add('modify-button');
modifyButton.dataset.departmentId = department.id;
modifyButton.addEventListener('click', () => {
console.log(`Modify button clicked for department ID: ${department.id}`);
openModifyModal(department.id, department.name); // Call the function to open the modify modal
});
// Create and add Delete button
const deleteButton = document.createElement('button');
deleteButton.textContent = 'Delete';
deleteButton.classList.add('delete-button');
deleteButton.dataset.departmentId = department.id;
deleteButton.addEventListener('click', async () => {
console.log(`Delete button clicked for department ID: ${department.id}`);
await deleteDepartment(department.id); // Call the function to delete the department
});
departmentDiv.appendChild(nameDiv);
departmentDiv.appendChild(modifyButton);
departmentDiv.appendChild(deleteButton);
departmentsContainer.appendChild(departmentDiv);
});
toggleScroll('departments-container', 370);
}
async function createDepartment(departmentName) {
if (!await window.networkAPI.sendUcMessage(codeCreateDepartment, { departmentName: departmentName })) {
await window.uiAPI.showAlert('Failed to send login request.');
return false;
}
// Wait for the response using waitForResponse
const response = await waitForResponse();
if(!response || response.operationCode !== codeOk){
await window.uiAPI.showAlert('Could not create new department.');
return false;
}
await fetchDepartments();
}
async function modifyDepartment(departmentId, newDepartmentName) {
if (!await window.networkAPI.sendUcMessage(codeModifyDepartment, { departmentId: departmentId, newDepartmentName: newDepartmentName })) {
await window.uiAPI.showAlert('Failed to send modify request.');
return false;
}
// Wait for the response using waitForResponse
const response = await waitForResponse();
if(!response || response.operationCode !== codeOk){
await window.uiAPI.showAlert('Could not modify department.');
console.log(response.metaInfo.message);
return false;
}
await fetchDepartments();
}
async function deleteDepartment(departmentId) {
const confirmDelete = confirm("Are you sure you want to delete this department?");
if (!confirmDelete) return;
if (!await window.networkAPI.sendUcMessage(codeDeleteDepartment, { departmentId: departmentId })) {
await window.uiAPI.showAlert('Failed to send delete request.');
return false;
}
const response = await waitForResponse();
if(!response || response.operationCode !== codeOk){
await window.uiAPI.showAlert('Could not delete department.');
return false;
}
await fetchDepartments();
}
// Show the Modify Department Modal
function openModifyModal(departmentId, departmentName) {
document.getElementById('confirmModifyButton').value = departmentId;
document.getElementById('modifiedDepartmentName').value = departmentName;
document.getElementById('modifyDepartmentModal').style.display = 'block';
document.getElementById('closeModifyModal').addEventListener('click', () => {
document.getElementById('modifyDepartmentModal').style.display = 'none';
});
document.getElementById('confirmModifyButton').addEventListener('click', async () => {
const newDepartmentName = document.getElementById('modifiedDepartmentName').value.trim();
const departmentId = document.getElementById('confirmModifyButton').value;
console.log(newDepartmentName, departmentId);
if (!newDepartmentName || !departmentId) {
window.uiAPI.showAlert("Please enter a new department name.");
return;
}
await modifyDepartment(departmentId, newDepartmentName);
document.getElementById('modifyDepartmentModal').style.display = 'none';
});
}
+150
View File
@@ -0,0 +1,150 @@
let codeGetDepartments = '';
let codeGetUsers = '';
let codeDeleteUser = '';
let codeOk = '';
document.addEventListener('DOMContentLoaded', async () => {
const backButton = document.getElementById('backButton');
backButton.addEventListener('click', async () => {
await window.networkAPI.closeUcSocket();
fadeOut('main_menu');
});
});
async function fetchData() {
const operationCodes = await window.networkAPI.getOperationsCodes();
if (!operationCodes) {
await window.uiAPI.showAlert('Internal error of the application. Failed to retrieve operation codes.');
return;
}
codeGetDepartments = operationCodes.GET_DEPARTMENTS;
codeGetUsers = operationCodes.GET_USERS;
codeDeleteUser = operationCodes.DELETE_USER;
codeOk = operationCodes.OK;
// Open the TCP socket right after fetching the operation codes
if (!await window.networkAPI.openUcSocket()) {
alert('Failed to open socket. Internal error of the application.');
return;
}
// Fetch departments
const departmentsResponse = await fetchDepartments();
if (!departmentsResponse || departmentsResponse.operationCode !== codeOk) {
alert('Failed to fetch departments. Redirecting to main menu...');
await redirectToMainMenu();
return;
}
const departments = departmentsResponse.metaInfo.departments;
// Fetch users
const usersResponse = await fetchUsers();
if (!usersResponse || usersResponse.operationCode !== codeOk) {
alert('Failed to fetch users. Redirecting to main menu...');
await redirectToMainMenu();
return;
}
const users = usersResponse.metaInfo.users;
const usersContainer = document.getElementById('users-container');
usersContainer.innerHTML = ''; // Clear the container
// Filter out users in the CEO department
const ceoDepartment = departments.find(dept => dept.name.toLowerCase() === 'ceo');
const filteredUsers = users.filter(user => user.departmentId !== ceoDepartment.id);
// Check if there are no users after filtering
if (!filteredUsers.length) {
const noUsersMessage = document.createElement('p');
noUsersMessage.textContent = 'No users exist.';
noUsersMessage.classList.add('no-users-message'); // Add a class for styling
usersContainer.appendChild(noUsersMessage);
fadeIn(); // Fade in the container when the message is loaded
return;
}
// Render users if there are any
filteredUsers.forEach(user => {
const userDiv = document.createElement('div');
userDiv.classList.add('user-card');
// Create user info div
const userInfoDiv = document.createElement('div');
userInfoDiv.classList.add('user-info');
// Create user name paragraph
const nameP = document.createElement('p');
nameP.classList.add('user-name');
nameP.textContent = user.name;
console.log(user)
console.log(departments)
// Find and display user's department name
const department = departments.find(dept => dept.id === user.departmentId);
const departmentName = department ? department.name : 'Unknown';
// Create user department paragraph
const departmentP = document.createElement('p');
departmentP.classList.add('user-department');
departmentP.textContent = `Department: ${departmentName}`;
// Append name and department to user info div
userInfoDiv.appendChild(nameP);
userInfoDiv.appendChild(departmentP);
// Create delete button
const deleteButton = document.createElement('button');
deleteButton.textContent = 'Delete';
deleteButton.classList.add('delete-button');
deleteButton.onclick = () => deleteUser(user.id);
// Append user info div and delete button to user card
userDiv.appendChild(userInfoDiv);
userDiv.appendChild(deleteButton);
// Append user card to the container
usersContainer.appendChild(userDiv);
});
}
async function fetchDepartments() {
// Send the request to get departments
if (!await window.networkAPI.sendUcMessage(codeGetDepartments)) {
return null;
}
return await waitForResponse();
}
async function fetchUsers() {
// Send the request to get users
if (!await window.networkAPI.sendUcMessage(codeGetUsers)) {
return null;
}
return await waitForResponse();
}
async function deleteUser(userId) {
// Send the request to delete the user
if (!await window.networkAPI.sendUcMessage(codeDeleteUser, {id: userId})) {
alert('Failed to send request to delete user.');
return;
}
const response = await waitForResponse();
if (!response || response.operationCode !== codeOk) {
alert('Failed to delete user.');
return;
}
await fetchData();
}
async function redirectToMainMenu() {
await window.networkAPI.closeUcSocket();
fadeOut('main_menu');
}
+86
View File
@@ -0,0 +1,86 @@
let id = '';
let departmentId = '';
document.addEventListener('DOMContentLoaded', async function () {
const {id: userId, name, email, departmentId: userDepartmentId} = await window.databaseAPI.getUserInfo();
const emailInput = document.querySelector('input[name="email"]');
const usernameInput = document.querySelector('input[name="username"]');
const passwordInput = document.querySelector('input[name="password"]');
// Pre-fill form fields with existing data
id = userId
departmentId = userDepartmentId;
usernameInput.value = name;
emailInput.value = email;
passwordInput.value = '';
const backButton = document.getElementById('back');
const submitButton = document.getElementById('submit');
// Get operation codes from the backend
const operationCodes = await window.networkAPI.getOperationsCodes();
if (!operationCodes) {
await window.uiAPI.showAlert('Internal error of the application.');
return;
}
const codeModifyUser = operationCodes.MODIFY_USER;
const codeOk = operationCodes.OK;
// Handle the back button click
backButton.addEventListener('click', async function () {
console.log('Back button clicked!');
fadeOut('main_menu');
});
// Handle the submit button click
submitButton.addEventListener('click', async function (e) {
e.preventDefault();
console.log('Submit button clicked!');
// Fetch form values
const email = emailInput.value;
const name = usernameInput.value;
const password = passwordInput.value;
const app_type = await window.databaseAPI.getAppType();
// Prepare the data to be sent via the UC socket
const messageData = {
id: id,
name: name,
email: email,
password: password,
departmentId: departmentId,
app_type: app_type
};
// Open UC socket
if (!await window.networkAPI.openUcSocket()) {
await window.uiAPI.showAlert('Failed to open socket. Internal error of the application.');
return;
}
// Send the message to the server using the UC socket
if (!await window.networkAPI.sendUcMessage(codeModifyUser, messageData)) {
await window.uiAPI.showAlert('Failed to send message.');
return;
}
// Wait for the response
const response = await waitForResponse();
if (response && response.operationCode === codeOk) {
console.log('User update successful.');
// Save updated user info to the userConfig
await window.databaseAPI.writeUserInfo({ id: id, email: email, name: name, departmentId: departmentId });
// Navigate back to the main menu
fadeOut('main_menu');
} else {
console.log('Error updating user:', response?.metaInfo?.message || 'Unknown error');
await window.electronAPI.showAlert(response?.metaInfo?.message || 'Unknown error occurred');
}
});
});
@@ -0,0 +1,31 @@
document.addEventListener('DOMContentLoaded', async function () {
const operationCodes = await window.networkAPI.getOperationsCodes();
if (!operationCodes) {
await window.uiAPI.showAlert('Internal error of the application. Failed to retrieve operation codes.');
return;
}
const codeResetDatabase = operationCodes.RESET_DATABASE;
const codeOk = operationCodes.OK;
// Open a TCP socket to the stored IP
if (!await window.networkAPI.openUcSocket()) {
await window.uiAPI.showAlert('Internal error of the application. Unable to open socket.');
return;
}
if (!await window.networkAPI.sendUcMessage(codeResetDatabase)) {
await window.uiAPI.showAlert('Failed to send login request.');
return;
}
const response = await waitForResponse();
if (response && response.operationCode !== codeOk) {
await window.uiAPI.showAlert('Database reset failed.');
return;
}
await window.networkAPI.closeUcSocket();
await new Promise(resolve => setTimeout(resolve, 2000));
fadeOut('login');
});
@@ -0,0 +1,66 @@
let codeResetPassword = '';
let codeOk = '';
document.addEventListener('DOMContentLoaded', async function () {
const backToLoginButton = document.getElementById('backToLogin');
const resetPasswordButton = document.getElementById('resetPassword');
// Retrieve the operation codes via IPC
const operationCodes = await window.networkAPI.getOperationsCodes();
if (!operationCodes) {
await window.uiAPI.showAlert('Internal error of the application.');
return;
}
codeResetPassword = operationCodes.RESET_PASSWORD;
codeOk = operationCodes.OK;
// Back to login
backToLoginButton.addEventListener('click', function (e) {
e.preventDefault();
window.uiAPI.changeContent('login');
});
// Reset password logic
resetPasswordButton.addEventListener('click', async function (e) {
e.preventDefault();
if (!await window.networkAPI.openUcSocket()) {
await window.uiAPI.showAlert('Internal error of the application.');
return;
}
const form = document.getElementById('resetPasswordForm');
const formData = new FormData(form);
const email = formData.get('email');
const newPassword = formData.get('newPassword');
// Ensure the email and new password are provided
if (!email || !newPassword) {
await window.uiAPI.showAlert('Please provide both email and new password.');
return;
}
if (!await attemptResetPassword(email, newPassword)) {
return;
}
await window.networkAPI.closeUcSocket();
await window.uiAPI.showAlert('Password reset successfully.');
await window.uiAPI.changeContent('login');
});
});
async function attemptResetPassword(email, newPassword) {
const app_type = await window.databaseAPI.getAppType();
const messageData = { email, newPassword, app_type };
if (!await window.networkAPI.sendUcMessage(codeResetPassword, messageData)) return false;
const response = await waitForResponse();
if (response && response.operationCode === codeOk) {
return true;
} else {
await window.uiAPI.showAlert(response?.metaInfo?.message || 'Error resetting password.');
return false;
}
}
+121
View File
@@ -0,0 +1,121 @@
let pathToFile = '';
let fetchUsersInterval = null;
document.addEventListener('DOMContentLoaded', async function () {
const selectFileButton = document.getElementById('selectFile');
const submitButton = document.getElementById('submitButton');
const backButton = document.getElementById('backButton');
selectFileButton.addEventListener('click', async function (event) {
event.preventDefault();
try {
pathToFile = await window.uiAPI.selectFile();
updateFileName();
} catch (error) {
console.error('Error opening file dialog:', error);
}
});
submitButton.addEventListener('click', async function (event) {
event.preventDefault();
// Check if a file was chosen
if (!pathToFile.trim()) {
await window.uiAPI.showAlert('File not chosen!');
return;
}
const user_info = await window.databaseAPI.getUserInfo();
if (!user_info) {
return;
}
const form = document.getElementById('userDestForm');
const checkboxes = form.querySelectorAll('input[name="users"]');
const selectedUserIps = Array.from(checkboxes)
.filter(checkbox => checkbox.checked)
.map(checkbox => checkbox.value); // Get IP of the selected users
if (!selectedUserIps.length) {
await window.uiAPI.showAlert('No user selected!');
return;
}
for (const selectedUserIp of selectedUserIps) {
try {
// Add task to send file to the queue
const task = {
ip: selectedUserIp, // Destination IP for the file
path: pathToFile, // File path
userName: user_info.name // Sender's username from userConfig
};
await window.databaseAPI.addTaskToSendFileQueue(task);
await window.uiAPI.showAlert('File sent to the queue.');
console.log(`Task added to send file to IP ${selectedUserIp}`);
} catch (error) {
console.error(`Error processing IP ${selectedUserIp}:`, error);
}
}
});
backButton.addEventListener('click', function (event) {
event.preventDefault();
fadeOut('main_menu');
});
setInterval(fetchUsersAndCreateCheckboxes, 5000);
});
// Function to update the file name display
function updateFileName() {
const fileNameElement = document.getElementById('selectFile');
if (!fileNameElement) {
return;
}
if (pathToFile.trim() === '') {
fileNameElement.textContent = 'No file chosen';
} else {
fileNameElement.textContent = pathToFile.split('\\').pop().split('/').pop();
}
}
async function fetchUsersAndCreateCheckboxes() {
// Step 1: Get the currently checked users before refreshing the list
const selectedUserIps = new Set(
Array.from(document.querySelectorAll('input[name="users"]:checked'))
.map(checkbox => checkbox.value)
);
const usersInfo = await window.databaseAPI.getActiveUsers();
const filteredUsers = usersInfo.filter(user => user.id !== '');
if (!filteredUsers.length === 0) {
await window.uiAPI.showAlert('No active users found.');
clearInterval(fetchUsersInterval);
fetchUsersInterval = null;
await window.uiAPI.changeContent('main_menu');
return;
}
const usersDiv = document.getElementById('choose_user_form_content');
usersDiv.innerHTML = ''; // Clear the list before updating
usersInfo.forEach(user => {
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.name = 'users';
checkbox.value = user.ip; // Store user's IP in the value
// Step 2: Check if this user was previously selected
if (selectedUserIps.has(user.ip)) {
checkbox.checked = true; // Restore checked state
}
const label = document.createElement('label');
label.innerHTML = `${user.name}`;
label.insertBefore(checkbox, label.firstChild);
usersDiv.appendChild(label);
});
toggleScroll('choose_user_form_content');
}