Built for Developers

DhiWise is a ProCode platform designed to dramatically accelerate development efficiency of your web and mobile applications while also delivering unprecedented levels of flexibility and quality in your source code.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
DhiWise GUI
icon
icon
icon
icon
icon
DhiWise GUI
logo
# NodeJS, Sequelize, Express Project in Clean-Code Architecture


**Supported version of nodejs-15.13.0**,
**Supported version of sequelize-6.6.5**

- This is a Web application, developed using MVC pattern with Node.js, ExpressJS, and Sequelize ORM. 
- Basic boilerplate for web applications, built on Express.js using the clean-code architecture
- A Sql database is used for data storage, with object modeling provided by Sequelize.
- Supported SQL Databases are - MSSQL, MySql, PostgreSQL 

## Initial
- Configure a basic server in app.js.
- Organize the routes with Express Router.
- Use the mainRoutes in app as middleware.
- Set a final use after the routes, to display a 404 message for the unhandled requests.
1. Install needed Node.js modules:
    ```$ npm install```
2. Add username, password in configuration file.
3. execute server:
    ```$ npm start```

## Default Folder structure:

--project_folder
    --config
    --constants
    --controllers
    --entity
    --helpers
    --jobs
    --logs
    --middleware
    --models
    --postman
    --public
    --routes
    --services
    --utils
    --validation
    --views
    --app.js
    --.env
    --.gitignore
    --.eslintrc.js
## app.js
- Entry point of application.

## config
- Passport strategy for all platforms.
- Based on Auth Model - authentication files has been generated.
- Used .env file and configure the db connection string and port to use in the project.

## constants
- Contains files of constants

## controller
- Includes controller files per model
- Controllers are separated per Platform

        -controller
                -admin
                    -model
                        -index.js
                        -controller.js
                -device
                -model
                        -index.js
                        -controller.js
                -desktop
                -model
                        -index.js
                        -controller.js
                -client
                -model
                        -index.js
                        -controller.js

## entity
- These are the business objects of your application. These should not be affected by any change external to them, and these should be the most stable code within your application. These can be POJOs, objects with methods, or even data structures.

## helper
- a helper function is used to assist in providing some functionality, which isn't the main goal of the application or class in which it is used.

## jobs
- Cron jobs related Files and configuration

## logs
- Log file

## middleware
- User authentication Middleware based on Roles and permission for Routes' access
- Custom Policy files

## models
- Sequelize Models, as per user defined schema 

## postman
- Postman collection File for Platform based APIs that are generated.
- Import this JSON in Postman to test the APIs.

## public 
- You can add static files like like images, pdf etc.

## routes
- Based on platform,separate folder is generated,within those folders model wise route files are that has model crud APIs' routes.
- index.js file, main file which includes all platform routes.
- Added index files in app.js to access the routes of the application.

## services
        -jobs
            -cron job services
        -auth.js
            -Logic for JWT Tokenization for user to login into Application using username and password along with otp if required.
        -dbService.js
            - Database related operations
            -common Database functionalities
            -findAll(find all records)
            -updateByPk(update single record in db by primary key)
            -deleteByPk(delete single record in db)
            -createOne(Insert single record in db)
            -findOne(find single record by query)
            -softDeleteByPk
            -updateMany(update records that matches query)
            -deleteMany(delete record that matches query)
            -createMany(insert multiple records in db)
            -count (count records that matches query)
            
## utils
        -common.js
            -converted object to enum function.
        -messages.js
            -static messages that are sent with response - contains status and Data
    -responseCode.js
            -codes for responses
    -validateRequest.js
            -validate schema based on joi validation

## validation
- Joi validations files.
- Files are separated by models.

## views
- Add ejs files                                                                                         
                                        
/*
* createDocument : create any mongoose document
* @param  model  : mongoose model
* @param  data   : {}
*/
const createDocument = (model, data) => new Promise((resolve, reject) => {
model.create(data, (err, result) => {
if (err) reject(err);
else resolve(result);
});
});

/*
* updateDocument : update any existing mongoose document
* @param  model  : mongoose model
* @param id      : mongoose document's _id
* @param data    : {}
*/
const updateDocument = (model, id, data) => new Promise((resolve, reject) => {
model.updateOne({ _id: id }, data, {
runValidators: true,
context: 'query',
}, (err, result) => {
if (err) reject(err);
else resolve(result);
});
});

/*
* deleteDocument : delete any existing mongoose document
* @param  model  : mongoose model
* @param  id     : mongoose document's _id
*/
const deleteDocument = (model, id) => new Promise((resolve, reject) => {
model.deleteOne({ _id: id }, (err, data) => {
if (err) reject(err);
else resolve(data);
});
});

/*
* getAllDocuments : find all the mongoose document
* @param  model   : mongoose model
* @param query    : {}
* @param options  : {}
*/
const getAllDocuments = (model, query, options) => new Promise((resolve, reject) => {
model.paginate(query, options, (err, data) => {
if (err) reject(err);
else resolve(data);
});
});

/*
* getSingleDocumentById : find single mongoose document
* @param  model  : mongoose model
* @param  id     : mongoose document's _id
* @param  select : [] *optional
*/
const getSingleDocumentById = (model, id, select = []) => new Promise((resolve, reject) => {
model.findOne({ _id: id }, select, (err, data) => {
if (err) reject(err);
else resolve(data);
});
});

/*
* findExistsData : find existing mongoose document
* @param  model  : mongoose model
* @params data   : {
*                   "query":{
*                       "and":[{"Name":"Dhiraj"},{"Salary":300}],
*                        "or":[{"Name":"Dhiraj"},{"Salary":300}]
*                   }
* }
*/
const findExistsData = (model, data) => {
// let { model } = data;
const { query } = data;
const { and } = query;
const { or } = query;
const q = {};

if (and) {
q.$and = [];
for (let index = 0; index < and.length; index += 1) {
    q.$and.push(and[index]);
}
}
if (or) {
q.$or = [];
for (let index = 0; index < or.length; index += 1) {
    q.$or.push(or[index]);
}
}

return new Promise((resolve, reject) => {
model.find(q, (err, result) => {
    if (err) reject(err);
    else resolve(result);
});
});
};
/*
* getDocumentByAggregation : find mongoose document by aggregation
* @param  model  : mongoose model
* @param  query : {}
*/
const getDocumentByAggregation = (model, query) => {
let keyInJson; let
valuesOfAggregate;
let valuesOfFields; let
keysOfFields;
let input = {}; let finalInput = {}; let
aggregate = {};
const array = [];
for (const [keys, values] of Object.entries(query)) {
for (const [key, value] of Object.entries(values)) {
    switch (keys) {
    case 'group':
    keyInJson = 'key' in value;
    if (keyInJson) {
        valuesOfAggregate = Object.values(value);
        valuesOfFields = Object.values(valuesOfAggregate[0]);
        keysOfFields = Object.keys(valuesOfAggregate[0]);
        for (const [nestKey, nestValue] of Object.entries(valuesOfFields)) {
        if (Array.isArray(nestValue)) {
            input._id = `$${keysOfFields[nestKey]}`;
            for (const [i, j] of Object.entries(nestValue)) {
            finalInput[`$${key}`] = '';
            finalInput[`$${key}`] += `$${j}`;
            input[j] = finalInput;
            finalInput = {};
            }
            aggregate.$group = input;
            array.push(aggregate);
        } else {
            input._id = `$${keysOfFields[nestKey]}`;
            finalInput[`$${key}`] = '';
            finalInput[`$${key}`] = `$${nestValue}`;
            input[nestValue] = finalInput;
            aggregate.$group = input;
            array.push(aggregate);
        }
        }
    }
    aggregate = {};
    finalInput = {};
    input = {};
    break;

    case 'match':
    valuesOfFields = Object.values(value).flat();
    keysOfFields = Object.keys(value);
    if (Array.isArray(valuesOfFields) && valuesOfFields.length > 1) {
        finalInput.$in = valuesOfFields;
        input[keysOfFields[0]] = finalInput;
    } else {
        input[keysOfFields[0]] = valuesOfFields[0];
    }
    aggregate.$match = input;
    array.push(aggregate);
    aggregate = {};
    input = {};
    finalInput = {};
    break;

    case 'project':
    valuesOfFields = Object.values(value);
    if (valuesOfFields.length === 1) {
        const projectValues = Object.values(valuesOfFields[0]).toString();
        const projectKeys = Object.keys(valuesOfFields[0]).toString();
        const projectArr = [];

        if (isNaN(projectValues)) {
        projectArr.push(`$${projectKeys}`);
        projectArr.push(`$${projectValues}`);
        } else {
        projectArr.push(`$${projectKeys}`);
        projectArr.push(projectValues);
        }
        finalInput[`$${key}`] = projectArr;
        input[projectKeys] = finalInput;
        aggregate.$project = input;
        array.push(aggregate);
    }
    aggregate = {};
    input = {};
    finalInput = {};
    break;
    }
}
}
return new Promise((resolve, reject) => {
model.aggregate(array, (err, data) => {
    if (err) {
    reject(err);
    }
    resolve(data);
});
});
};

