Added background animation for homepage and similar other pages, started making body validation schemas on backend and removed delay when searching
This commit is contained in:
parent
ca96f57fb8
commit
6d48a10c1d
|
@ -14,6 +14,7 @@
|
|||
"packageManager": "pnpm@10.10.0",
|
||||
"dependencies": {
|
||||
"ajv": "^8.17.1",
|
||||
"ajv-formats": "^3.0.1",
|
||||
"bcrypt": "^5.1.1",
|
||||
"better-sqlite3": "^11.10.0",
|
||||
"cors": "^2.8.5",
|
||||
|
|
|
@ -11,6 +11,9 @@ importers:
|
|||
ajv:
|
||||
specifier: ^8.17.1
|
||||
version: 8.17.1
|
||||
ajv-formats:
|
||||
specifier: ^3.0.1
|
||||
version: 3.0.1(ajv@8.17.1)
|
||||
bcrypt:
|
||||
specifier: ^5.1.1
|
||||
version: 5.1.1
|
||||
|
@ -98,6 +101,14 @@ packages:
|
|||
resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
ajv-formats@3.0.1:
|
||||
resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==}
|
||||
peerDependencies:
|
||||
ajv: ^8.0.0
|
||||
peerDependenciesMeta:
|
||||
ajv:
|
||||
optional: true
|
||||
|
||||
ajv@8.17.1:
|
||||
resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
|
||||
|
||||
|
@ -1000,6 +1011,10 @@ snapshots:
|
|||
|
||||
agent-base@7.1.3: {}
|
||||
|
||||
ajv-formats@3.0.1(ajv@8.17.1):
|
||||
optionalDependencies:
|
||||
ajv: 8.17.1
|
||||
|
||||
ajv@8.17.1:
|
||||
dependencies:
|
||||
fast-deep-equal: 3.1.3
|
||||
|
|
|
@ -10,7 +10,7 @@ async function getAllUsers() {
|
|||
}
|
||||
|
||||
async function getUserByName(name) {
|
||||
return await db.query("SELECT username, display_name, profile_picture, role FROM Users WHERE username = ?;", [name]);
|
||||
return await db.query("SELECT username, display_name, email, profile_picture, role FROM Users WHERE username = ?;", [name]);
|
||||
}
|
||||
|
||||
async function getUserByEmail(email) {
|
||||
|
@ -25,10 +25,15 @@ async function getUserPassword(name) {
|
|||
return await db.query("SELECT username, password FROM Users WHERE username = ?;", [name]);
|
||||
}
|
||||
|
||||
//TODO test
|
||||
async function exists(name) {
|
||||
return await db.exists("Users", "username", name);
|
||||
}
|
||||
|
||||
async function existsEmail(email) {
|
||||
return await db.exists("Users", "email", email);
|
||||
}
|
||||
|
||||
|
||||
// --- Create ---
|
||||
|
||||
|
@ -122,4 +127,4 @@ module.exports = { getAllUsers, getUserByName, getUserByEmail, getFullUserInfos,
|
|||
createUser, addFavoriteMods,
|
||||
updateUser,
|
||||
deleteUser, deleteFavoriteMods,
|
||||
exists }
|
||||
exists, existsEmail }
|
|
@ -1,5 +1,6 @@
|
|||
const Ajv = require("ajv");
|
||||
const ajv = new Ajv();
|
||||
const addFormats = require("ajv-formats")
|
||||
const ajv = new Ajv({formats: {email: true}});
|
||||
|
||||
// --- Schemas ---
|
||||
//TODO
|
||||
|
@ -7,14 +8,17 @@ const ajv = new Ajv();
|
|||
const newUserSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
email: { type: 'string', format: 'email' },
|
||||
name: { type: 'string' },
|
||||
password: { type: 'string', minLength: 3, maxLength: 30 },
|
||||
username: { type: 'string' }, //TODO
|
||||
display_name: { type: 'string'},
|
||||
email: { type: 'string', format: 'email' }, //TODO
|
||||
password: { type: 'string', minLength: 6, maxLength: 255 },
|
||||
profile_picture: {type: 'string'} //TODO
|
||||
},
|
||||
required: ['name', 'email', 'password'],
|
||||
additionalProperties: false
|
||||
};
|
||||
|
||||
addFormats(ajv, ['email']);
|
||||
const validateNewUserData = ajv.compile(newUserSchema);
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const model = require("../models/user");
|
||||
const AppError = require("../utils/appError");
|
||||
const cryptoUtils = require("../utils/crypto");
|
||||
const { validateUserData } = require("../utils/validate_legacy");
|
||||
const { validateNewUserData} = require("../schemas/user");
|
||||
const { sanitizeUserData } = require("../utils/sanitize");
|
||||
|
||||
async function getAllUsers() {
|
||||
|
@ -10,22 +10,43 @@ async function getAllUsers() {
|
|||
|
||||
async function getUserByName(name) {
|
||||
const res = await model.getUserByName(name);
|
||||
if (res.length == 0) {
|
||||
throw new AppError(404, "No user with this name", "Not found");
|
||||
}
|
||||
return res[0];
|
||||
}
|
||||
|
||||
async function createUser(user_data) {
|
||||
|
||||
// Check body validity
|
||||
// TODO
|
||||
try {
|
||||
validateNewUserData(user_data);
|
||||
} catch (err) {
|
||||
throw new AppError(400, "Invalid fields", "Bad request");
|
||||
}
|
||||
|
||||
// Sanitize
|
||||
// TODO
|
||||
|
||||
// Gather data
|
||||
const { username, email, password, display_name, profile_picture, settings } = user_data
|
||||
const password_hash = await cryptoUtils.hashPassword(password);
|
||||
// Generate data
|
||||
|
||||
await model.createUser(username, email, password_hash, display_name, null, null);
|
||||
const { username, email, password, display_name, profile_picture, settings } = user_data
|
||||
|
||||
const password_hash = cryptoUtils.hashPassword(password);
|
||||
|
||||
if (await model.exists(username) ) {
|
||||
throw new AppError(403, "A user with this username already exists", "Already exists");
|
||||
}
|
||||
if (await model.existsEmail(email)) {
|
||||
throw new AppError(403, "A user with this email already exists", "Already exists");
|
||||
}
|
||||
|
||||
if (!display_name) {
|
||||
display_name = username;
|
||||
}
|
||||
|
||||
// Write changes
|
||||
await model.createUser(username, email, await password_hash, display_name, null, null);
|
||||
return model.getUserByName(username);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,10 +9,11 @@ import SearchIcon from '../../assets/search.svg'
|
|||
import styles from './search.module.css'; // Optional: CSS Modules
|
||||
|
||||
|
||||
function SearchBar({ onSearch }) {
|
||||
function SearchBar({ onSearch, timeout }) {
|
||||
|
||||
const [search_input, setSearchInput] = useState('');
|
||||
const timeout_id = useRef(null);
|
||||
const timeout_id = useRef(null);
|
||||
timeout = timeout | 0;
|
||||
|
||||
const handleInputChange = (event) => {
|
||||
|
||||
|
@ -25,7 +26,7 @@ function SearchBar({ onSearch }) {
|
|||
|
||||
timeout_id.current = setTimeout(() => {
|
||||
onSearch(new_search_input);
|
||||
}, 500);
|
||||
}, timeout);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -1,10 +1,35 @@
|
|||
.halo {
|
||||
position: fixed;
|
||||
/* position: fixed; */
|
||||
position: relative;
|
||||
z-index: -1;
|
||||
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
background: radial-gradient(circle at 50% 200%,#353be5 0%, #353be5 45%, #00000000 80%);
|
||||
}
|
||||
|
||||
.halo::before,
|
||||
.halo::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: bottom;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.halo::before {
|
||||
background: radial-gradient(circle at 60% 200%,#353be5 0%, #353be5 45%, #00000000 85%);
|
||||
opacity: 1;
|
||||
animation: haloBlue 10s infinite alternate;
|
||||
}
|
||||
|
||||
.halo::after {
|
||||
background: radial-gradient(circle at 0% 210%,#353be5 10%, #4935e5 45%, #00000000 80%);
|
||||
opacity: 0;
|
||||
animation: haloPurple 7s infinite alternate;
|
||||
}
|
||||
|
||||
.background {
|
||||
|
@ -86,4 +111,37 @@
|
|||
font-size: 1.5em;
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Animations ---------------- */
|
||||
|
||||
@keyframes haloBlue {
|
||||
0% {
|
||||
opacity: 0;
|
||||
/* background-size: 50% 50%; */
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
/* background-size: 150% 150%; */
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
/* background-size: 50% 50%; */
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes haloPurple {
|
||||
0% {
|
||||
opacity: 1;
|
||||
/* background-size: 100% 50%; */
|
||||
}
|
||||
50% {
|
||||
opacity: 0;
|
||||
/* background-size: 100% 100%; */
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
/* background-size: 100% 50%; */
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue