Add common service and base class

This commit is contained in:
2023-09-27 15:48:51 +07:00
parent 40d9f37f1b
commit b48089ffe4
9 changed files with 422 additions and 2 deletions
-1
View File
@@ -1 +0,0 @@
typescript-training
+1 -1
View File
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
@@ -0,0 +1,28 @@
export const DATABASE_URL =
'https://javascript-training-81f7a-default-rtdb.asia-southeast1.firebasedatabase.app';
export const TIME_OUT_SEC = 3;
export enum BTN_CONTENT {
GOT_IT = 'Got it!',
OK = 'Ok',
}
export const LOCAL_STORAGE = {
ACCESS_TOKEN: 'accessToken',
};
export enum TYPE_TOAST {
success = 'success',
error = 'error',
}
export enum MARK_ICON {
success = 'check',
error = 'error',
}
export const REGEX = {
PASSWORD:
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/,
EMAIL:
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|.(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
};
@@ -0,0 +1,31 @@
export const PASSWORD_NOT_MATCH = 'Password not match!';
export const PASSWORD_NOT_STRONG =
'Password must at least one uppercase, one lowercase letter, one number and one special character!';
export const ERROR_MESSAGE_DEFAULT = ['Something went wrong!'];
export const TIME_OUT_ERROR = 'Connection time out! Please try again!';
export const ERROR_CREDENTIAL = {
title: 'Error Credential',
message: 'Email or password not match! Please try again!',
};
export const DEFAULT_TITLE_ERROR_TOAST = 'Error';
export const USER_EXIST_ERROR = 'User is exists! Please try another email!';
export const ADD_WALLET_SUCCESS = 'Add wallet success!';
export const DEFAULT_MESSAGE = 'Press OK to continue!';
export const ADD_TRANSACTION_SUCCESS = 'Add success!';
export const UPDATE_TRANSACTION_SUCCESS = 'Update success!';
export const REGISTER_SUCCESS = 'Register Success';
export const REQUIRED_MESSAGE = (field) => `The ${field} is required!`;
export const INVALID_EMAIL_FORMAT = `The email is not correct!`;
@@ -0,0 +1,69 @@
import * as MESSAGE from '../constants/message';
import { TIME_OUT_SEC, REGEX } from '../constants/config';
import FirebaseService from '../services/firebaseService';
/**
* Validate password
* @param {string} password Password input
* @returns {boolean} Return true if validate password success, otherwise return false
*/
export const isValidPassword = (password: string): boolean => {
return REGEX.PASSWORD.test(password);
};
export const isValidateEmail = (email: string): RegExpMatchArray | null => {
return String(email).toLowerCase().match(REGEX.EMAIL);
};
export const compare2Password = (
password: string,
passwordConfirm: string,
): boolean => {
return password === passwordConfirm;
};
/**
* A waiting function with s second
* @param {number} s The time will be waiting
* @returns {Promise} A Promise will be only reject after s second
*/
export const timeout = (s: number): Promise<string> => {
return new Promise((_, reject) => {
setTimeout(() => {
FirebaseService.disconnect();
reject(MESSAGE.TIME_OUT_ERROR);
}, s * 1000);
});
};
export const createIdUser = (): number => {
return new Date().getTime();
};
/**
* A function waiting the action need to be perform and throw error after s second.
* @param {Function} action The action need to be perform.
* @returns { Object || Error } Return the any object from Firebase or Error
*/
export const timeOutConnect = async (
action: Promise<object>,
): Promise<string | object> => {
const result: object | string = await Promise.race([
action,
timeout(TIME_OUT_SEC),
]);
return result;
};
export const renderRequiredText = (field: string, element: Element) => {
const markup: string = `
<p class="error-text">${MESSAGE.REQUIRED_MESSAGE(field)}</p>
`;
element.insertAdjacentHTML('afterend', markup);
};
export const redirectToLoginPage = () => {
window.location.replace('/login');
};
@@ -0,0 +1,104 @@
import {
convertDataObjectToModel,
convertModelToDataObject,
timeOutConnect,
} from '../helpers/helpers';
import FirebaseService from './firebaseService';
export default class CommonService {
constructor() {
this.defaultPath = '/';
this.firebaseService = FirebaseService;
}
/**
* Connect to Firebase Databse
*/
connectToDb() {
this.firebaseService.reconnect();
}
async getDataFromProp(property, value, path = this.defaultPath) {
this.connectToDb();
const data = this.firebaseService.getDataFromProp(path, property, value);
const result = await timeOutConnect(data);
if (result.id && result.data) {
return convertDataObjectToModel(result);
}
return null;
}
/**
* Save data on database
* @param {*} data The data wants to save on database
* @param {string} path The path of database
*/
async save(model) {
this.connectToDb();
const results = convertModelToDataObject(model);
const saveData = this.firebaseService.save(
results.data,
this.defaultPath + results.id,
);
await timeOutConnect(saveData);
}
/**
*
* @param {string} id The string of data object
* @param {string} path The path of database
* @returns {Object || null} Return the object if has, otherwise return null
*/
async getDataFromId(id, path = this.defaultPath) {
this.connectToDb();
const result = await this.firebaseService.getDataFromId(id, path);
const data = await timeOutConnect(result);
if (data) return data;
return null;
}
async getAllDataFromPath(path = this.defaultPath) {
this.connectToDb();
const results = await timeOutConnect(
this.firebaseService.getAllDataFromPath(path),
);
if (results) {
// Convert format object
return results.map((data) => {
return convertDataObjectToModel(data);
});
}
return null;
}
async getListDataFromProp(property, value, path = this.defaultPath) {
this.connectToDb();
const results = await timeOutConnect(
this.firebaseService.getListDataFromProp(path, property, value),
);
if (results) {
// Convert format object
return results.map((data) => {
return convertDataObjectToModel(data);
});
}
return null;
}
async deleteData(id, path = this.defaultPath) {
this.connectToDb();
await timeOutConnect(this.firebaseService.delete(id, path));
}
}
@@ -0,0 +1,163 @@
import { FirebaseApp, initializeApp } from 'firebase/app';
import {
getDatabase,
ref,
set,
goOffline,
goOnline,
onValue,
remove,
Database,
} from 'firebase/database';
import { DATABASE_URL } from '../constants/config';
class FirebaseService {
private app: FirebaseApp;
private db: Database;
constructor() {
const firebaseConfig = {
databaseURL: DATABASE_URL,
};
this.app = initializeApp(firebaseConfig);
this.db = getDatabase(this.app);
}
/**
* Save data in database
* @param {Object} data The object need to save into database
* @param {string} path The path of database need to be save
* @returns {Promise} Return the resolves when write to database completed
*/
save(data: object, path: string): Promise<any> {
return set(ref(this.db, path), data);
}
delete(id: string, path: string) {
return remove(ref(this.db, path + id));
}
/**
* Disconnect to database
*/
disconnect() {
goOffline(this.db);
}
/**
* Reconnect to database
*/
reconnect() {
goOnline(this.db);
}
/**
* Find id of value by property in database
* @param {string} path The path of database to be found
* @param {string} property The property of the value need to be found
* @param {value} value The value to compare in database
* @returns {Promise} Return the resolve when find completed
*/
getDataFromProp(path: string, property: string, value: object): Promise<any> {
return new Promise((resolve) => {
onValue(
ref(this.db, path),
(snapshot) => {
let id: string | null = null;
let data: object | null = null;
// snapshot is a type of data by Firebase define
snapshot.forEach((childSnapshot) => {
const dataTemp = childSnapshot.val();
if (dataTemp[property] === value) {
id = childSnapshot.key;
data = dataTemp;
}
});
resolve({ id, data });
},
{
onlyOnce: true,
},
);
});
}
/**
* Get data object from Id
* @param {string} id The id of data object
* @param {string} path The path of data save in database
* @returns {Promise} Return new Promise
*/
getDataFromId(id: string, path: string): Promise<any> {
return new Promise((resolve) => {
onValue(
ref(this.db, path + id),
(snapshot) => {
resolve(snapshot.val());
},
{
onlyOnce: true,
},
);
});
}
getAllDataFromPath(path) {
return new Promise((resolve) => {
onValue(
ref(this.db, path),
(snapshot) => {
const listData: object[] = [];
// snapshot is a type of data by Firebase define
snapshot.forEach((childSnapshot) => {
let id: string | null = null;
let data: object | null = null;
id = childSnapshot.key;
data = childSnapshot.val();
listData.push({ id, data });
});
resolve(listData);
},
{
onlyOnce: true,
},
);
});
}
getListDataFromProp(path: string, property: string, value: object) {
return new Promise((resolve) => {
onValue(
ref(this.db, path),
(snapshot) => {
let id: string;
let data: object;
const listData: object[] = [];
// snapshot is a type of data by Firebase define
snapshot.forEach((childSnapshot) => {
const dataTemp = childSnapshot.val();
if (dataTemp[property] === value) {
id = childSnapshot.key;
data = dataTemp;
listData.push({ id, data });
}
});
resolve(listData);
},
{
onlyOnce: true,
},
);
});
}
}
export default new FirebaseService();
@@ -0,0 +1 @@
export default class Service {}
@@ -0,0 +1,25 @@
class LocalStorageService {
private localStorage: Storage;
constructor() {
this.localStorage = localStorage;
}
add(key: string, value: string) {
this.localStorage.setItem(key, value);
}
get(key: string) {
return this.localStorage.getItem(key);
}
remove(key: string) {
this.localStorage.removeItem(key);
}
clear() {
this.localStorage.clear();
}
}
export default new LocalStorageService();