/*
* softDeleteDocument : soft delete ( partially delete ) mongoose document
* @param  model      : mongoose model
* @param  id         : mongoose document's _id
*/
const softDeleteDocument = (model, id) => new Promise(async (resolve, reject) => {
const result = await getSingleDocumentById(model, id);
result.isDeleted = true;
result.isActive = false;
model.updateOne({ _id: id }, result, (err, data) => {
if (err) reject(err);
else resolve(data);
});
});

/*
* bulkInsert     : create document in bulk mongoose document
* @param  model  : mongoose model
* @param  data   : {}
*/
const bulkInsert = (model, data) => new Promise((resolve, reject) => {
model.insertMany(data, (err, result) => {
if (result !== undefined && result.length > 0) {
    resolve(result);
} else {
    reject(err);
}
});
});

/*
* bulkInsert     : update existing document in bulk mongoose document
* @param  model  : mongoose model
* @param  filter : {}
* @param  data   : {}
*/
const bulkUpdate = (model, filter, data) => new Promise((resolve, reject) => {
model.updateMany(filter, data, (err, result) => {
if (result !== undefined) {
    resolve(result);
} else {
    reject(err);
}
});
});

/*
* countDocument : count total number of records in particular model
* @param  model : mongoose model
* @param where  : {}
*/
const countDocument = (model, where) => new Promise((resolve, reject) => {
model.where(where).countDocuments((err, result) => {
if (result !== undefined) {
    resolve(result);
} else {
    reject(err);
}
});
});

/*
* getDocumentByQuery : find document by dynamic query
* @param  model      : mongoose model
* @param  where      : {}
* @param  select     : [] *optional
*/
const getDocumentByQuery = (model, where, select = []) => new Promise((resolve, reject) => {
model.findOne(where, select, (err, data) => {
if (err) reject(err);
else resolve(data);
});
});

/*
* findOneAndUpdateDocument : find existing document and update mongoose document
* @param  model   : mongoose model
* @param  filter  : {}
* @param  data    : {}
* @param  options : {} *optional
*/
const findOneAndUpdateDocument = (model, filter, data, options = {}) => new Promise((resolve, reject) => {
model.findOneAndUpdate(filter, data, options, (err, result) => {
if (err) reject(err);
else resolve(result);
});
});

/*
* findOneAndDeleteDocument : find existing document and delete mongoose document
* @param  model  : mongoose model
* @param  filter  : {}
* @param  options : {} *optional
*/
const findOneAndDeleteDocument = (model, filter, options = {}) => new Promise((resolve, reject) => {
model.findOneAndDelete(filter, options, (err, data) => {
if (err) reject(err);
else resolve(data);
});
});

module.exports = {
createDocument,
getAllDocuments,
updateDocument,
deleteDocument,
getSingleDocumentById,
findExistsData,
softDeleteDocument,
bulkInsert,
bulkUpdate,
countDocument,
getDocumentByQuery,
getDocumentByAggregation,
findOneAndUpdateDocument,
findOneAndDeleteDocument,
};                                               
                                    
const { DataTypes } = require('sequelize');
const sequelize = require('../config/dbConnection');
const sequelizePaginate = require('sequelize-paginate');
let Cart = sequelize.define('cart',{
addedBy:{ type:DataTypes.INTEGER },
createdAt:{ type:DataTypes.DATE },
email:{ type:DataTypes.TEXT },
isActive:{ type:DataTypes.BOOLEAN },
isDelete:{ type:DataTypes.BOOLEAN },
items:[{
product_id:{
    type:DataTypes.TEXT,
    allowNull:false
},
qty:{ type:DataTypes.INTEGER }
}],
updatedAt:{ type:DataTypes.DATE },
isDeleted:{ type:DataTypes.BOOLEAN }
}
,{
hooks:{
beforeCreate: [
    async function (cart,options){
    cart.isActive = true;
    cart.isDeleted = false;
    },
],
} 
});
sequelizePaginate.paginate(Cart);
module.exports = Cart;                                                
                                    
