Merge branche webapps dans dev
This commit is contained in:
parent
59bbfafbb7
commit
92c77c91e0
99
crates/sp_client/src/injecteurhtml.rs
Normal file
99
crates/sp_client/src/injecteurhtml.rs
Normal file
@ -0,0 +1,99 @@
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn inject_html_create_id() -> String {
|
||||
String::from("
|
||||
<div class='card'>
|
||||
<div class='side-by-side'>
|
||||
<h3>Create an Id</h3>
|
||||
<div><a href='#'>Processes</a></div>
|
||||
</div>
|
||||
<form id='form4nk' action='#'>
|
||||
<label for='password'>Password :</label>
|
||||
<input type='password' id='password' /><hr/>
|
||||
<input type='hidden' id='currentpage' value='creatid' />
|
||||
<select id='selectProcess' class='custom-select'></select><hr/>
|
||||
<div class='side-by-side'>
|
||||
<button type='submit' id='submitButton' class='bg-primary'>Create</button>
|
||||
<div>
|
||||
<a href='#' id='displayrecover'>Recover</a>
|
||||
</div>
|
||||
</div>
|
||||
</form><br/>
|
||||
<div id='passwordalert' class='passwordalert'></div>
|
||||
</div>
|
||||
")
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn inject_html_recover() -> String {
|
||||
String::from("
|
||||
<div class='card'>
|
||||
<div class='side-by-side'>
|
||||
<h3>Recover my Id</h3>
|
||||
<div><a href='#'>Processes</a></div>
|
||||
</div>
|
||||
<form id='form4nk' action='#'>
|
||||
<label for='password'>Password :</label>
|
||||
<input type='password' id='password' />
|
||||
<input type='hidden' id='currentpage' value='recover' />
|
||||
<select id='selectProcess' class='custom-select'></select><hr/>
|
||||
<div class='side-by-side'>
|
||||
<button type='submit' id='submitButton' class='recover bg-primary'>Recover</button>
|
||||
<div>
|
||||
<a href='#' id='displaycreateid'>Create an Id</a>
|
||||
</div>
|
||||
</div><hr/>
|
||||
<a href='#' id='displayrevoke' class='btn'>Revoke</a>
|
||||
</form><br/>
|
||||
<div id='passwordalert' class='passwordalert'></div>
|
||||
</div>
|
||||
")
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn inject_html_revokeimage() -> String {
|
||||
String::from("
|
||||
<div class='card2'>
|
||||
<form id='form4nk' action='#'>
|
||||
<input type='hidden' id='currentpage' value='revokeimage' />
|
||||
<button type='submit' id='submitButton'>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'>
|
||||
<path
|
||||
d='M246.6 9.4c-12.5-12.5-32.8-12.5-45.3 0l-128 128c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 109.3V320c0 17.7 14.3 32 32 32s32-14.3 32-32V109.3l73.4 73.4c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-128-128zM64 352c0-17.7-14.3-32-32-32s-32 14.3-32 32v64c0 53 43 96 96 96H352c53 0 96-43 96-96V352c0-17.7-14.3-32-32-32s-32 14.3-32 32v64c0 17.7-14.3 32-32 32H96c-17.7 0-32-14.3-32-32V352z'
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</form>
|
||||
<div class='image-container'>
|
||||
<label class='image-label bg-secondary'>Revoke image</label>
|
||||
<img src='assets/revoke.jpeg' alt='' />
|
||||
</div>
|
||||
</div>
|
||||
")
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn inject_html_revoke() -> String {
|
||||
String::from("
|
||||
<div class='card'>
|
||||
<div class='side-by-side'>
|
||||
<h3>Revoke an Id</h3>
|
||||
<div>
|
||||
<a href='#' id='displayrecover'>Recover</a>
|
||||
</div>
|
||||
</div>
|
||||
<form id='form4nk' action='#'>
|
||||
<label for='password'>Password :</label>
|
||||
<input type='password' id='password' />
|
||||
<hr/>
|
||||
<div class='image-container'>
|
||||
<label class='image-label'>Revoke image</label>
|
||||
<img src='assets/revoke.jpeg' alt='' />
|
||||
</div>
|
||||
<hr/>
|
||||
<button type='submit' id='submitButton' class='recover bg-primary'>Revoke</button>
|
||||
</form>
|
||||
</div>
|
||||
")
|
||||
}
|
@ -1 +1,3 @@
|
||||
pub mod api;
|
||||
mod injecteurhtml;
|
||||
mod process;
|
||||
|
10
crates/sp_client/src/process.rs
Normal file
10
crates/sp_client/src/process.rs
Normal file
@ -0,0 +1,10 @@
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn get_process() -> Vec<String> {
|
||||
let mut data_process: Vec<String> = Vec::new();
|
||||
data_process.push(String::from("process1"));
|
||||
data_process.push(String::from("process2"));
|
||||
data_process.push(String::from("process3"));
|
||||
data_process
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"copy-webpack-plugin": "^12.0.2",
|
||||
"html-webpack-plugin": "^5.6.0",
|
||||
"ts-loader": "^9.5.1",
|
||||
"typescript": "^5.3.3",
|
||||
|
BIN
src/assets/4nk_image.png
Normal file
BIN
src/assets/4nk_image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
BIN
src/assets/revoke.jpeg
Normal file
BIN
src/assets/revoke.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 408 KiB |
@ -9,15 +9,15 @@ class Database {
|
||||
options: {}
|
||||
},
|
||||
AnkUser: {
|
||||
name: "4nkUser",
|
||||
name: "user",
|
||||
options: {}
|
||||
},
|
||||
AnkSession: {
|
||||
name: "4nkSession",
|
||||
name: "session",
|
||||
options: {}
|
||||
},
|
||||
AnkProcess: {
|
||||
name: "4nkProcess",
|
||||
name: "process",
|
||||
options: {}
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,16 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="author" content="4NK">
|
||||
<meta name="description" content="4NK Web5 Platform">
|
||||
<meta name="keywords" content="4NK web5 bitcoin blockchain decentralize dapps relay contract">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>4NK Client</title>
|
||||
<link rel="stylesheet" href="style/4nk.css">
|
||||
<title>4NK Application</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="containerId" class="container">
|
||||
<!-- 4NK Web5 Solution -->
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
10
src/index.ts
10
src/index.ts
@ -4,10 +4,18 @@ import IndexedDB from './database'
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
try {
|
||||
const services = await Services.getInstance();
|
||||
const indexedDB = await IndexedDB.getInstance();
|
||||
|
||||
if ((await services.isNewUser())) {
|
||||
services.displayCreateId();
|
||||
}
|
||||
else {
|
||||
services.displayRecover()
|
||||
}
|
||||
|
||||
const indexedDB = await IndexedDB.getInstance();
|
||||
const db = indexedDB.getDb();
|
||||
await indexedDB.writeObject(db, indexedDB.getStoreList().SpClient, services.new_sp_client(), "default");
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
365
src/services.ts
365
src/services.ts
@ -1,8 +1,11 @@
|
||||
import IndexedDB from './database'
|
||||
import Processstore from './store/processstore';
|
||||
import Userstore from './store/userstore';
|
||||
|
||||
class Services {
|
||||
private static instance: Services;
|
||||
private sdkClient: any;
|
||||
private static CURRENT_PROCESS = "currentprocess";
|
||||
|
||||
// Private constructor to prevent direct instantiation from outside
|
||||
private constructor() {}
|
||||
@ -44,6 +47,368 @@ class Services {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public async isNewUser(): Promise<boolean> {
|
||||
let isNew = false;
|
||||
try {
|
||||
let listUserProcess = await Services.instance.getAllUserProces();
|
||||
if (listUserProcess.length == 0) {
|
||||
isNew = true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to retrieve isNewUser :", error);
|
||||
}
|
||||
return isNew;
|
||||
}
|
||||
|
||||
public async displayCreateId(): Promise<void> {
|
||||
Services.instance.injectHtml(Services.instance.get_html_create_id());
|
||||
Services.instance.attachSubmitListener("form4nk", Services.instance.createId);
|
||||
Services.instance.attachClickListener("displayrecover", Services.instance.displayRecover);
|
||||
Services.instance.displayProcess(await Services.instance.getAllProcesAvailable());
|
||||
}
|
||||
|
||||
public get_html_create_id(): string {
|
||||
return this.sdkClient.inject_html_create_id();
|
||||
}
|
||||
|
||||
public async createId(event: Event): Promise<void> {
|
||||
event.preventDefault();
|
||||
|
||||
const passwordElement = document.getElementById("password") as HTMLInputElement;
|
||||
const processElement = document.getElementById("selectProcess") as HTMLSelectElement;
|
||||
|
||||
if (!passwordElement || !processElement) {
|
||||
console.error("One or more elements not found");
|
||||
return;
|
||||
}
|
||||
|
||||
const password = passwordElement.value;
|
||||
const process = processElement.value;
|
||||
console.log("JS password: " + password + " process: " + process);
|
||||
// To comment if test
|
||||
if (!Services.instance.isPasswordValid(password)) return;
|
||||
|
||||
// TODO get secretpart1 from User object
|
||||
// const user = new this.sdkClient.User(password);
|
||||
let secretpart1 = "LKHGKJJJ3H";
|
||||
|
||||
try {
|
||||
let userstore = new Userstore;
|
||||
userstore.secretpart1 = secretpart1;
|
||||
userstore.process = process;
|
||||
const indexedDb = await IndexedDB.getInstance();
|
||||
const db = indexedDb.getDb();
|
||||
|
||||
await indexedDb.writeObject(db, indexedDb.getStoreList().AnkUser, userstore, process);
|
||||
console.log("JS Userstore added");
|
||||
|
||||
await indexedDb.writeObject(db, indexedDb.getStoreList().AnkSession, process, Services.CURRENT_PROCESS);
|
||||
console.log("JS Sessionstore added currentprocess");
|
||||
} catch (error) {
|
||||
console.error("Failed to write userstore object :", error);
|
||||
}
|
||||
|
||||
await Services.instance.displayRevokeImage();
|
||||
}
|
||||
|
||||
public async displayRecover(): Promise<void> {
|
||||
Services.instance.injectHtml(Services.instance.get_html_recover());
|
||||
Services.instance.attachSubmitListener("form4nk", Services.instance.recover);
|
||||
Services.instance.attachClickListener("displaycreateid", Services.instance.displayCreateId);
|
||||
Services.instance.attachClickListener("displayrevoke", Services.instance.displayRevoke);
|
||||
Services.instance.attachClickListener("submitButtonRevoke", Services.instance.revoke);
|
||||
Services.instance.displayProcess(await Services.instance.getAllUserProces());
|
||||
}
|
||||
|
||||
public get_html_recover(): string {
|
||||
return this.sdkClient.inject_html_recover();
|
||||
}
|
||||
|
||||
public async recover(event: Event) {
|
||||
event.preventDefault();
|
||||
console.log("JS recover submit ");
|
||||
|
||||
const passwordElement = document.getElementById("password") as HTMLInputElement;
|
||||
const processElement = document.getElementById("selectProcess") as HTMLSelectElement;
|
||||
|
||||
if (!passwordElement || !processElement) {
|
||||
console.error("One or more elements not found");
|
||||
return;
|
||||
}
|
||||
|
||||
const password = passwordElement.value;
|
||||
const process = processElement.value;
|
||||
console.log("JS password: " + password + " process: " + process);
|
||||
// To comment if test
|
||||
if (!Services.instance.isPasswordValid(password)) return;
|
||||
|
||||
// TODO
|
||||
alert("Recover submit to do ...");
|
||||
}
|
||||
|
||||
public async displayRevokeImage(): Promise<void> {
|
||||
const html = Services.instance.get_html_revokeimage();
|
||||
Services.instance.injectHtml(html);
|
||||
Services.instance.attachSubmitListener("form4nk", Services.instance.revokeimage);
|
||||
}
|
||||
|
||||
public get_html_revokeimage(): string {
|
||||
return this.sdkClient.inject_html_revokeimage();
|
||||
}
|
||||
|
||||
public async revokeimage(event: Event): Promise<void> {
|
||||
event.preventDefault();
|
||||
console.log("JS revokeimage submit ");
|
||||
// TODO
|
||||
alert("Revokeimage submit to do ..., next page Update an id ...");
|
||||
|
||||
await Services.instance.displayUpdateAnId();
|
||||
}
|
||||
|
||||
public async displayRevoke(): Promise<void> {
|
||||
const html = Services.instance.get_html_revoke();
|
||||
Services.instance.injectHtml(html);
|
||||
Services.instance.attachClickListener("displayrecover", Services.instance.displayRecover);
|
||||
Services.instance.attachSubmitListener("form4nk", Services.instance.revoke);
|
||||
}
|
||||
|
||||
public get_html_revoke(): string {
|
||||
return this.sdkClient.inject_html_revoke();
|
||||
}
|
||||
|
||||
public async revoke(event: Event): Promise<void> {
|
||||
event.preventDefault();
|
||||
console.log("JS revoke click ");
|
||||
// TODO
|
||||
alert("revoke click to do ...");
|
||||
}
|
||||
|
||||
public async displayUpdateAnId() {
|
||||
let currentProcess = await this.getCurrentProcess();
|
||||
|
||||
let body = "";
|
||||
let style = "";
|
||||
let script = "";
|
||||
let inputName = "";
|
||||
try {
|
||||
const indexedDB = await IndexedDB.getInstance();
|
||||
const db = indexedDB.getDb();
|
||||
try {
|
||||
let processObject = await indexedDB.getObject<Processstore>(db, indexedDB.getStoreList().AnkProcess, currentProcess);
|
||||
body = processObject.html;
|
||||
style = processObject.style;
|
||||
script = processObject.script;
|
||||
inputName = processObject.inputName;
|
||||
} catch (error) {
|
||||
console.log("JS Processstore not exist ");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to retrieve userstore object :", error);
|
||||
}
|
||||
|
||||
Services.instance.injectUpdateAnIdHtml(body, style, script, inputName);
|
||||
Services.instance.attachSubmitListener("form4nk", Services.instance.updateAnId);
|
||||
}
|
||||
|
||||
public injectUpdateAnIdHtml(bodyToInject: string, styleToInject: string, scriptToInject: string, inputName: string) {
|
||||
console.log("JS html : "+bodyToInject);
|
||||
const body = document.getElementsByTagName('body')[0];
|
||||
|
||||
if (!body) {
|
||||
console.error("No body tag");
|
||||
return;
|
||||
}
|
||||
body.innerHTML = styleToInject + bodyToInject;
|
||||
|
||||
const script = document.createElement("script");
|
||||
script.innerHTML = scriptToInject;
|
||||
document.body.appendChild(script);
|
||||
script.onload = () => {
|
||||
console.log('Script loaded successfuly');
|
||||
};
|
||||
script.onerror = () => {
|
||||
console.log('Error loading script');
|
||||
};
|
||||
}
|
||||
|
||||
public async updateAnId(event: Event): Promise<void> {
|
||||
event.preventDefault();
|
||||
|
||||
// TODO get values
|
||||
const firstNameElement = 'firstName';
|
||||
const lastNameElement = 'lastName';
|
||||
const firstName = document.getElementById(firstNameElement) as HTMLInputElement;
|
||||
const lastName = document.getElementById(lastNameElement) as HTMLInputElement;
|
||||
|
||||
console.log("JS updateAnId submit ");
|
||||
// TODO
|
||||
alert("updateAnId submit to do ... Name : "+firstName.value + " "+lastName.value);
|
||||
}
|
||||
|
||||
public displayProcess(processList: string[]): void {
|
||||
console.log("JS processList : "+processList);
|
||||
const selectProcess = document.getElementById("selectProcess");
|
||||
if (selectProcess) {
|
||||
processList.forEach((process) => {
|
||||
let child = new Option(process, process);
|
||||
if (!selectProcess.contains(child)) {
|
||||
selectProcess.appendChild(child);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public async getAllUserProces(): Promise<string[]> {
|
||||
let userProcessList: string[] = [];
|
||||
try {
|
||||
const indexedDB = await IndexedDB.getInstance();
|
||||
const db = indexedDB.getDb();
|
||||
let userListObject = await indexedDB.getAll<Userstore>(db, indexedDB.getStoreList().AnkUser);
|
||||
userListObject.forEach(async (userObject) => {
|
||||
const processName = userObject.process;
|
||||
userProcessList.push(processName);
|
||||
console.log("JS Userstore found");
|
||||
})
|
||||
} catch (error) {
|
||||
console.log("JS Userstore not found");
|
||||
}
|
||||
return userProcessList;
|
||||
}
|
||||
|
||||
public async getAllProcesAvailable(): Promise<string[]> {
|
||||
let userProcessList = await Services.instance.getAllUserProces();
|
||||
let processList = await Services.instance.getAllProces();
|
||||
let availableProcessList = processList.filter(x => !userProcessList.includes(x));
|
||||
return availableProcessList;
|
||||
}
|
||||
|
||||
public async getAllProces(): Promise<string[]> {
|
||||
// if indexedDB is empty, get list from wasm
|
||||
let processList: string[] = [];
|
||||
try {
|
||||
const indexedDB = await IndexedDB.getInstance();
|
||||
const db = indexedDB.getDb();
|
||||
let processListObject = await indexedDB.getAll<Processstore>(db, indexedDB.getStoreList().AnkProcess);
|
||||
processListObject.forEach(async (processObject) => {
|
||||
const processName = processObject.process;
|
||||
processList.push(processName);
|
||||
console.log("JS Processstore found");
|
||||
})
|
||||
} catch (error) {
|
||||
console.log("JS Processstore not found");
|
||||
}
|
||||
if (processList.length == 0) {
|
||||
processList = await this.addProcessStore();
|
||||
}
|
||||
return processList;
|
||||
}
|
||||
|
||||
public async addProcessStore(): Promise<string[]> {
|
||||
const processList = this.sdkClient.get_process()
|
||||
processList.forEach(async (process: string) => {
|
||||
// TODO process mock
|
||||
let processstore = new Processstore;
|
||||
processstore.process = process;
|
||||
const indexedDB = await IndexedDB.getInstance();
|
||||
const db = indexedDB.getDb();
|
||||
await indexedDB.writeObject(db, indexedDB.getStoreList().AnkProcess, processstore, process);
|
||||
console.log("JS Processstore mock added");
|
||||
})
|
||||
return processList;
|
||||
}
|
||||
|
||||
private async getSecretPart1(process: string): Promise<string> {
|
||||
let secretpart1 = "";
|
||||
try {
|
||||
const indexedDB = await IndexedDB.getInstance();
|
||||
const db = indexedDB.getDb();
|
||||
try {
|
||||
let userObject = await indexedDB.getObject<Userstore>(db, indexedDB.getStoreList().AnkUser, process);
|
||||
secretpart1 = userObject.secretpart1;
|
||||
console.log("JS Userstore exist secretpart1 : "+secretpart1);
|
||||
} catch (error) {
|
||||
console.log("JS Userstore not exist ");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to retrieve userstore object :", error);
|
||||
}
|
||||
console.log("JS secretpart1 : "+secretpart1);
|
||||
|
||||
return secretpart1;
|
||||
}
|
||||
|
||||
public attachClickListener(elementId: string, callback: (event: Event) => void): void {
|
||||
const element = document.getElementById(elementId);
|
||||
element?.removeEventListener("click", callback);
|
||||
element?.addEventListener("click", callback);
|
||||
}
|
||||
|
||||
public attachSubmitListener(elementId: string, callback: (event: Event) => void): void {
|
||||
const element = document.getElementById(elementId);
|
||||
element?.removeEventListener("submit", callback);
|
||||
element?.addEventListener("submit", callback);
|
||||
}
|
||||
|
||||
public injectHtml(html: string) {
|
||||
console.log("JS html : "+html);
|
||||
const container = document.getElementById('containerId');
|
||||
|
||||
if (!container) {
|
||||
console.error("No html container");
|
||||
return;
|
||||
}
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
public async getCurrentProcess(): Promise<string> {
|
||||
let currentProcess = "";
|
||||
try {
|
||||
const indexedDB = await IndexedDB.getInstance();
|
||||
const db = indexedDB.getDb();
|
||||
currentProcess = await indexedDB.getObject<string>(db, indexedDB.getStoreList().AnkSession, Services.CURRENT_PROCESS);
|
||||
} catch (error) {
|
||||
console.error("Failed to retrieve currentprocess object :", error);
|
||||
}
|
||||
return currentProcess;
|
||||
}
|
||||
|
||||
public isPasswordValid(password: string) {
|
||||
var alertElem = document.getElementById("passwordalert");
|
||||
var success = true;
|
||||
var strength = 0;
|
||||
if (password.match(/[a-z]+/)) {
|
||||
var strength = 0;
|
||||
strength += 1;
|
||||
}
|
||||
if (password.match(/[A-Z]+/)) {
|
||||
strength += 1;
|
||||
}
|
||||
if (password.match(/[0-9]+/)) {
|
||||
strength += 1;
|
||||
}
|
||||
if (password.match(/[$@#&!]+/)) {
|
||||
strength += 1;
|
||||
}
|
||||
if (alertElem !== null) {
|
||||
// TODO Passer à 18
|
||||
if (password.length < 4) {
|
||||
alertElem.innerHTML = "Password size is < 4";
|
||||
success = false;
|
||||
} else {
|
||||
if (password.length > 30) {
|
||||
alertElem.innerHTML = "Password size is > 30";
|
||||
success = false;
|
||||
} else {
|
||||
if (strength < 4) {
|
||||
alertElem.innerHTML = "Password need [a-z] [A-Z] [0-9]+ [$@#&!]+";
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
export default Services;
|
||||
|
237
src/store/processstore.ts
Normal file
237
src/store/processstore.ts
Normal file
@ -0,0 +1,237 @@
|
||||
class Processstore {
|
||||
process: string;
|
||||
html: string;
|
||||
style: string;
|
||||
script: string;
|
||||
inputName: string;
|
||||
createDate: Date;
|
||||
|
||||
constructor() {
|
||||
this.process = "";
|
||||
this.html = getMockHtml();
|
||||
this.style = getMockStyle();
|
||||
this.script = getMockScript();
|
||||
this.script = getMockScript();
|
||||
this.inputName = getMockinputName();
|
||||
this.createDate = new Date;
|
||||
}
|
||||
}
|
||||
|
||||
export default Processstore;
|
||||
|
||||
function getMockHtml(): string {
|
||||
let html: string = `
|
||||
<body>
|
||||
<div class='container'>
|
||||
<div>
|
||||
<h3>Update an Id</h3>
|
||||
</div>
|
||||
<hr />
|
||||
<form id='form4nk' action='#'>
|
||||
<label for='firstName'>First Name:</label>
|
||||
<input type='text' id='firstName' name='firstName' required />
|
||||
|
||||
<label for='lastName'>Last Name:</label>
|
||||
<input type='text' id='lastName' name='lastName' required />
|
||||
|
||||
<label for='Birthday'>Birthday:</label>
|
||||
<input type='date' id='Birthday' name='birthday' />
|
||||
|
||||
<label for='file'>File:</label>
|
||||
<input type='file' id='fileInput' name='file' />
|
||||
|
||||
<label>Third parties:</label>
|
||||
<div id='sp-address-block'>
|
||||
<div class='side-by-side'>
|
||||
<input
|
||||
type='text'
|
||||
name='sp-address'
|
||||
id='sp-address'
|
||||
placeholder='sp address'
|
||||
form='no-form'
|
||||
/>
|
||||
<button
|
||||
type='button'
|
||||
class='circle-btn bg-secondary'
|
||||
id='add-sp-address-btn'
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class='div-text-area'>
|
||||
<textarea
|
||||
name='bio'
|
||||
id=''
|
||||
cols='30'
|
||||
rows='10'
|
||||
placeholder='Bio'
|
||||
></textarea>
|
||||
</div>
|
||||
<button type='submit' class='bg-primary'>Update</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
return html;
|
||||
}
|
||||
|
||||
function getMockStyle(): string {
|
||||
let style: string = `
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
background-color: #f4f4f4;
|
||||
font-family: 'Arial', sans-serif;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 400px;
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
background-color: #ffffff;
|
||||
border-radius: 8px;
|
||||
text-align: left;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
form {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(1fr, 2fr);
|
||||
gap: 10px;
|
||||
max-width: 400px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.bg-primary {
|
||||
background-color: #1a61ed;
|
||||
}
|
||||
|
||||
.bg-primary:hover {
|
||||
background-color: #457be8;
|
||||
}
|
||||
|
||||
.bg-secondary {
|
||||
background-color: #2b81ed;
|
||||
}
|
||||
|
||||
.bg-secondary:hover {
|
||||
background-color: #5f9bff;
|
||||
}
|
||||
|
||||
label {
|
||||
text-align: left;
|
||||
padding-right: 10px;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
button {
|
||||
grid-column: span 2;
|
||||
display: inline-block;
|
||||
color: #fff;
|
||||
border: none;
|
||||
padding: 12px 17px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.div-text-area {
|
||||
grid-column: span 2;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.side-by-side {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.circle-btn {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 0px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#fileInput {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
padding-left: 0px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>`;
|
||||
return style;
|
||||
}
|
||||
|
||||
function getMockScript(): string {
|
||||
let script: string = `
|
||||
var addSpAddressBtn = document.getElementById('add-sp-address-btn');
|
||||
var removeSpAddressBtn = document.querySelectorAll('.minus-sp-address-btn');
|
||||
|
||||
addSpAddressBtn.addEventListener('click', function (event) {
|
||||
addDynamicField(this);
|
||||
});
|
||||
|
||||
function addDynamicField(element) {
|
||||
var addSpAddressBlock = document.getElementById('sp-address-block');
|
||||
var spAddress = addSpAddressBlock.querySelector('#sp-address').value;
|
||||
addSpAddressBlock.querySelector('#sp-address').value = '';
|
||||
spAddress = spAddress.trim();
|
||||
if (spAddress != '') {
|
||||
var sideBySideDiv = document.createElement('div');
|
||||
sideBySideDiv.className = 'side-by-side';
|
||||
|
||||
var inputElement = document.createElement('input');
|
||||
inputElement.type = 'text';
|
||||
inputElement.name = 'spAddresses[]';
|
||||
inputElement.setAttribute('form', 'no-form');
|
||||
inputElement.value = spAddress;
|
||||
inputElement.disabled = true;
|
||||
|
||||
var buttonElement = document.createElement('button');
|
||||
buttonElement.type = 'button';
|
||||
buttonElement.className =
|
||||
'circle-btn bg-secondary minus-sp-address-btn';
|
||||
buttonElement.innerHTML = '-';
|
||||
|
||||
buttonElement.addEventListener('click', function (event) {
|
||||
removeDynamicField(this.parentElement);
|
||||
});
|
||||
|
||||
sideBySideDiv.appendChild(inputElement);
|
||||
sideBySideDiv.appendChild(buttonElement);
|
||||
|
||||
addSpAddressBlock.appendChild(sideBySideDiv);
|
||||
}
|
||||
function removeDynamicField(element) {
|
||||
element.remove();
|
||||
}
|
||||
}
|
||||
`;
|
||||
return script;
|
||||
}
|
||||
|
||||
function getMockinputName(): string {
|
||||
return "firstName";
|
||||
}
|
15
src/store/userstore.ts
Normal file
15
src/store/userstore.ts
Normal file
@ -0,0 +1,15 @@
|
||||
class Userstore {
|
||||
process: string;
|
||||
secretpart1: string;
|
||||
password: string;
|
||||
createDate: Date;
|
||||
|
||||
constructor() {
|
||||
this.process = "";
|
||||
this.secretpart1 = "";
|
||||
this.password = "";
|
||||
this.createDate = new Date;
|
||||
}
|
||||
}
|
||||
|
||||
export default Userstore;
|
162
src/style/4nk.css
Normal file
162
src/style/4nk.css
Normal file
@ -0,0 +1,162 @@
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
background-color: #f4f4f4;
|
||||
font-family: 'Arial', sans-serif;
|
||||
}
|
||||
.container {
|
||||
text-align: center;
|
||||
}
|
||||
.card {
|
||||
max-width: 400px;
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
background-color: #ffffff;
|
||||
border-radius: 8px;
|
||||
text-align: left;
|
||||
overflow: hidden;
|
||||
}
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* flex-wrap: wrap; */
|
||||
}
|
||||
label {
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
hr {
|
||||
border: 0;
|
||||
height: 1px;
|
||||
background-color: #ddd;
|
||||
margin: 10px 0;
|
||||
}
|
||||
input, select {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
margin: 8px 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
select {
|
||||
padding: 10px;
|
||||
background-color: #f9f9f9;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
button {
|
||||
display: inline-block;
|
||||
background-color: #4caf50;
|
||||
color: #fff;
|
||||
border: none;
|
||||
padding: 12px 17px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
.side-by-side {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.side-by-side>* {
|
||||
display: inline-block;
|
||||
}
|
||||
button.recover {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
background-color: #4caf50;
|
||||
color: #fff;
|
||||
border: none;
|
||||
padding: 12px 17px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
button.recover:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
a.btn {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
background-color: #4caf50;
|
||||
color: #fff;
|
||||
border: none;
|
||||
padding: 12px 17px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
a.btn:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #78a6de;
|
||||
}
|
||||
.bg-secondary {
|
||||
background-color: #2b81ed;
|
||||
}
|
||||
.bg-primary {
|
||||
background-color: #1A61ED;
|
||||
}
|
||||
.bg-primary:hover {
|
||||
background-color: #457be8;
|
||||
}
|
||||
.card2 {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 400px;
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
background-color: #ffffff;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
.card2 button {
|
||||
max-width: 50px;
|
||||
width: 100%;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
.card2 svg {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
fill: #333;
|
||||
}
|
||||
.image-label {
|
||||
display: block;
|
||||
color: #fff;
|
||||
padding: 5px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.image-container {
|
||||
width: 400px;
|
||||
height: 300px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.image-container img {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center center;
|
||||
}
|
||||
.passwordalert {
|
||||
color: #FF0000;
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
const path = require('path');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
mode: 'development',
|
||||
@ -32,6 +33,12 @@ module.exports = {
|
||||
new HtmlWebpackPlugin({
|
||||
template: 'src/index.html'
|
||||
}),
|
||||
new CopyWebpackPlugin({
|
||||
patterns: [
|
||||
{ from: 'src/assets', to: './assets' },
|
||||
{ from: 'src/style', to: './style' }
|
||||
],
|
||||
}),
|
||||
],
|
||||
devServer: {
|
||||
static: './dist',
|
||||
|
Loading…
x
Reference in New Issue
Block a user