first commit

This commit is contained in:
Alomairi 2024-08-29 11:42:20 +00:00
commit 45da69700c
14 changed files with 1321 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
# config/db.config.js
node_modules
upload/*
stuff-expermental
package-lock.json
config/db.config.js

20
README.md Normal file
View File

@ -0,0 +1,20 @@
# Terminal Diagnostic Helper
## Overview
**Terminal Diagnostic Helper** is an application designed to assist engineers in diagnosing and resolving issues with POS terminals. Users can view terminal images, select problems, record fixes, and generate reports in Excel format, while also sending data to a server for storage.
## Features
- **Terminal Image View:** Display images of POS terminals for easier diagnosis.
- **Problem Selection:** Choose from a list of common terminal problems.
- **Fix Logging:** Record the fixes applied to each issue.
- **Excel Export:** Copy diagnostic and repair data to an Excel spreadsheet.
- **Server Storage:** Automatically save diagnostic data to a server.
## Installation
1. **Clone the Repository:**
```bash
git clone https://github.com/yourusername/your-repository.git
```

View File

@ -0,0 +1,6 @@
module.exports = {
host: 'database or ip',
user: 'user',
password: 'pass',
database: 'dbname'
}

30
login.html Normal file
View File

@ -0,0 +1,30 @@
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,minimum-scale=1">
<title>Login</title>
<!-- the form awesome library is used to add icons to our form -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css">
<!-- include the stylesheet file -->
<link href="/style.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="login">
<h1>Login</h1>
<form action="/auth" method="post">
<label for="username">
<!-- font awesome icon -->
<i class="fas fa-user"></i>
</label>
<input type="text" name="username" placeholder="Username" id="username" required>
<label for="password">
<i class="fas fa-lock"></i>
</label>
<input type="password" name="password" placeholder="Password" id="password" required>
<input type="submit" value="Login">
</form>
</div>
</body>
</html>

162
main.js Normal file
View File

@ -0,0 +1,162 @@
const express = require('express');
const fs = require('fs');
const path = require('path');
const mysql = require("mysql2/promise");
const config = require("./config/db.config.js");
const session = require('express-session');
const PORT = process.env.PORT || 5000; // Default port is 5000
const log = {
yellow: '\x1b[33m%s\x1b[0m', //yellow
cyan: '\x1b[36m%s\x1b[0m',//cyan
red: '\x1b[31m%s\x1b[0m', //red
green: '\x1b[32m%s\x1b[0m', //green
black: '\x1b[30m%s\x1b[0m', //black
blue: '\x1b[34m%s\x1b[0m', //blue
gray: '\x1b[90m%s\x1b[0m' //gray
}
// Create a connection pool
const pool = mysql.createPool({
host: config.host,
user: config.user,
password: config.password,
database: config.database,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
const app = express();
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.use(session({
secret: config.secret,
resave: true,
saveUninitialized: true
}));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, 'static')));
app.get('/', function(request, response) {
if (request.session.loggedin) {
// Output username
// response.send('Welcome back, ' + request.session.username + '!');
console.log(request.session.username , 'open main page');
// Render home page with username
response.render('home', { username: request.session.username });
} else {
// Not logged in
// response.send('Please login to view this page!');
response.redirect('/login');
}
});
app.get('/login', function(request, response) {
/// Render login template with any message from query parameters
console.log('Message:', request.query.message); // Log the message
response.render('login', { message: request.query.message || '' });
// response.sendFile(path.join(__dirname + '/login.html'));
});
app.post('/auth', async function(request, response) {
// Capture the input fields
const { login, password } = request.body;
// Ensure the input fields exist and are not empty
if (login && password) {
try {
// Get a connection from the pool
const connection = await pool.getConnection();
// Execute SQL query
// const [rows] = await connection.execute(
// 'SELECT * FROM accounts WHERE username = ? AND password = ?',
// [username, password]
// );
const [rows] = await connection.execute(
'SELECT * FROM accounts WHERE (username = ? OR email = ?) AND password = ?',
[login, login, password]
);
// console.log(rows);
// Release the connection back to the pool
connection.release();
// If the account exists
if (rows.length > 0) {
// Authenticate the user
request.session.loggedin = true;
request.session.username = rows[0].username;
// request.session.username = username;
// Redirect to home page
response.redirect('/');
} else {
response.redirect('/login?message=Incorrect Username and/or Password!');
}
} catch (error) {
console.error('Database query error:', error);
response.status(500).send('An error occurred while processing your request.');
}
} else {
// response.send('Please enter Username and Password!');
response.redirect('/login?message=Please enter Username and Password!');
}
});
// http://localhost:3000/home
app.get('/home', function(request, response) {
// If the user is loggedin
if (request.session.loggedin) {
// Output username
// response.send('Welcome back, ' + request.session.username + '!');
// Render home page with username
response.render('home', { username: request.session.username });
} else {
// Not logged in
// response.send('Please login to view this page!');
response.redirect('/login');
}
response.end();
});
// http://localhost:3000/logout
app.get('/logout', function(request, response) {
request.session.destroy((err) => {
if (err) {
return response.status(500).send('Failed to logout');
}
response.redirect('/');
});
});
app.listen(PORT, () => {
console.info(`Listening on http://0.0.0.0:${PORT}/`);
});

24
package.json Normal file
View File

@ -0,0 +1,24 @@
{
"name": "Terminal Diagnostic Helper",
"version": "1.0.0",
"description": "POS Terminal Diagnostic Helper by Ahmed Alomairi",
"main": "index.js",
"scripts": {
"test": "node main.js test",
"start": "node main.js",
"clean": "rm -f /app/service-upload/upload/* && node main.js clean",
"reset": "rm -f /app/service-upload/upload/* && node main.js",
"dev": "npm install nodemon --save-dev && node main.js development --port 3000"
},
"author": "Ahmed Alomairi",
"license": "ISC",
"dependencies": {
"ejs": "^3.1.10",
"express": "^4.18.3",
"express-session": "^1.18.0",
"mysql2": "^3.6.5"
},
"devDependencies": {
"nodemon": "^3.1.0"
}
}

111
public/index.html Normal file
View File

@ -0,0 +1,111 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Загрузчик файлов</title>
<link rel="apple-touch-icon" sizes="180x180" href="/images/favicon/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon/favicon-16x16.png">
<link rel="manifest" href="/images/favicon/site.webmanifest">
<link rel="mask-icon" href="/images/favicon/safari-pinned-tab.svg" color="#5bbad5">
<link rel="shortcut icon" href="/images/favicon/favicon.ico">
<meta name="msapplication-TileColor" content="#2b5797">
<meta name="msapplication-config" content="/images/favicon/browserconfig.xml">
<meta name="theme-color" content="#ffffff">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="nav-bar flex">
<div class="first-holder flex">
<!-- <h1 class="logo">EasyCode</h1> -->
<a class="logo"> <img src="/images/favicon/android-chrome-192x192.png" height="40"> СЕРВИС-ВОЛГА </a>
<a href="#" id="m-bar"><i class="fas fa-bars hm"></i></a>
</div>
<div id="menu-links" class="hidden">
<ul>
<li><a onClick="window.location.reload();" class=" "><i class="fa-solid fa-arrows-rotate"></i> Обновить страницу </a>
</li>
<!-- <li><a href="check-serials.html"> <i class="fa-solid fa-list-check"></i> Check Serials</a></li> -->
<!-- <li><a href="#"> <i class="fa-solid fa-upload"></i> Test</a></li> -->
<!-- <li><a id="showStorage" class=" show"><div id="history-lable"><i class="fa-solid fa-floppy-disk"></i> Show History</div></a></li> -->
</ul>
</div>
<!-- <a href="#" id="nav-btn" class="hidden">Signup</a> -->
<a id="showStorage" class="nav-btn hidden show">
<div id="history-lable"><i class="fa-solid fa-floppy-disk"></i>Последние файлы </div>
</a>
</div>
<h2 class="title">
Загрузчик инженерных файлов
<div class="tooltip">
<span> <img src="/images/info.svg" height="20" style="filter: invert(85%) sepia(89%) saturate(5847%) hue-rotate(343deg) brightness(103%) contrast(101%);" alt="" srcset=""></span> <!-- Insert symbol here (question mark) -->
<span class="tooltiptext">Загружаемый файл Excel инженера из папка "Перевод в платные" должен содержать заголовок <br> ( Модель, Сер.номер, Заявленная неисправность, Произведенная работа ) </span>
</div></h2>
<div id="dropZone" class="drop-zone">
<p>Перетащите файлы сюда или нажмите, чтобы выбрать</p>
</div>
<div class="upload-section">
<!-- <label for="fileInput" class="btn">
Select files
</label> -->
<form action="/upload" method="post" enctype="multipart/form-data">
<!-- <input type="file" name="uploaded" multiple id="fileInput"> -->
<input type="file" name="uploaded" multiple id="fileInput" style="display: none;">
<input type="submit" value="Загружать" class="btn" id="fileUpload">
</form>
<button id="getFileStateBtn" class="btn" disabled>Получить состояние файлов</button>
</div>
<div class="container">
<div id="selectedFiles"></div>
</div>
<!-- <div class="filesList">
<div class="selected">
<p>Selected files</p>
</div>
<div class="uploaded">
<p>Uploaded files</p>
<div id="result"></div>
</div>
<div class="state">
<p>Files state</p>
<div id="state"></div>
</div> -->
</div>
<script src="js.js"></script>
<footer>
<a> Upload XLSX v0.9 © 2024 Ал Омаири Ахмед </a>
</footer>
</body>
</html>

288
public/js.js Normal file
View File

@ -0,0 +1,288 @@
const fileInput = document.getElementById('fileInput');
const selectedFilesDiv = document.getElementById('selectedFiles');
let repeatedList = []
fileInput.addEventListener('change', function () {
populateFileTable(Array.from(fileInput.files));
console.log('fileInput.files on change', fileInput.files); getFileListFromServer(fileInput.files);
});
async function getFileListFromServer(fileInput) {
const fileUpload = document.getElementById('fileUpload');
fileUpload.style.color = 'white';
await fetch('/getfilenames')
.then(response => response.json())
.then(data => {
// Call populateFileTable() with the retrieved file list
compareFilelist(fileInput , data);
})
.catch(error => console.error('Error getting file list from server:', error));
}
function compareFilelist(fileInput , data) {
// console.log("resultes :");
console.log(fileInput);
// console.log(data); //array
Array.from(fileInput).forEach(selectedfile => {
console.log(selectedfile.name);
data.forEach(filename => {
if (filename === selectedfile.name){
const repeatedFileName = selectedfile.name
console.log( repeatedFileName, 'is repeated ');
repeatedList.push(repeatedFileName);
Array.from(selectedFilesDiv.children[0].rows).forEach((row, index) => {
const fileNameCell = row.cells[0];
const fileStateCell = row.cells[2];
const fileName = fileNameCell.textContent;
if (fileName == repeatedFileName) {
row.style.backgroundColor = 'rgb(254 255 82)';
fileStateCell.innerText = 'Repeated file!';
}
});
} // repeat function
});
});
}
async function handleFormSubmit(event) {
event.preventDefault();
const getFileStateBtn = document.getElementById('getFileStateBtn');
getFileStateBtn.disabled = false;
const fileUpload = document.getElementById('fileUpload');
fileUpload.style.color = 'grey';
const formData = new FormData(this);
// Get the file input element
const fileInput = document.getElementById('fileInput');
const fileList = fileInput.files;
// Filter out files based on repeatedList before upload
const filteredFiles = Array.from(fileList).filter(file => {
return !repeatedList.includes(file.name);
});
if (filteredFiles.length > 0) {
// Replace the original files with the modified file list
formData.delete('uploaded'); // Delete the existing files
filteredFiles.forEach(file => formData.append('uploaded', file)); // Add modified files
try {
const response = await fetch('/upload', {
method: 'POST',
body: formData
});
// Handle response as needed
const data = await response.json();
console.log(data);
const fileStates = data.states;
const filelist = data.files;
const fileErrors = data.errors;
const resultDiv = document.getElementById('result');
// createTable(resultDiv, data.files);
Array.from(selectedFilesDiv.children[0].rows).forEach((row, index) => {
const fileNameCell = row.cells[0];
const fileSizeCell = row.cells[1];
const fileStateCell = row.cells[2];
const fileName = fileNameCell.textContent;
const fileSize = fileSizeCell.textContent;
filelist.forEach(element => {
if (element.originalFilename === fileName) {
console.log('found file name similar');
console.log('element.size', element.size);
console.log('fileName', fileSize);
if (element.size == fileSize) {
row.style.fontWeight = 'bold';
row.style.backgroundImage = 'radial-gradient(farthest-corner at 50% 50%, skyblue, transparent)';
fileStateCell.innerText = 'uploaded';
} else {
row.style.backgroundColor = 'pink';
fileStateCell.innerText = 'error upload';
}
}
});
// const fileState = filelist.find(file => file.originalFilename === fileName);
// if (fileState) {
// fileSizeCell.textContent = fileState.size;
// if (fileState.size === 'Bad') {
// row.style.backgroundColor = 'red';
// } else {
// row.style.backgroundColor = 'transparent';
// }
// }
});
} catch (error) {
console.error('Error uploading files:', error);
// Handle errors during upload
alert('Error uploading files:', error);
}
} else {
console.log("No valid files selected for upload.");
alert('Допустимые файлы не выбраны или уже загружены.');
}
}
// Function to populate the file table with selected files
function populateFileTable(fileList) {
const table = document.createElement('table');
const headerRow = table.insertRow();
// headerRow.style.background = '#121212';
headerRow.style.background = ' linear-gradient(90deg, rgba(28,28,28,0.8379726890756303) 0%, rgba(24,23,23,0.9556197478991597) 51%, rgba(29,29,29,0.8715861344537815) 100%)';
headerRow.style.color = 'white';
const filenameHeader = headerRow.insertCell();
filenameHeader.textContent = 'Filename';
const sizeHeader = headerRow.insertCell();
sizeHeader.textContent = 'Size';
const stateHeader = headerRow.insertCell();
stateHeader.textContent = 'State';
fileList.forEach(fileData => {
const row = table.insertRow();
const filenameCell = row.insertCell();
if (fileData.originalFilename) {
filenameCell.textContent = fileData.originalFilename;
} else if (fileData.name) {
filenameCell.textContent = fileData.name;
}
const sizeCell = row.insertCell();
sizeCell.textContent = fileData.size;
const stateCell = row.insertCell();
stateCell.textContent = '---';
});
// Replace the existing content with the new table
selectedFilesDiv.innerHTML = '';
selectedFilesDiv.appendChild(table);
}
document.querySelector('form').addEventListener('submit', handleFormSubmit);
document.getElementById("getFileStateBtn").addEventListener("click", async function () {
const getFileStateBtn = document.getElementById('getFileStateBtn');
getFileStateBtn.disabled = true; // Disable the button
const fileUpload = document.getElementById('fileUpload');
fileUpload.style.color = 'white';
const response = await fetch('/getState');
const data = await response.json();
console.log(data);
// const stateDiv = document.getElementById('state');
// createTable(stateDiv, data.states);
const fileStates = data.states;
const fileErrors = data.errors;
// const resultDiv = document.getElementById('result');
// createTable(resultDiv, data.files);
Array.from(selectedFilesDiv.children[0].rows).forEach((row, index) => {
const fileNameCell = row.cells[0];
const fileSizeCell = row.cells[1];
const fileStateCell = row.cells[2];
const fileName = fileNameCell.textContent;
const fileState = fileStates.find(file => file.name === fileName);
if (fileState) {
fileStateCell.innerText = fileState.size;
if (fileState.size === 'Bad') {
row.style.backgroundImage = 'radial-gradient(farthest-corner at 50% 50%, orangered, transparent)';
} else {
row.style.backgroundImage = 'radial-gradient(farthest-corner at 50% 50%, lightgreen, transparent)';
}
}
});
});
const dropZone = document.getElementById('dropZone');
// Prevent default behavior for drag events
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, preventDefault, false);
});
function preventDefault(event) {
event.preventDefault();
event.stopPropagation();
}
// Handle file drop event
dropZone.addEventListener('drop', handleDrop, false);
function handleDrop(event) {
event.preventDefault();
event.stopPropagation();
const fileList = event.dataTransfer.files;
// const repeatedList = ['avoid_uploading_this_file.txt', 'another_filename_to_avoid.txt']; // Example repeatedList
// Filter out files based on repeatedList before upload
const filteredFiles = Array.from(fileList).filter(file => {
return !repeatedList.includes(file.name);
});
// Replace the original files with the modified file list
const formData = new FormData();
filteredFiles.forEach(file => formData.append('uploaded', file)); // Add modified files
// Update the file input field with dropped files
const fileInput = document.getElementById('fileInput');
fileInput.files = fileList;
// Submit the form or call handleFormSubmit function here with formData
populateFileTable(Array.from(fileInput.files));
console.log('dragdrop', fileInput.files);
getFileListFromServer(fileInput.files);
}
// Allow users to trigger file selection by clicking the drop zone
dropZone.addEventListener('click', () => {
const fileInput = document.getElementById('fileInput');
fileInput.click();
});

320
public/style.css Normal file
View File

@ -0,0 +1,320 @@
body {
background-color: #262626;
}
/* .title {
color: #6dabf1;
text-align: center;
} */
.filesList {
display: flex;
gap: 10px;
justify-content: center;
}
table {
display: table;
width: 68vw;
max-width: 1140px;
border-collapse: separate;
box-sizing: border-box;
text-indent: initial;
/* border-spacing: 2px; */
border-spacing: initial;
/* border-color: gray; */
}
td {
padding: 10px;
border-bottom: solid;
/* border-style: solid; */
}
td:first-child{
border-top: solid;
border-top-style: none !important;
border-top-left-radius: 15px;
}
td:last-child{
border-top: solid;
border-top-style: none !important;
border-top-right-radius: 15px;
}
tr:last-child td {
border: none;
}
.container {
display: flex;
margin: 10px;
justify-content: center;
}
#selectedFiles {
text-align: -webkit-center;
max-width: 1140px;
background-color: lavender;
border-radius: 20px;
/* padding-bottom: 10px; */
border-style: outset;
}
body {
/* color: #fff; */
font-family: 'Rubik', sans-serif;
/* margin:0; */
max-width: 1140px;
margin: 0 auto;
}
.logo {
display: flex;
align-items: center;
}
.flex {
display: flex;
justify-content: space-between;
align-items: center;
}
.nav-bar {
padding: 3px 10px 3px 20px;
background-color: rgb(0, 0, 0);
}
.nav-bar a {
color: #fff;
cursor: pointer;
}
.nav-bar .hm {
font-size: 20px;
}
#m-bar {
display: none;
font-size: 20px;
}
#menu-links ul {
margin: 0;
padding: 0;
}
#menu-links ul li {
display: inline-block;
margin: 0 35px;
list-style-type: none;
}
#menu-links a {
text-decoration: none;
font-weight: 500;
font-size: 15px;
text-transform: uppercase;
}
.nav-btn {
padding: 3px 15px;
background-color: #868686;
text-decoration: none;
color: black;
border-radius: 35px;
}
.nav-btn:hover {
background-color: #6791e0 !important;
}
.active {
color: #2d6cdf !important;
}
#menu-links a:hover {
color: #6dabf1 !important;
}
@media only screen and (max-width: 900px) {
#btn {
display: none;
}
}
@media only screen and (max-width: 880px) {
.nav-bar {
display: block;
text-align: center;
background-color: rgba(0, 0, 0, .4);
}
#menu-links ul li {
display: block;
margin: 25px 0;
}
#btn {
display: block;
}
#m-bar {
display: block;
}
.hidden {
display: none !important;
}
.not-hidden {
display: block !important;
}
}
.bg-tarakan {
display: none;
position: absolute;
max-width: 1140px;
width: -webkit-fill-available;
}
.show-tarakan {
display: block;
}
.control {
display: flex;
gap: 20px;
margin: auto;
text-align-last: center;
justify-content: center;
}
/* #getFileStateBtn {
padding: 10px;
} */
.btn {
padding: 12px;
border-radius: 10px;
color: #f5f5f5;
/* background-color: #2d6cdf; */
background: linear-gradient(40deg, #000000, #698ed1);
font-size: 16px;
cursor: pointer;
align-self: center;
box-shadow: 0 4px 7px rgb(99 139 255 / 40%);
border-style: hidden;
}
.upload-section {
display: flex;
gap: 30px;
align-content: center;
justify-content: center;
}
#fileInput {
opacity: 0;
width: 0.1px;
height: 0.1px;
position: absolute;
}
.upload-section input[type=submit] {
/* padding: 12px 30px; */
border: none;
/* background-color: #333333; */
/* color: #ffffff; */
font-size: 16px;
}
.btn:hover ,
.btn:focus {
transform: scale(1.09);
}
form {
/* width: 50%; */
/* margin: auto; */
/* background-color: #f5f5f5; */
/* padding: 30px; */
/* font-size: 20px; */
/* padding: 10px; */
/* border-radius: 10px; */
/* color: #f5f5f5; */
/* background-color: #2d6cdf; */
}
#dropZone {
background: repeating-linear-gradient(45deg, black, transparent 100px);
padding: 30px;
text-align: center;
margin-bottom: 10px;
color: white;
}
/* Add a style for the disabled button */
#getFileStateBtn[disabled] {
color: #ccc; /* Grey text color */
cursor: not-allowed; /* Change cursor to 'not-allowed' */
}
.title {
color: #6dabf1;
display: flex;
align-items: center;
justify-content: center;
gap: 5px;
}
.tooltip {
position: relative;
display: inline-block;
cursor: help; /* Change cursor to pointer on hover */
}
.tooltip .tooltiptext {
visibility: hidden;
width: 327px;
background-color: #333;
color: #fff;
text-align: center;
border-radius: 9px;
padding: 5px;
position: absolute;
z-index: 1;
bottom: -87px;
/* left: 50%; */
margin-left: -60px;
opacity: 0;
transition: opacity 0.3s;
font-size: 16px;
}
.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
}
footer {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
padding-top: 5px;
padding-bottom: 5px;
display: flex;
justify-content: center;
background-color: #000000;
color: lightgray;
font-family: sans-serif;
text-decoration: none !important;
}

195
static/login-style.css Normal file
View File

@ -0,0 +1,195 @@
@import url('https://fonts.googleapis.com/css?family=Raleway:400,700');
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: Raleway, sans-serif;
}
body {
background: linear-gradient(90deg, #C7C5F4, #776BCC);
overflow: hidden;
}
.container {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
}
.screen {
background: linear-gradient(90deg, #5D54A4, #7C78B8);
position: relative;
height: 600px;
width: 360px;
box-shadow: 0px 0px 24px #5C5696;
}
.screen__content {
z-index: 1;
position: relative;
height: 100%;
}
.screen__background {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 0;
-webkit-clip-path: inset(0 0 0 0);
clip-path: inset(0 0 0 0);
}
.screen__background__shape {
transform: rotate(45deg);
position: absolute;
}
.screen__background__shape1 {
height: 520px;
width: 520px;
background: #FFF;
top: -50px;
right: 120px;
border-radius: 0 72px 0 0;
}
.screen__background__shape2 {
height: 220px;
width: 220px;
background: #6C63AC;
top: -172px;
right: 0;
border-radius: 32px;
}
.screen__background__shape3 {
height: 540px;
width: 190px;
background: linear-gradient(270deg, #5D54A4, #6A679E);
top: -24px;
right: 0;
border-radius: 32px;
}
.screen__background__shape4 {
height: 400px;
width: 200px;
background: #7E7BB9;
top: 420px;
right: 50px;
border-radius: 60px;
}
.login {
width: 360px;
padding: 30px;
padding-top: 64px;
}
.login__field {
padding: 20px 0px;
position: relative;
}
.login__icon {
position: absolute;
top: 30px;
color: #7875B5;
}
.login__input {
border: none;
border-bottom: 2px solid #D1D1D4;
background: none;
padding: 10px;
padding-left: 24px;
font-weight: 700;
width: 75%;
transition: .2s;
}
.login__input:active,
.login__input:focus,
.login__input:hover {
outline: none;
border-bottom-color: #6A679E;
}
.login__submit {
background: #fff;
font-size: 14px;
margin-top: 30px;
padding: 16px 20px;
border-radius: 26px;
border: 1px solid #D4D3E8;
text-transform: uppercase;
font-weight: 700;
display: flex;
align-items: center;
width: 100%;
color: #4C489D;
box-shadow: 0px 2px 2px #5C5696;
cursor: pointer;
transition: .2s;
}
.login__submit:active,
.login__submit:focus,
.login__submit:hover {
border-color: #6A679E;
outline: none;
}
.button__icon {
font-size: 24px;
margin-left: auto;
color: #7875B5;
}
.social-login {
position: absolute;
height: 140px;
width: 160px;
text-align: center;
bottom: 0px;
right: 0px;
color: #fff;
}
.social-icons {
display: flex;
align-items: center;
justify-content: center;
}
.social-login__icon {
padding: 20px 10px;
color: #fff;
text-decoration: none;
text-shadow: 0px 0px 8px #7875B5;
}
.social-login__icon:hover {
transform: scale(1.5);
}
.login-title{
font-size: large;
padding-left: 30px;
padding-top: 30px;
}
.error-message{
font-size: small;
/* text-align: center; */
color: coral;
font-weight: bold;
}
.logo{
width: 64px;
}

BIN
static/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

71
static/styles.css Normal file
View File

@ -0,0 +1,71 @@
body {
font-family: Arial, sans-serif;
}
nav ul {
list-style-type: none;
padding: 0;
}
nav ul li {
display: inline;
margin-right: 10px;
}
* {
box-sizing: border-box;
font-family: -apple-system, BlinkMacSystemFont, "segoe ui", roboto, oxygen, ubuntu, cantarell, "fira sans", "droid sans", "helvetica neue", Arial, sans-serif;
font-size: 16px;
}
body {
background-color: #435165;
}
.login {
width: 400px;
background-color: #ffffff;
box-shadow: 0 0 9px 0 rgba(0, 0, 0, 0.3);
margin: 100px auto;
}
.login h1 {
text-align: center;
color: #5b6574;
font-size: 24px;
padding: 20px 0 20px 0;
border-bottom: 1px solid #dee0e4;
}
.login form {
display: flex;
flex-wrap: wrap;
justify-content: center;
padding-top: 20px;
}
.login form label {
display: flex;
justify-content: center;
align-items: center;
width: 50px;
height: 50px;
background-color: #3274d6;
color: #ffffff;
}
.login form input[type="password"], .login form input[type="text"] {
width: 310px;
height: 50px;
border: 1px solid #dee0e4;
margin-bottom: 20px;
padding: 0 15px;
}
.login form input[type="submit"] {
width: 100%;
padding: 15px;
margin-top: 20px;
background-color: #3274d6;
border: 0;
cursor: pointer;
font-weight: bold;
color: #ffffff;
transition: background-color 0.2s;
}
.login form input[type="submit"]:hover {
background-color: #2868c7;
transition: background-color 0.2s;
}

21
views/home.ejs Normal file
View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home</title>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<nav>
<ul>
<li><a href="/home">Home</a></li>
<li><a href="/logout">Logout</a></li>
</ul>
<div>
Welcome, <%= username %>!
</div>
</nav>
<h1>Welcome to the Home Page!</h1>
</body>
</html>

67
views/login.ejs Normal file
View File

@ -0,0 +1,67 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
<link rel="stylesheet" href="/login-style.css">
</head>
<body>
<div class="container">
<div class="screen">
<div class="screen__content">
<div class="login-title">
<h3>Terminal Diagnostic Helper</h2>
<span>v1.0.0</span>
<!-- <p class="login-title"> <br> </p> -->
</div>
<form class="login" action="/auth" method="post">
<% if (message) { %>
<div class="error-message"><%= message %></div>
<% } %>
<div class="login__field">
<i class="login__icon fas fa-user"></i>
<input type="text" class="login__input" id="login" name="login" placeholder="User name / Email">
</div>
<div class="login__field">
<i class="login__icon fas fa-lock"></i>
<input type="password" class="login__input" id="password" name="password" placeholder="Password">
</div>
<input class="button login__submit" type="submit" value="Login">
</form>
<div class="social-login">
<img class="logo" src="/logo.png" alt="" sizes="20px" >
<h3>SERVICE VOLGA</h3>
<div class="social-icons">
<a href="#" class="social-login__icon fab fa-instagram"></a>
<a href="#" class="social-login__icon fab fa-facebook"></a>
<a href="#" class="social-login__icon fab fa-twitter"></a>
</div>
</div>
</div>
<div class="screen__background">
<span class="screen__background__shape screen__background__shape4"></span>
<span class="screen__background__shape screen__background__shape3"></span>
<span class="screen__background__shape screen__background__shape2"></span>
<span class="screen__background__shape screen__background__shape1"></span>
</div>
<p> © 2024 Ал Омаири Ахмед </p>
</div>
</div>
</body>
</html>