const Cart = require("../../model/cart");
const Product = require("../../model/product");
const utils = require("../../utils/messages");
const cartSchemaKey = require("../../utils/validation/cartValidation");
const validation = require("../../utils/validateRequest");
const dbService = require("../../utils/dbService");
const addCart = async(req, res) => {
try {
let isValid = validation.validateParamsWithJoi(
    req.body,
    cartSchemaKey.schemaKeys);
if (isValid.error) {
    return utils.inValidParam(isValid.details, res);
} 
let cartData = {}
let options = {}
let query={}
let proQuery={}
const { email, product_id } = req.body;
const qty = Number.parseInt(req.body.qty);
if(req.body.email !==undefined){
    query.email = req.body.email;
}
proQuery._id = product_id;
let cart = await dbService.getDocumentByQuery(Cart, query);
let proRes = await dbService.getDocumentByQuery(Product,proQuery);
if (proRes.quantity < qty) {
    return utils.failureResponse('Invalid quantity',res); 
}
if (!cart && qty <= 0) {
    return utils.failureResponse('Invalid request',res); 
} else if (cart) {
    const indexFound = cart?.items.findIndex(item => {
        return item.product_id === product_id;
    });
    if (indexFound !== -1 && qty <= 0) {
        cart?.items.splice(indexFound, 1);
        } else if (indexFound !== -1) {
        cart.items[indexFound].qty = cart.items[indexFound].qty + qty;
        } else if (qty > 0) {
        cart?.items.push({
            product_id: product_id,
            qty: qty
        });
        } else {
        return utils.failureResponse('Invalid request',res); 
        }
        console.log("idddddd",cart.id.toString());
        let re = await dbService.findOneAndUpdateDocument(Cart,{_id:cart.id.toString()},cart,{new:true});
        return  utils.successResponse(re, res); 
} else {
    cartData = {
    email: email,
    items: [
        {
        product_id: product_id,
        qty: qty
        }
    ]
    };
    }
// const data = new Cart({...req.body,});
let result = await dbService.createDocument(Cart,cartData);
return  utils.successResponse(result, res); 
} catch (error) {
if(error.name === "ValidationError"){
    return utils.validationError(error.message, res);
}
if(error.code && error.code == 11000){
    return utils.isDuplicate(error.message, res);
}
return utils.failureResponse(error.message,res); 
}
};
const findAllCart = async(req, res) => {
try {
let options = {};
let query={};
let result;
if(req.body.isCountOnly){
    if (req.body.query !== undefined) {
    query = { ...req.body.query };
    }
    result = await dbService.countDocument(Cart, query);
    if (result) {
    result = { totalRecords: result };
    return utils.successResponse(result, res);
    } 
    return utils.recordNotFound([], res);
}
else {
    if (req.body.options !== undefined) {
    if(req.body.options.populate){
        delete req.body.options.populate;
    }
    options = { ...req.body.options };
    }
        
    if(req.body.query !==undefined){
    query={...req.body.query};
    }
    result = await dbService.getAllDocuments( Cart,query,options);
        
    if(!result){
    return utils.recordNotFound([],res);
    }
    return utils.successResponse(result, res);   
}
}
catch(error){
return utils.failureResponse(error.message,res);
}
};
const getCart = async(req, res) => {
try {
// const email  = req.body.email;
// if (!email) {
//     return utils.failureResponse(error.message,res); 
// }
let query={};
query._id = req.params.id;
// query.email = req.body.email;
let result = await dbService.getDocumentByQuery(Cart,query);
if(result){
    return  utils.successResponse(result, res);
        
}
return utils.recordNotFound([],res);
}
catch(error){
return utils.failureResponse(error.message,res);
}
};
const getCartCount = async(req, res) => {
try {
let where ={};
if(req.body.where){
    where = req.body.where;
}

let result = await dbService.countDocument(Cart,where);
if(result){
    result = {totalRecords:result};
    return utils.successResponse(result, res);
}
return utils.recordNotFound([],res);
}
catch(error){
return utils.failureResponse(error.message,res);
}
};
const getCartByAggregate = async (req,res)=>{
try{
let result=await dbService.getDocumentByAggregation(Cart,req.body);
if(result){
    return utils.successResponse(result, res);
}
return utils.recordNotFound([],res);
}catch(error){
return utils.failureResponse(error.message,res);
}
};
const updateCart = async(req, res) => {
try {
const data = {
    ...req.body,
    id:req.params.id
};
let isValid = validation.validateParamsWithJoi(
    data,
    cartSchemaKey.schemaKeys
);
if (isValid.error) {
    return  utils.inValidParam(isValid.details, res);
}

let result = await dbService.findOneAndUpdateDocument(Cart,{_id:req.params.id},data,{new:true});
if(!result){
    return utils.failureResponse("something is wrong",res);
}
    
return  utils.successResponse(result, res);
}
catch(error){
if(error.name === "ValidationError"){
    return utils.isDuplicate(error.message, res);
}
if(error.code && error.code == 11000){
    return utils.isDuplicate(error.message, res);
}
return utils.failureResponse(error.message,res);
}
};
const partialUpdateCart = async (req, res) => {
try {
const data = {
    ...req.body,
    id: req.body.id
};
let isValid = validation.validateParamsWithJoi(
    data,
    cartSchemaKey.updateSchemaKeys
);
if (isValid.error) {
    return utils.inValidParam(isValid.details, res);
}

let result = await dbService.findOneAndUpdateDocument(Cart, {_id:req.body.id}, data,{new:true});
if (!result) {
    return utils.failureResponse("something is wrong", res);
}
    
return utils.successResponse(result, res);
    
}
catch(error){
return utils.failureResponse(error.message, res);
}
};
const softDeleteCart = async (req, res) => {
try{
let result = await dbService.findOneAndUpdateDocument(Cart, { _id: req.body.id }, { isDeleted: true },{new:true});
if(!result){
    return utils.recordNotFound([],res);
}
return  utils.successResponse(result, res);
}catch(error){
return utils.failureResponse(error.message,res); 
}
};
const bulkInsertCart = async(req,res)=>{
try{
let data;   
if(req.body.data !== undefined && req.body.data.length){
    data = req.body.data;

    let result =await dbService.bulkInsert(Cart,data);
    return  utils.successResponse(result, res);
}else{
    return utils.failureResponse('Invalid Data',res);
}  
}catch(error){
if(error.name === "ValidationError"){
    return utils.validationError(error.message, res);
}
if(error.code && error.code == 11000){
    return utils.isDuplicate(error.message, res);
}
return utils.failureResponse(error.message,res);
}
};
const bulkUpdateCart=async(req,res)=>{
try {
let filter={};
let data;
if(req.body.filter !== undefined){
    filter = req.body.filter;
}
if(req.body.data !== undefined){
    data = req.body.data;

    let result = await dbService.bulkUpdate(Cart,filter,data);
    if(!result){
    return utils.failureResponse("something is wrong.",res);
    }

    return  utils.successResponse(result, res);
}
else{
    return utils.failureResponse("Invalid Data", res);
}
}
catch(error){
return utils.failureResponse(error.message,res); 
}
};
const deleteCart =async(req, res) => {
try {
const result = await dbService.findOneAndDeleteDocument(Cart, {_id:req.params.id});
if(result){
    return  utils.successResponse(result, res);
}
return utils.failureResponse("something went wrong",res);
}
catch(error){
return utils.failureResponse(error.message,res);
}
};
const subtract = async(req, res) => {
try {
    let options = {}
    let query={}
    const email = req.body.email;
    const product_id = req.body.product_id;
    const qty = Number.parseInt(req.body.qty);
    if(req.body.query !==undefined){
        query={...req.body.query}
    }
    cart = await dbService.getAllDocuments( Cart,query,options);
    if (!cart && qty <= 0) {
        return utils.failureResponse('Invalid request',res); 
    } else {
        const indexFound = cart.items.findIndex(item => {
            return item.product_id === product_id;
        });
        if (indexFound !== -1) {
            console.log('index Found: ', indexFound);
            console.log('before update items: ', cart.items);
            let updatedQty = cart.items[indexFound].qty - qty;
            if (updatedQty <= 0) {
            cart.items.splice(indexFound, 1);
            } else {
            cart.items[indexFound].qty = updatedQty;
            }
            console.log('after update items: ', cart.items);
            let result = await dbService.updateDocument(Cart,{_id:req.body.id},cart);
            if(!result){
                return utils.failureResponse("something is wrong",res)
            }
            return  utils.successResponse(result, res);
        } else {
            return utils.failureResponse("Invalid request",res);
        }
    }
} catch (error) {
    if(error.name === "ValidationError"){
        return utils.validationError(error.message, res);
    }
    if(error.code && error.code == 11000){
        return utils.isDuplicate(error.message, res);
    }
    return utils.failureResponse(error.message,res); 
}
}

module.exports = {
addCart,
findAllCart,
getCart,
getCartCount,
getCartByAggregate,
updateCart,
partialUpdateCart,
softDeleteCart,
bulkInsertCart,
bulkUpdateCart,
deleteCart,
subtract
};                                                
                                    
const express = require('express');
const router = express.Router();
const session = require('express-session');
const passport = require('passport');

const {
githubStrategy, loginUser 
} = require('../services/github-login-service');
const utils = require('../utils/messages');

//github
githubStrategy(passport);

router.use(passport.initialize());

router.use(session({
secret: 'my-secret',
resave: true,
saveUninitialized: false
}));

passport.serializeUser(function (user, cb) {
cb(null, user);
});

passport.deserializeUser(function (user, cb) {
cb(null, user);
});

router.get('/error', (req, res) => {
utils.loginFailed('Login Failed', res);
});

router.get('/auth/github', passport.authenticate('github', {
scope: ['public_profile', 'email'],
session: false 
}));

router.get('/auth/github/callback',
passport.authenticate('github', { failureRedirect: '/error' }),
function (req, res) {
loginUser(req.user.email,req.session.platform).then(result=>{
    if (result.flag){
    return utils.loginFailed(result.data,res);
    }
    return utils.loginSuccess(result.data,res);
})
    .catch(error=>{
    return utils.failureResponse(error,res);
    });
});

module.exports = router;                                            
                                    
const GithubStrategy = require('passport-github2').Strategy;
const jwt = require('jsonwebtoken');

const User = require('../model/user'); 
const dbService = require('../utils/dbService');
const {
JWT,LOGIN_ACCESS,USER_ROLE,PLATFORM,NO_OF_DEVICE_ALLOWED
} = require('../config/authConstant');

module.exports = {
githubStrategy: passport => {
passport.use(new GithubStrategy({
    clientID: process.env.GITHUB_CLIENTID,
    clientSecret: process.env.GITHUB_CLIENTSECRET,
    callbackURL: process.env.GITHUB_CALLBACKURL,
    scope: ['public_profile', 'email']
}, async function (accessToken, refreshToken, profile, done) {
    if (profile){
    let userObj = {
        'username':profile.username,
        'sso_auth': { 'githubId': profile.id },
        'email': profile.emails !== undefined ? profile.emails[0].value : '',
        'password':'',
        'role':USER_ROLE.User
    };
    let found = await dbService.getDocumentByQuery(User,{ 'email':userObj.email });
    if (found){
        const id = found.id;
        await dbService.updateDocument(User,id,userObj);
    }
    else {
        await dbService.createDocument(User,userObj);
    }
    let user = await dbService.getDocumentByQuery(User,{ 'sso_auth.githubId':profile.id });
    return done(null, user);
    }
    return done(null,null);
}
));
},
loginUser: async (email, platform) => {
try {
    const user = await dbService.getDocumentByQuery(User,{ email });
    if (user && user.email) {
    const { ...userData } = user.toJSON();
    let token;
    if (!user.role) {
        return {
        flag:true,
        data:'You have no assigned any role'
        };
    }
    if (platform == undefined){
        return {
        flag:true,
        data:'Please Login through Platform'
        };
    }
    if (platform.toLowerCase() === 'client') {
        if (!LOGIN_ACCESS[user.role].includes(PLATFORM.CLIENT)) {
        return {
            flag:true,
            data:'you are unable to access this platform'
        };
        }
        token = await generateToken(userData, JWT.CLIENT_SECRET);
    }
    let tokens = user.tokens;
    if (user.tokens.length == NO_OF_DEVICE_ALLOWED){
        tokens.pop();
    }
    tokens.unshift(token);
    await dbService.updateDocument(User,user.id,{ tokens });
    delete userData.tokens;
    const userToReturn = {
        ...userData,
        ...{ token } 
    };
    return {
        flag:false,
        data:userToReturn
    };
    }
    else {
    return {
        flag:true,
        data:'Email not exists'
    };
    }
} catch (e) {
    console.log(e);
    throw new Error(e);
}

}

};

async function generateToken (user,secret){
return jwt.sign( {
id:user.id,
email:user.email
}, secret, { expiresIn: JWT.EXPIRES_IN });
}                                           
                                    
DhiWise GUI
icon
icon
icon
icon
DhiWise GUI
logo
# DhiWise App

Built with AndroidX Support

Requires Android Studio 4.1 or greater.

Current Kotlin Version 1.4.30


### SDK Versions

compileSdkVersion 30

buildToolsVersion "30.0.1"

minSdkVersion 21

targetSdkVersion 30


### Libraries

1. Retrofit- REST API Call
https://square.github.io/retrofit/
2. Glide - Image Loading and cacheing.
https://github.com/bumptech/glide
3. Material Design Components - Google's latest Material Components.
https://material.io/develop/android
4. koin - Dependency Injection
https://insert-koin.io/
### Package Structure


```
├── appcomponents       
│ ├── di                 - Dependency Injection Components 
│ │ └── MyApp.kt
│ ├── network            - REST API Call setup
│ │ ├── ResponseCode.kt
│ │ └── RetrofitProvider.kt
│ └── ui                 - Data Binding Utilities
│     └── CustomBindingAdapter.kt
├── constants            - Constant Files
│ ├── IntegerConstants.kt
│ └── StringConstants.kt
├── extensions           - Kotlin Extension Function Files
│ └── Strings.kt
├── modules              - Application Specific code
│ └── example            - A module of Application 
│  ├── ui                - UI handling classes
│  └── data              - Data Handling classes
│    ├── viewmodel       - ViewModels for the UI
│    └── model           - Model for the UI
└── network              - REST API setup
├── models             - Request/Response Models
├── repository         - Network repository
├── resources          - Common classes for API
└── RetrofitService.kt                                            

                                    
package com.dhiwiseapp.app.modules.login.ui

import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.dhiwiseapp.app.R
import com.dhiwiseapp.app.appcomponents.googleauth.GoogleHelper
import com.dhiwiseapp.app.databinding.ActivityLoginBinding
import com.dhiwiseapp.app.extensions.NoInternetConnection
import com.dhiwiseapp.app.extensions.showProgressDialog
import com.dhiwiseapp.app.modules.dashboard.ui.DashboardActivity
import com.dhiwiseapp.app.modules.login.data.model.LoginModel
import com.dhiwiseapp.app.modules.login.data.viewmodel.LoginVM
import com.dhiwiseapp.app.modules.registerform.ui.RegisterFormActivity
import com.dhiwiseapp.app.network.models.createlogin.CreateLoginRequest
import com.dhiwiseapp.app.network.models.createlogin.CreateLoginResponse
import com.dhiwiseapp.app.network.resources.ErrorResponse
import com.dhiwiseapp.app.network.resources.SuccessResponse
import com.google.android.material.snackbar.Snackbar

public class LoginActivity : AppCompatActivity() {
private lateinit var binding: ActivityLoginBinding

private val viewModel: LoginVM by viewModels()

private lateinit var googleLogin: GoogleHelper

public override fun onCreate(savedInstanceState: Bundle?): Unit {
    super.onCreate(savedInstanceState)
    binding = DataBindingUtil.setContentView(this, R.layout.activity_login)
    binding.lifecycleOwner = this
    binding.loginVM = viewModel
    binding.txtDonTHaveAnA.setOnClickListener {

        val destIntent = RegisterFormActivity.getIntent(this, null)
        startActivity(destIntent)

    }
    var progressDialog: AlertDialog? = null

    viewModel.progressLiveData.observe([email protected]) {

        if (it) {

            progressDialog?.dismiss()
            progressDialog = null
            progressDialog = [email protected]()

        } else {

            progressDialog?.dismiss()

        }

    }
    viewModel.createLoginLiveData.observe([email protected]) {

        if (it is SuccessResponse) {
            val response = it.getContentIfNotHandled()
            onSuccessCreateLogin(it)

        } else if (it is ErrorResponse) {
            onErrorCreateLogin(it)
        }

    }
    binding.btnSignIn.setOnClickListener {

        viewModel.onClickBtnSignIn(
            contentType = "application/json",
            createLoginRequest = CreateLoginRequest(
                password = viewModel.loginModel.value?.etPasswordValue,
                username = viewModel.loginModel.value?.etYourEmailValue
            )
        )

    }
    googleLogin = GoogleHelper(this,
        { accountInfo ->

        }, { error ->

        })
    binding.linear2.setOnClickListener {
        googleLogin.login()
    }
}

private fun onSuccessCreateLogin(response: SuccessResponse): Unit {
    val responseData = response.data
    val loginModelValue = viewModel.loginModel.value ?: LoginModel()
    viewModel.loginModel.value = loginModelValue
    val destIntent = DashboardActivity.getIntent(this, null)

    destIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
    finishAffinity()
    startActivity(destIntent)
}

private fun onErrorCreateLogin(response: ErrorResponse): Unit {
    when (response.data) {
        is NoInternetConnection -> {
            Snackbar.make(binding.root, response.message, Snackbar.LENGTH_LONG).show()
        }
    }
}

public companion object {
    public const val TAG: String = "LOGIN_ACTIVITY"

    public fun getIntent(context: Context, bundle: Bundle?): Intent {
        val destIntent = Intent(context, LoginActivity::class.java)
        destIntent.putExtra("bundle", bundle)
        return destIntent
    }
}
}                                                                                
                                        


    


    
    
    
    
    
    
    
        
        
        
    
    
        
        
    
    
        
        
    
    
    

                                                                                                                          
                                        
package com.dhiwiseapp.app.modules.login.`data`.viewmodel

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.dhiwiseapp.app.modules.login.`data`.model.LoginModel
import com.dhiwiseapp.app.network.models.createlogin.CreateLoginRequest
import com.dhiwiseapp.app.network.models.createlogin.CreateLoginResponse
import com.dhiwiseapp.app.network.repository.NetworkRepository
import com.dhiwiseapp.app.network.resources.Response
import kotlin.Boolean
import kotlin.String
import kotlin.Unit
import kotlinx.coroutines.launch
import org.koin.core.KoinComponent
import org.koin.core.inject

public class LoginVM : ViewModel(), KoinComponent {
public val loginModel: MutableLiveData = MutableLiveData(LoginModel())

public val progressLiveData: MutableLiveData = MutableLiveData()

private val networkRepository: NetworkRepository by inject()

public val createLoginLiveData: MutableLiveData> =
    MutableLiveData>()

public fun onClickBtnSignIn(contentType: String?, createLoginRequest: CreateLoginRequest?): Unit {
viewModelScope.launch {
    progressLiveData.postValue(true)
    createLoginLiveData.postValue(networkRepository.createLogin(contentType, createLoginRequest))
    progressLiveData.postValue(false)
}
}
}                                                                                                    
                                        
package com.dhiwiseapp.app.modules.login.`data`.model

import com.dhiwiseapp.app.R
import com.dhiwiseapp.app.appcomponents.di.MyApp
import kotlin.String

public data class LoginModel(
/**
* TODO Replace with dynamic value
*/
public var txtWelcomeToECo: String? =
    MyApp.getInstance().resources.getString(R.string.msg_welcome_to_e_co)
,
/**
* TODO Replace with dynamic value
*/
public var txtSignInToCont: String? =
    MyApp.getInstance().resources.getString(R.string.msg_sign_in_to_cont)
,
/**
* TODO Replace with dynamic value
*/
public var txtOr: String? = MyApp.getInstance().resources.getString(R.string.lbl_or)
,
/**
* TODO Replace with dynamic value
*/
public var txtLoginWithGoog: String? =
    MyApp.getInstance().resources.getString(R.string.msg_login_with_goog)
,
/**
* TODO Replace with dynamic value
*/
public var txtLoginWithFace: String? =
    MyApp.getInstance().resources.getString(R.string.msg_login_with_face)
,
/**
* TODO Replace with dynamic value
*/
public var txtForgotPassword: String? =
    MyApp.getInstance().resources.getString(R.string.msg_forgot_password)
,
/**
* TODO Replace with dynamic value
*/
public var txtDonTHaveAnA: String? =
    MyApp.getInstance().resources.getString(R.string.msg_don_t_have_an_a)
,
/**
* TODO Replace with dynamic value
*/
public var etYourEmailValue: String? = null,
/**
* TODO Replace with dynamic value
*/
public var etPasswordValue: String? = null
)                                                                                                                                              
                                        


    


    
        
            
                
                
                    
                
            
        
        
            
        
        
        
        
            
            
        
        
        
            
            
        
        
        
            
        
        
            
        
    

                                                                                                                                                                                             
                                        
DhiWise GUI
icon
icon
icon
DhiWise GUI
logo
# Getting Started with Create React App

This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).

## Available Scripts

In the project directory, you can run:

### `npm install`

### `npm start`

Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.

The page will reload if you make edits.\
You will also see any lint errors in the console.

## Folder Structure :

- src
- api :
- config.js: All API URLs are defined in this file
- client.js : Provides customized function in order to call API
- assets
- fonts
- images
- scss
- components: Components are places in this folder
- data :
- pages: Contains different pages and its configuration file
- Example :
    - User.jsx : React page
    - User.schema.json :
    - Contains different configurations:
        - Which attributes can be added/edited/displayed (User can add or edit the attributes defined in  array and same will be reflected in the panel)
        - Properties of 
            - addEdit : Attributes which can be added or edited are mentioned here
            - listing : Attributes which will be displayed on listing are mentioned here
            - detailView : Attributes which will be displayed on detail view (When user click on view icon ) are mentioned here
        - Theme style (dark theme or light theme)
        - Screen Layout
- queries: Functions are defined which are used to call APIs(react-query is used)
- .env :
- Properties :
- REACT_APP_PORT : Define backend service port(integer)

## Table Component :

Display data in table format

| Property                        |                Description                 |   Type   | Default Value |
| :------------------------------ | :----------------------------------------: | :------: | :-----------: |
| tableName                       |               Name of table                |  String  |  Model Name   |
| columnProp                      |           Describe table columns           |   JSON   |       -       |
| modelQueries                    |        Query function for API call         | Function |       -       |
| data                            |            Describe table data             |  Array   |       -       |
| hasPaginationProp               |         Enable/Disable pagination          | Boolean  |     false     |
| pageLimitProp                   |          Display table page limit          |  Number  |      10       |
| globalSearchProp                | Enable/Disable global search functionality | Boolean  |     false     |
| allowFilterProp                 |     Enable/Disable filter for columns      | Boolean  |     false     |
| allowToggleColumnVisibilityProp | Provide functionality to hide/show column  | Boolean  |     false     |
| allowRowSelectionProp           | Enable/Disable row selection functanility  | Boolean  |     false     |
| allowResizingColumnProp         |               Allow resizing               | Boolean  |     false     |
| displayTotalCountsProp          |        Display total counts of data        | Boolean  |     false     |
| onEditRecord                    |                Edit action                 | Function |       -       |
| onDeleteRecord                  |               Delete action                | Function |       -       |
| viewDataProp                    |                View action                 | Function |       -       |

## Add Drawer Component :

Add record

| Property |     Description      |   Type   | Default Value |
| :------- | :------------------: | :------: | :-----------: |
| onSubmit | Handle submit action | Function |       -       |
| schema   |     Modal Schema     |   JSON   |       -       |
| open     |   Show/Hide drawer   | Boolean  |     false     |
| onClose  | Handle close action  | Function |       -       |

## Edit Drawer Component :

Edit record

| Property    |     Description      |   Type   | Default Value |
| :---------- | :------------------: | :------: | :-----------: |
| onSubmit    | Handle submit action | Function |       -       |
| schema      |     Modal Schema     |   JSON   |       -       |
| open        |   Show/Hide drawer   | Boolean  |     false     |
| onClose     | Handle close action  | Function |       -       |
| currentData |     Current Data     |   JSON   |       -       |
                                            
                                    
import * as React from "react";
import SchemaTable from "../../components/Table/SchemaTable";
import ModelJsonSchema from "./User.schema.json";
import mockData from "./data.json";
import {
useUserList,
useUserCreate,
useUserUpdate,
useUserSoftDelete
} from "../../queries/User.queries";
import Loader from '../../components/common/Loader';
import { useBoolean } from './../../hooks';
import { AddDrawer } from "../../components/common/AddDrawer";
import { EditDrawer } from "../../components/common/EditDrawer";
import { Popup } from "../../components/common/Popup";
import { Confirmation } from "../../components/common/Confirmation";
import { errorToast, successToast } from "../../utils/notifications";

const formSchema = {
screenLayout: ModelJsonSchema.screenLayout,
attributes: ModelJsonSchema.actions.find(action => action.category === 'addEdit').attributes
}


const User = () => {

const [page, setPage] = React.useState(1);
const [limit, setLimit] = React.useState(ModelJsonSchema?.screenLayout?.listing?.config?.limitSetup || 10)

const { error, data, isLoading } = useUserList({
query: { isActive: true, isDeleted: false },
options: { page, limit }
});

const { mutate: addRecord } = useUserCreate();
const { mutate: editRecord } = useUserUpdate();
const { mutate: deleteRecord } = useUserSoftDelete();

const [addModal, showAddModal, hideAddModal] = useBoolean(false);
const [editModal, showEditModal, hideEditModal] = useBoolean(false);
const [deleteModal, showDeleteModal, hideDeleteModal] = useBoolean(false);
const [viewModal, showViewModal, hideViewModal] = useBoolean(false);
const currentRecord = React.useRef({});

const onPageChange = React.useCallback((pageIndex) => {
pageIndex >= 0 && setPage(pageIndex + 1);
}, [])

const onLimitChange = React.useCallback((pageLimit) => {
setLimit(pageLimit);
}, [])

const onViewRecord = React.useCallback((record) => {
currentRecord.current = record;
showViewModal();
}, [showViewModal])


const onDelete = React.useCallback((record) => {
currentRecord.current = record;
showDeleteModal();
}, []);

const onEdit = React.useCallback((record) => {
currentRecord.current = record;
showEditModal();
}, [])


const onCustomActionClick = React.useCallback((actionName, record) => {
alert(actionName + " action clicked");
}, []);

if (isLoading) return ;

if (error) {
console.log("error => ", error)
}
return (

     action.category === "detailView").attributes
    }
    >
    

     {
        addRecord(record, {
        onSuccess: () => successToast("Record created successfully."),
        onError: (error) => errorToast(error?.message),
        onSettled: hideAddModal
        });
    }}
    schema={formSchema}
    open={addModal}
    onClose={hideAddModal}
    />
     {
        editRecord(
        { ...record, id: currentRecord?.current?.id },
        {
            onSuccess: () => successToast("Record updated successfully."),
            onError: error => errorToast(error?.message),
            onSettled: hideEditModal
        }
        );
    }}
    />
     {
        currentRecord.current.id &&
        deleteRecord({ id: currentRecord.current.id });
        hideDeleteModal();
        successToast("Record deleted successfully!");
    }}
    handleCancel={hideDeleteModal}
    isOpen={deleteModal}
    OkText="Delete"
    />


);
};

export default User;

                                    
{
"name": "dhiwise",
"version": "0.1.0",
"private": true,
"dependencies": {
    "@dhiwise/core-ui": "0.0.14-alpha.23",
    "axios": "^0.20.0",
    "dayjs": "^1.10.6",
    "lodash": "^4.17.21",
    "match-sorter": "^6.3.0",
    "node-sass": "^4.14.1",
    "rc-drawer": "^4.3.1",
    "react": "^17.0.1",
    "react-copy-to-clipboard": "^5.0.2",
    "react-dom": "^17.0.1",
    "react-feather": "^2.0.8",
    "react-hook-form": "^7.10.1",
    "react-modal": "^3.14.3",
    "react-paginate": "^7.1.3",
    "react-popover": "^0.5.10",
    "react-query": "^3.18.1",
    "react-router": "^5.1.2",
    "react-router-dom": "^5.2.0",
    "react-scripts": "^3.4.3",
    "react-select": "^4.3.1",
    "react-table": "^7.7.0",
    "react-toastify": "^5.5.0",
    "reactstrap": "^8.4.1",
    "use-debounce": "^7.0.0",
    "use-onclickoutside": "^0.4.0"
},
"scripts": {
    "start": "react-scripts --max_old_space_size=8096 start",
    "build": "react-scripts --max_old_space_size=8096 build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
},
"browserslist": {
    "production": [
    ">0.2%",
    "not dead",
    "not op_mini all"
    ],
    "development": [
    "last 1 chrome version",
    "last 1 firefox version",
    "last 1 safari version"
    ]
}
}                                                                                              
                                        
export class ConfigDB {
static data = {
    settings: {
    layout_type: "ltr",
    sidebar: { wrapper: "default", bodyWrapper: "default" },
    sidebar_setting: "default-sidebar",
    sidebar_backround: "dark-sidebar",
    },
    color: {
    layout_version: "dark-only",
    color: "color-1",
    primary_color: "#4466f2",
    secondary_color: "#1ea6ec",
    mix_layout: "default",
    },
    router_animation: "fadeIn",
};
}

export default ConfigDB;                                                                                                                                               
                                        
DhiWise GUI
icon
icon
icon
DhiWise GUI
logo
import 'package:flutter/material.dart';
import 'package:ecommerce_sample_demo/localization/app_localization.dart';
import 'package:get/get.dart';

import 'core/app_export.dart';

void main() {
    WidgetsFlutterBinding.ensureInitialized();
    runApp(MyApp());
}

class MyApp extends StatelessWidget {
    // This widget is the root of your application.
    @override
    Widget build(BuildContext context) {
    return GetMaterialApp(
        debugShowCheckedModeBanner: false,
        translations: AppLocalization(),
        locale: Get.deviceLocale,
        fallbackLocale: Locale('en', 'US'),
        title: 'ecommerce_sample_demo',
        initialRoute: AppRoutes.initialRoute,
        getPages: AppRoutes.pages,
    );
    }
} 
                                    
import 'package:ecommerce_sample_demo/presentation/splash_screen_screen/splash_screen_screen.dart';
import 'package:ecommerce_sample_demo/presentation/login_screen/login_screen.dart';
import 'package:ecommerce_sample_demo/presentation/profile_screen/profile_screen.dart';
import 'package:ecommerce_sample_demo/presentation/app_navigation_screen/app_navigation_screen.dart';
import 'package:get/get.dart';

class AppRoutes {
static String splashScreenScreen = 'splash_screen_screen';

static String loginScreen = 'login_screen';

static String profileScreen = 'profile_screen';

static String appNavigationScreen = 'app_navigation_screen';

static String initialRoute = 'initialRoute';

static List pages = [
    GetPage(name: splashScreenScreen, page: () => SplashScreenScreen()),
    GetPage(name: loginScreen, page: () => LoginScreen()),
    GetPage(name: profileScreen, page: () => ProfileScreen()),
    GetPage(name: appNavigationScreen, page: () => AppNavigationScreen()),
    GetPage(name: initialRoute, page: () => SplashScreenScreen())
];
}
                                    
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility that Flutter provides. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

import 'package:ecommerce_sample_demo/main.dart';

void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
    // Build our app and trigger a frame.
    await tester.pumpWidget(MyApp());

    // Verify that our counter starts at 0.
    expect(find.text('0'), findsOneWidget);
    expect(find.text('1'), findsNothing);

    // Tap the '+' icon and trigger a frame.
    await tester.tap(find.byIcon(Icons.add));
    await tester.pump();

    // Verify that our counter has incremented.
    expect(find.text('0'), findsNothing);
    expect(find.text('1'), findsOneWidget);
});
}
                                    
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility that Flutter provides. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

import 'package:ecommerce_sample_demo/main.dart';

void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
    // Build our app and trigger a frame.
    await tester.pumpWidget(MyApp());

    // Verify that our counter starts at 0.
    expect(find.text('0'), findsOneWidget);
    expect(find.text('1'), findsNothing);

    // Tap the '+' icon and trigger a frame.
    await tester.tap(find.byIcon(Icons.add));
    await tester.pump();

    // Verify that our counter has incremented.
    expect(find.text('0'), findsNothing);
    expect(find.text('1'), findsOneWidget);
});
}
                                    
# ecommerce_sample_demo

A new Flutter project.

## SDK Versions

Dart SDK Version 2.12.0 or greater.

Flutter SDK Version 2.0.0 or greater.

## Libraries

1. cupertino_icons - for iOS icons
https://pub.dev/packages/cupertino_icons
2. connectivity - For status of network connectivity
https://pub.dev/packages/connectivity
3. get - State management
https://pub.dev/packages/get


## Package Structure

```
.
├── main.dart                   - starting point of the application
├── core
│   ├── app_export.dart         - contains commonly used file imports 
│   ├── errors                  - contains error handling classes                  
│   ├── network                 - contains network related classes
│   └── utils                   - contains common files and utilities of project
├── data
│   ├── apiClient               - contains api calling methods
│   ├── dataSources             -     
│   ├── models                  - contains request/response models 
│   └── repository              - network repository
├── localization                - contains localization classes
├── presentation               
│   ├── commonWidgets           - contains common widgets
│   └── screens                 - contains all screens
├── routes                      - contains all the routes of application
└── theme                       - contains app theme and decoration classes
```
                                    
DhiWise GUI
icon
icon
icon
icon
icon
DhiWise GUI
logo
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model as Model;

class Cart extends Model
{
    protected $table = 'carts';

    protected $fillable = [
        'is_active',
        'created_at',
        'updated_at',
        'added_by',
        'updated_by',
        'productId',
        'userId',
        'qty',
    ];

    protected $hidden = [
    ];

    protected $casts = [
        'is_active' => 'boolean',
        'created_at' => 'date',
        'updated_at' => 'date',
        'added_by' => 'integer',
        'updated_by' => 'integer',
        'productId' => 'integer',
        'userId' => 'integer',
        'qty' => 'integer',
    ];
}
                                        
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model as Model;

class Category extends Model
{
    protected $table = 'categories';

    protected $fillable = [
        'is_active',
        'created_at',
        'updated_at',
        'added_by',
        'updated_by',
        'icon',
        'name',
        'description',
        'categoryId',
    ];

    protected $hidden = [
    ];

    protected $casts = [
        'is_active' => 'boolean',
        'created_at' => 'date',
        'updated_at' => 'date',
        'added_by' => 'integer',
        'updated_by' => 'integer',
        'icon' => 'string',
        'name' => 'string',
        'description' => 'string',
        'categoryId' => 'integer',
    ];
}
                                        
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model as Model;

class Order extends Model
{
    protected $table = 'orders';

    protected $fillable = [
        'is_active',
        'created_at',
        'updated_at',
        'added_by',
        'updated_by',
        'orderNumber',
        'userId',
        'status',
        'totalPrice',
    ];

    protected $hidden = [
    ];

    protected $casts = [
        'is_active' => 'boolean',
        'created_at' => 'date',
        'updated_at' => 'date',
        'added_by' => 'integer',
        'updated_by' => 'integer',
        'orderNumber' => 'string',
        'userId' => 'integer',
        'status' => 'integer',
        'totalPrice' => 'integer',
    ];
}
                                        
<?php

namespace App\Models;

use Spatie\Permission\Models\Role as RoleModel;

class Role extends RoleModel
{
    public function __construct(array $attributes = [])
    {
        $attributes['guard_name'] = $attributes['guard_name'] ?? 'web';

        parent::__construct($attributes);
    }

    protected $with = ['permissions'];
}
                                        
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Laravel\Sanctum\Sanctum;

class AppServiceProvider extends ServiceProvider
{
    /**
        * Register any application services.
        *
        * @return void
        */
    public function register()
    {
        Sanctum::ignoreMigrations();
    }

    /**
        * Bootstrap any application services.
        *
        * @return void
        */
    public function boot()
    {
    }
}
                                        
DhiWise GUI
icon
icon
icon
DhiWise GUI
logo
//
//  AppDelegate.swift
//  EComTest
//

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

    // MARK: UISceneSession Lifecycle

    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // Called when a new scene session is being created.
        // Use this method to select a configuration to create the new scene with.
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
        // Called when the user discards a scene session.
        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
    }


}


                                    
//
//  SceneDelegate.swift
//  EComTest
//

import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?


    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            let vc  = LoginVC(nibName:"LoginVC", bundle:nil)
            let nav = UINavigationController(rootViewController: vc)
            nav.setNavigationBarHidden(true, animated: false)
            
            window.rootViewController = nav
            
            self.window = window
            window.makeKeyAndVisible()
        }
    }

    func sceneDidDisconnect(_ scene: UIScene) {
        // Called as the scene is being released by the system.
        // This occurs shortly after the scene enters the background, or when its session is discarded.
        // Release any resources associated with this scene that can be re-created the next time the scene connects.
        // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
    }

    func sceneDidBecomeActive(_ scene: UIScene) {
        // Called when the scene has moved from an inactive state to an active state.
        // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
    }

    func sceneWillResignActive(_ scene: UIScene) {
        // Called when the scene will move from an active state to an inactive state.
        // This may occur due to temporary interruptions (ex. an incoming phone call).
    }

    func sceneWillEnterForeground(_ scene: UIScene) {
        // Called as the scene transitions from the background to the foreground.
        // Use this method to undo the changes made on entering the background.
    }

    func sceneDidEnterBackground(_ scene: UIScene) {
        // Called as the scene transitions from the foreground to the background.
        // Use this method to save data, release shared resources, and store enough scene-specific state information
        // to restore the scene back to its current state.
    }


}


                                    
//
//  UIViewExtension.swift
//  EComTest
//

import UIKit

//MARK: UIView IBInspactable
extension UIView {
    
    @IBInspectable
    var shadowColor: UIColor {
        get{
            return UIColor(cgColor: layer.shadowColor ?? UIColor.gray.cgColor)
        }
        
        set {
            layer.shadowColor =  newValue.cgColor
        }
    }

      @IBInspectable var shadowOpacity: Float{
          set {
              layer.shadowOpacity = newValue
            if newValue > 0 {
                 self.addShadow()
            }
          }
          get{
              return layer.shadowOpacity
          }
      }

      @IBInspectable var shadowOffset: CGSize{
          set {
              layer.shadowOffset = newValue
          }
          get{
              return layer.shadowOffset
          }
      }

      @IBInspectable var shadowRadius: CGFloat{
          set {
              layer.shadowRadius = newValue
          }
          get{
              return layer.shadowRadius
          }
      }
    

     fileprivate func addShadow() {
          let layer = self.layer
          layer.masksToBounds = false

        layer.shadowPath = UIBezierPath(roundedRect: layer.bounds, cornerRadius: layer.cornerRadius).cgPath

          let backgroundColor = self.backgroundColor?.cgColor
          self.backgroundColor = nil
          layer.backgroundColor =  backgroundColor
     }

    
     @IBInspectable var cornerRadius: CGFloat {
          get {
               return self.layer.cornerRadius
          }

          set {
               self.layer.cornerRadius = newValue
          }
     }


    // Border Color

    @IBInspectable
    var BorderColorKey: UIColor {
        get{
            return UIColor(cgColor: layer.borderColor ?? UIColor.gray.cgColor)
        }
        
        set {
            layer.borderColor = newValue.cgColor
        }
    }
    
     // Border width
     @IBInspectable
     public var borderWidth: CGFloat {
          set {
               layer.borderWidth = newValue
          }

          get {
               return layer.borderWidth
          }
     }


}



                                    
//
//  RequestManager.swift
//  EComTest
//


import Alamofire
import NVActivityIndicatorView

public typealias ResponseData = [String: Any]
public typealias ResponseArray = [Any]
public typealias FailureMessage = String
public typealias ResponseString = String
public typealias FailureCode    = String


class NetworkClient {
    
//    // MARK: - Constant
//    struct Constants {
//        
//        struct RequestHeaderKey {
//            static let contentType                  = "Content-Type"
//            static let applicationJSON              = "application/json"
//        }
//        
//        struct HeaderKey {
//            
//            static let Authorization                = "Authorization"
//        }
//        
//        struct ResponseKey {
//            
//            static let code                         = "code"
//            static let data                         = "data"
//            static let message                      = "message"
//            static let list                         = "list"
//            static let serverLastSync               = "server_last_sync"
//        }
//        
//        //MARK:  ResponseCode
//        struct ResponseCode {
//            
//            static let EmailRequired                     = "EMAIL_IS_REQUIRED"
//            static let DobRequired                       = "DOB_IS_REQUIRED"
//            static let EmailDobRequired                  = "EMAIL_DOB_IS_REQUIRED"
//            static let ok                                = "OK"
//            static let kTokenExpiredCode                 = "E_TOKEN_EXPIRED"
//            static let kUnAuthorized                     = "E_UNAUTHORIZED"
//            static let kInvalidToken                     = "E_INVALID_TOKEN"
//        }
//    }

    // MARK: - Properties
    
    // A Singleton instance
    static let sharedInstance = NetworkClient()
    
    // A network reachability instance
    let networkReachability = NetworkReachabilityManager()
    private var requestsToRetry: [RequestRetryCompletion] = []
    
    // Initialize
    private init() {
        networkReachability?.startListening()
        setIndicatorViewDefaults()
    }
    
    // MARK: - Indicator view
    private func setIndicatorViewDefaults() {
        
        NVActivityIndicatorView.DEFAULT_TYPE = .ballRotateChase
        NVActivityIndicatorView.DEFAULT_COLOR = UIColor.white
        NVActivityIndicatorView.DEFAULT_BLOCKER_SIZE = CGSize(width: 40, height: 40)
        NVActivityIndicatorView.DEFAULT_BLOCKER_MESSAGE_FONT = UIFont.boldSystemFont(ofSize: 17)
    }
    
    func isNetworkAvailable() -> Bool {
        
        guard (networkReachability?.isReachable)! else {
            return false
        }
        
        return true
    }
    
    /// show indicator before network request
    func showIndicator(_ message:String?, stopAfter: Double) {
        
        let activityData = ActivityData(message: message)
        NVActivityIndicatorPresenter.sharedInstance.startAnimating(activityData)
        
        if stopAfter > 0 {
            DispatchQueue.main.asyncAfter(deadline: .now() + stopAfter) {
                NVActivityIndicatorPresenter.sharedInstance.stopAnimating()
            }
        }
    }
    
    ///Stop Indicator Manually
    func stopIndicator() {
        NVActivityIndicatorPresenter.sharedInstance.stopAnimating()
    }
    
    /// Show indicator
    func showIndicatorInView(view: UIView) -> NVActivityIndicatorView {
        
        let indicatorView = NVActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 40, height: 40), type: NVActivityIndicatorType.ballScaleMultiple, color: UIColor.gray.withAlphaComponent(0.8))
        indicatorView.center = view.center
        view.superview?.addSubview(indicatorView)
        
        indicatorView.startAnimating()
        return indicatorView
    }
    
    
    //     MARK: - Network Request
    
    // Global function to call web service
    func request(_ url: URLConvertible, command: String, method: HTTPMethod = .get, parameters: Parameters? = nil, headers: HTTPHeaders? = nil, success:@escaping ((Any, String)->Void), failure:@escaping ((FailureMessage,FailureCode)->Void)) {
        
        // check network reachability
        guard (networkReachability?.isReachable)! else {
            
            NVActivityIndicatorPresenter.sharedInstance.stopAnimating()
            //            failure("No Internet Connection.",100)
            Utilities.showAlert(title: "Error", message: "No Internet Connection.")
            return
        }
        
        var serverUrl = "\(url)"
        
        if serverUrl == "" {
            serverUrl = AppConstants.serverURL
        }

        // create final url
        let finalURLString: String = "\(serverUrl)\(command)"
        let finalURL = NSURL(string : finalURLString)! as URL
        
        print(finalURL)
        // Network request
        Alamofire.request(finalURL, method: method, parameters: parameters, encoding: JSONEncoding.default, headers: headers).responseJSON { (response: DataResponse) in
            
            NVActivityIndicatorPresenter.sharedInstance.stopAnimating()
            
            // check result is success
            guard response.result.isSuccess else {
                failure((response.result.error?.localizedDescription)!,"")
                return
            }
            
            let responseObject = response.result.value as? [String: Any]
            if(responseObject != nil){
                success(responseObject, response.result.description)
                
            }
//            // get status code
//            let statusCode = responseObject?[Constants.ResponseKey.code] as? String ?? ""
//
//            // get status message
//            let message = responseObject?[Constants.ResponseKey.message] as? String ?? ""
//
//            //User LogOut
//            if statusCode == Constants.ResponseCode.kTokenExpiredCode {
//                //                ApplicationData.sharedInstance.logoutUser(isClear: false)
//                failure(message,statusCode)
//                return
//            }
//
//            if statusCode ==  NetworkClient.Constants.ResponseCode.kInvalidToken {
//
//              failure(message,statusCode)
//                return
//
//            }
//
//            if statusCode == Constants.ResponseCode.kUnAuthorized {
//
//                failure(message,statusCode)
//                return
//            }
//
//
//            if statusCode != Constants.ResponseCode.ok {
//                failure(message,statusCode)
//                return
//            }
//
//            // get data object
//            let dataObject = responseObject?[Constants.ResponseKey.data]
//
//            // pass data as dictionary if data key contains json object
//            if let data = dataObject as? ResponseData {
//                success(data, message)
//                return
//            }
//            else if let data = dataObject as? ResponseArray {
//                success(data, message)
//                return
//            } else  if statusCode == Constants.ResponseCode.ok {
//                success([], message)
//                return
//            } else {
//                failure(message,statusCode)
//                return
//            }
        }
    }
}