login page, and forget password page

This commit is contained in:
omair saleh
2021-07-21 16:10:07 +08:00
parent 4f7b4ab9aa
commit 8b51cdc1dc
29 changed files with 1799 additions and 8 deletions
Vendored
+118
View File
@@ -0,0 +1,118 @@
const pkg = require('./package.json');
const gulp = require('gulp');
const fancyLog = require('fancy-log');
const del = require('del');
const plugins = require('gulp-load-plugins')({
lazy: true,
postRequireTransforms: {
print: (plugin) => plugin.default,
uglifyEs: (plugin) => plugin.default
}
});
const onError = (error) => {
fancyLog(error);
};
const sassOptions = {style: 'compressed'};
gulp.task('vendorJs', () => {
fancyLog('Compiling vendor JS dependencies');
return gulp.src(pkg.globs.vendorJs)
.pipe(plugins.plumber({errorHandler: onError}))
.pipe(plugins.print())
.pipe(plugins.concat('vendor.js'))
.pipe(plugins.uglify())
.pipe(gulp.dest(pkg.paths.build.js));
});
gulp.task('vendorCss', () => {
fancyLog('Compiling vendor CSS dependencies');
return gulp.src(pkg.globs.vendorCss)
.pipe(plugins.plumber({errorHandler: onError}))
.pipe(plugins.print())
.pipe(plugins.concatCss('vendor.css'))
.pipe(plugins.cleanCss())
.pipe(plugins.replace('../../../font-awesome/', './'))
.pipe(plugins.replace('../../jquery-ui-dist/', ''))
.pipe(gulp.dest(pkg.paths.build.css));
});
gulp.task('vendorFonts', () => {
fancyLog('Copying vendor fonts for dependencies');
return gulp.src(pkg.globs.vendorFlags)
.pipe(plugins.plumber({errorHandler: onError}))
.pipe(plugins.print())
.pipe(gulp.dest(pkg.paths.build.flags));
});
gulp.task('vendorFlags', () => {
fancyLog('Copying flags svg for dependencies');
return gulp.src(pkg.globs.vendorFonts)
.pipe(plugins.plumber({errorHandler: onError}))
.pipe(plugins.print())
.pipe(gulp.dest(pkg.paths.build.fonts));
});
gulp.task('vendorImages', () => {
fancyLog('Copying vendor images for dependencies');
return gulp.src(pkg.globs.vendorImages)
.pipe(plugins.plumber({errorHandler: onError}))
.pipe(plugins.print())
.pipe(gulp.dest(pkg.paths.build.images));
});
gulp.task('sourceImages', () => {
fancyLog('Compiling source image files');
return gulp.src(pkg.globs.sourceImages)
.pipe(plugins.plumber({errorHandler: onError}))
.pipe(plugins.print())
.pipe(gulp.dest(pkg.paths.build.images));
});
gulp.task('sourceCss', gulp.series('sourceImages', () => {
fancyLog('Compiling source CSS files');
return gulp.src(pkg.globs.sourceCss)
.pipe(plugins.plumber({errorHandler: onError}))
.pipe(plugins.print())
.pipe(plugins.sass(sassOptions).on('error', plugins.sass.logError))
.pipe(plugins.autoprefixer())
.pipe(plugins.concatCss('site.css'))
.pipe(gulp.dest(pkg.paths.build.css));
}));
gulp.task('sourceJs', () => {
fancyLog('Compiling source JS dependencies');
return gulp.src(pkg.globs.sourceJs)
.pipe(plugins.plumber({errorHandler: onError}))
.pipe(plugins.print())
.pipe(plugins.concat('site.js'))
.pipe(plugins.uglifyEs())
.pipe(gulp.dest(pkg.paths.build.js));
});
gulp.task('sourceFonts', () => {
fancyLog('Compiling source font files');
return gulp.src(pkg.globs.sourceFonts)
.pipe(plugins.plumber({errorHandler: onError}))
.pipe(plugins.print())
.pipe(gulp.dest(pkg.paths.build.fonts));
});
gulp.task('clean', () => {
return del([pkg.paths.build.css + '/*', pkg.paths.build.js + '/*', !pkg.paths.build.js + '/app.js', pkg.paths.build.images + '/*', pkg.paths.build.fonts + '/*']);
});
gulp.task('vendor', gulp.series('vendorJs', 'vendorCss', 'vendorFonts', 'vendorFlags', 'vendorImages'));
gulp.task('source', gulp.series('sourceCss', 'sourceImages', 'sourceJs', 'sourceFonts'));
gulp.task('build', gulp.series('clean', 'vendor', 'source'));
gulp.task('watch', (done) => {
gulp.watch(pkg.globs.sourceCss, gulp.series('sourceCss'));
gulp.watch(pkg.globs.sourceImages, gulp.series('sourceImages'));
gulp.watch(pkg.globs.sourceJs, gulp.series('sourceJs'));
gulp.watch(pkg.globs.sourceJs, gulp.series('sourceFonts'));
done();
});
+5 -5
View File
@@ -27,12 +27,12 @@ $color-master-darkest:mix($color-master, #000, 18%) !default;
$color-white: #fff !default;
$color-black: #000 !default;
$color-success: #1ac86f !default;
$color-complete : #009add !default;
$color-primary: #00baa4 !default;
$color-success: #349128 !default;
$color-complete : #386DFF !default;
$color-primary: #912873 !default;
$color-warning: #ffca00 !default;
$color-danger: #ed5335 !default;
$color-info: #4d6286 !default;
$color-danger: #F3201F !default;
$color-info: #503C93 !default;
$base-font-family: wf_segoe-ui_light,wf_segoe-ui_normal,"Helvetica Neue", Helvetica, Arial, sans-serif !default;
+5
View File
@@ -2174,3 +2174,8 @@ select2-dropdown,
padding-bottom: 0;
}
}
.dotted-grid {
background : radial-gradient(#fff 1px, transparent 2px);
background-size : 12px 12px;
}
+2 -2
View File
@@ -294,8 +294,8 @@ hr{
------------------------------------
*/
.bg-primary-complete-gradient {
background: linear-gradient(to right, $color-complete, $color-primary);
.bg-info-primary-gradient {
background: linear-gradient($color-info, $color-primary);
}
/* Primary
------------------------------------
@@ -0,0 +1,59 @@
<template>
<div class="row">
<div class="col">
<loading-component style="height: 200px; top: 0;" key="1" color="success" v-show="$store.getters.isLoading(section)"></loading-component>
<div class="row" v-show="sent">
<div class="col">
<div class="row align-items-center m-b-10">
<div class="col-auto p-r-0">
<div class="icon-thumbnail fs-16 icon-25 m-r-10 btn-rounded bg-success">
<i class="fa fa-check fs-16 text-white"></i>
</div>
</div>
<div class="col p-l-0">
<div class="font-heading fs-12 all-caps bold text-success">Verification email sent</div>
</div>
</div>
<div class="font-heading fs-11">It may take a few minutes. follow the directions in the email to confirm and activate your account</div>
</div>
</div>
<div class="row" v-show="!$store.getters.isLoading(section) && !sent">
<div class="col">
<div class="row">
<div class="col">
<div class="font-heading fs-16 all-caps bold m-b-15">Verify your email</div>
<div class="font-heading fs-12 m-b-5">We have sent an email to <span class="bold text-primary">{{ $store.getters.getUserEmail }}</span></div>
<div class="font-heading fs-11">You need to verify your email to continue.</div>
<div class="font-heading fs-11 m-b-15">If you have not received the verification email, please check your <span class="text-danger">Spam</span> folder.</div>
<div class="font-heading fs-11 m-b-10">You can also click the resend button below to have another email sent to you.</div>
</div>
</div>
<div class="row">
<div class="col-auto">
<button class="btn btn-sm b-rad-none btn-outline-success" @click="submit(route('api.account.email.verification.resend'), 'post', section, true, false); sent=true">Resend Verification Email</button>
</div>
<div class="col no-padding">
<error-message-component :error="error"></error-message-component>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import ModalFromHandler from '../../../general/mixins/modalFormHandler'
export default {
data(){
return {
sent: false,
parameters: {
user_id: this.$store.getters.getUserId
}
}
},
mixins: [ModalFromHandler]
}
</script>
@@ -0,0 +1,88 @@
<template>
<div class="row">
<div class="col">
<div class="row m-b-10 animate__animated animate__fadeInUpBig animate__fast" v-if="error">
<div class="col">
<small class="bold fs-10 text-danger">{{error}}</small>
</div>
</div>
<div class="row" v-show="!$store.getters.isShowing('forgetPasswordSuccess')">
<div class="col animate__animated">
<div class="row align-items-center">
<div class="col">
<validation-wrapper-component class="m-b-15" :validator="$v.parameters.email">
<label class="text-primary">Email Address</label>
<div class="controls">
<input type="text" class="form-control fs-12" v-model="parameters.email">
</div>
</validation-wrapper-component>
</div>
</div>
</div>
</div>
<div class="row m-b-15" v-show="$store.getters.isShowing('forgetPasswordSuccess')">
<div class="col">
<div class="row m-b-5">
<div class="col">
<h4 class="font-lato text-success bold"><i class="fa fa-check-circle m-r-5"></i> Password Reset Email Sent</h4>
</div>
</div>
<div class="row">
<div class="col">
<small class="font-lato">An email has been sent to your rescue email address. Follow the directions in the email to reset your password.</small>
</div>
</div>
</div>
</div>
<div class="row align-items-center justify-content-center">
<div class="col" v-show="!$store.getters.isShowing('forgetPasswordSuccess')">
<div class="btn btn-block btn-lg btn-primary b-rad-none no-border" @click="submit(route('api.account.authentication.password.forget'), 'post', section, false , false)">Reset Password</div>
</div>
</div>
<div class="row m-t-20">
<div class="col text-center">
<p class="muted fs-11 font-arial m-b-0 pointer bold" >Remember password? <span class="point text-primary" @click="$store.dispatch('returnToLoginAfterSendResetPasswordLink')">Sign in</span></p>
</div>
</div>
</div>
</div>
</template>
<script>
import { required, email } from "vuelidate/lib/validators";
import request from '../../../general/mixins/request'
export default {
props: {
section:{
type: String,
required: true
}
},
data() {
return {
error: '',
parameters: {
email: ''
}
};
},
validations: {
parameters: {
email: { required, email }
}
},
methods:{
successHandler(){
this.$store.dispatch('toggleSection', {name: 'forgetPasswordSuccess', status: true});
this.$store.dispatch('passwordResetEmail', {email: this.parameters.email});
this.resetForm();
},
errorHandler(error){
this.error = error.message;
}
},
mixins: [request]
}
</script>
@@ -0,0 +1,62 @@
<template>
<div class="row" @keyup.enter="submitForm">
<div class="col">
<error-message-component class="m-b-20" :error="error"></error-message-component>
<div class="row">
<div class="col">
<validation-wrapper-component class="m-b-15" :validator="$v.parameters.email">
<label class="text-primary">Email Address</label>
<input type="text" class="form-control fs-12" v-model.trim="parameters.email">
</validation-wrapper-component>
<validation-wrapper-component :validator="$v.parameters.password">
<label class="text-primary">Password</label>
<input type="password" class="form-control fs-12" v-model="parameters.password">
</validation-wrapper-component>
<div class="row m-t-15 align-items-center justify-content-center">
<div class="col-auto">
<div class="checkbox check-complete no-margin">
<input type="checkbox" checked="checked" value="1" id="checkbox2">
<label for="checkbox2 bold no-margin">Remember Me</label>
</div>
</div>
<div class="col text-right">
<p class="muted fs-11 font-arial m-b-0 pointer bold" @click="$store.dispatch('toggleSection', {name: 'forgetPassword', status: true})">Forgot password?</p>
</div>
</div>
<div class="row m-t-15 align-items-center justify-content-center">
<div class="col">
<div class="btn btn-block btn-lg btn-primary b-rad-none no-border" @click="submitForm">Sign In</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import loginFormValidation from '../../../general/mixins/accounts/validation/loginFormValidation'
export default {
props: {
section:{
type: String,
required: true
}
},
data() {
return {
error: '',
parameters: {
email: this.email,
password: ''
}
};
},
methods: {
submitForm(){
this.submit(this.route('api.account.authentication.authenticate.attempt'), 'post', this.section, false, false)
}
},
mixins: [loginFormValidation]
}
</script>
File diff suppressed because one or more lines are too long
@@ -0,0 +1,104 @@
<template>
<div class="row">
<div class="col">
<div class="row" v-show="!$store.getters.isShowing('resetPasswordSuccess')">
<div class="col">
<div class="row m-b-15">
<div class="col">
<div class="inline v-align-middle">
<div class="font-heading fs-20 all-caps text-primary no-margin lh-28 bold">Reset your password</div>
</div>
</div>
</div>
<div class="row m-r-0 m-l-0 m-b-20" v-if="error">
<div class="col p-l-50">
<small class="bold fs-10 text-danger">{{error}}</small>
</div>
</div>
<validation-wrapper-component class="m-b-15" :validator="$v.parameters.password">
<label class="text-primary">Password</label>
<div class="controls">
<input type="password" class="form-control fs-12" v-model="parameters.password">
</div>
</validation-wrapper-component>
<validation-wrapper-component class="m-b-15" :validator="$v.parameters.confirmPassword">
<label class="text-primary">Confirm Password</label>
<div class="controls">
<input type="password" class="form-control fs-12" v-model="parameters.confirmPassword">
</div>
</validation-wrapper-component>
<div class="row align-items-center">
<div class="col"></div>
<div class="col-auto">
<div class="btn btn-lg b-rad-none btn-success" @click="submit(route('api.account.authentication.password.reset'), 'post', section, false , false)">Reset Password</div>
</div>
</div>
</div>
</div>
<div class="row" v-show="$store.getters.isShowing('resetPasswordSuccess')">
<div class="col">
<div class="row m-b-5">
<div class="col">
<h4 class="font-lato text-success bold"><i class="fa fa-check-circle m-r-5"></i> Password Changed successfully</h4>
</div>
</div>
<div class="row m-b-10">
<div class="col">
<small class="font-lato">You have successfully changed your password, now you can login into your account using your new password.</small>
</div>
</div>
<div class="row">
<div class="col">
<a :href="route('login')"><div class="btn btn-sm btn-default b-rad-none light" style="letter-spacing: 2px;"><i class="fa fa-angle-left" style="padding-right: 18px;"></i>Go to login</div></a>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { required } from "vuelidate/lib/validators";
import request from '../../../general/mixins/request'
export default {
props: {
section:{
type: String,
required: true
},
token:{
type: String,
required: true
}
},
data() {
return {
error: '',
passwordChanged: false,
parameters: {
email: '',
confirmPassword:'',
token:this.token,
}
};
},
validations: {
parameters: {
password:{required},
confirmPassword: {required},
token: {required}
}
},
methods:{
successHandler(){
this.$store.dispatch('toggleSection', {name: 'resetPasswordSuccess', status: true});
},
errorHandler(error){
this.error = error.message;
}
},
mixins: [request]
}
</script>
@@ -0,0 +1,101 @@
<template>
<div class="row parentContainer">
<div class="col">
<div class="requestModal pointer h-100" @click="loadFile" data-type="filePreview">
<slot name="button" ></slot>
</div>
<modal-component styleType="fill-in" size="extra-large" type="filePreview">
<loading-component style="height: 200px; top: 0;" key="1" color="success" v-show="isLoading"></loading-component>
<div class="row">
<div class="col text-center">
<img :src="src" class="w-100" v-if="type !== 'pdf'">
<div class="btn btn-complete pointer m-b-20" @click="openBase64NewTab()" v-show="type === 'pdf'">Open in new window</div>
<iframe v-if="type === 'pdf'" class="pdf-display w-100 scrollable" style="height: 80vh" :src="'data:application/pdf;base64,'+src"></iframe>
</div>
</div>
</modal-component>
</div>
</div>
</template>
<script>
export default {
props: {
file: {
type: Object,
required: true
},
},
data(){
return {
isLoading: false,
loaded: false,
src: ''
}
},
computed: {
type() {
return this.file.file.mime_type === 'application/pdf' ? 'pdf' : 'image'
}
},
methods:{
loadFile(){
if(!this.loaded) {
this.isLoading = true;
let filePath = this.type === 'pdf' ? this.file.file.file_info.original.file : this.file.file.file_info[0].original.file;
this.submit(this.route('api.storage.document.file', filePath)+'/', 'get', 'imagePreviewSection', false, false)
}
},
renderPdf() {
this.isLoading = false;
},
openBase64NewTab() {
console.log(this.src);
var blob = this.base64toBlob(this.src);
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, "pdfBase64.pdf");
} else {
const blobUrl = URL.createObjectURL(blob);
window.open(blobUrl);
}
},
base64toBlob(base64Data) {
const sliceSize = 1024;
const byteCharacters = atob(base64Data);
const bytesLength = byteCharacters.length;
const slicesCount = Math.ceil(bytesLength / sliceSize);
const byteArrays = new Array(slicesCount);
for (let sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
const begin = sliceIndex * sliceSize;
const end = Math.min(begin + sliceSize, bytesLength);
const bytes = new Array(end - begin);
for (let offset = begin, i = 0; offset < end; ++i, ++offset) {
bytes[i] = byteCharacters[offset].charCodeAt(0);
}
byteArrays[sliceIndex] = new Uint8Array(bytes);
}
return new Blob(byteArrays, { type: "application/pdf" });
},
successHandler(response){
this.loaded = true;
this.src = response.payload.src;
this.isLoading = false;
if(this.type === 'pdf'){
this.renderPdf()
}
},
errorHandler(error, statusCode){
this.src = statusCode === 404 ? '/images/3231370.jpg' : '/images/2942005.jpg'
this.isLoading = false;
}
},
}
</script>
<style scoped>
</style>
@@ -0,0 +1,17 @@
<template>
<div class="row animate__animated animate__fadeInUpBig animate__fast align-items-center" v-if="error">
<div class="col">
<small class="bold fs-10 text-danger">{{error}}</small>
</div>
</div>
</template>
<script>
export default {
props: {
error: {
required: true
}
}
}
</script>
@@ -0,0 +1,110 @@
<template>
<transition-component group enter-class="animate__animated animate__fadeInUp animate__delay-1 animate__faster p-r-30" leave-class="animate__animated animate__fadeOutDown animate__faster p-r-30" style="min-height: 300px;width:100%">
<loading-component style="height: 200px; top: 0;" key="1" color="success" v-show="$store.getters.isLoading(section)"></loading-component>
<div class="row" key="2" v-show="!$store.getters.isLoading(section)">
<div class="col">
<div class="row">
<div class="col">
<div class="row align-items-center justify-content-center p-t-50 p-b-50" v-show="!$store.getters.getListData(section).length && !$store.getters.isLoading(section) && emptyListSection">
<div class="col-10">
<div class="row align-items-center justify-content-center hint-text">
<div class="col-4 hint-text"><img src="/images/not-found-illustration.png" class="w-100 hint-text"/></div>
</div>
<div class="row text-center">
<div class="col">
<div class="row m-t-20">
<div class="col">
<p class="all-caps no-margin fs-11" style="letter-spacing: 2px;">Nothing To Show Here</p>
</div>
</div>
<div class="row m-t-5 align-items-center justify-content-center">
<div class="col">
<small class="fs-9 muted all-caps font-lato" style="letter-spacing: 2px">There is no results found, Try adjusting your filters to find what you are looking for.</small>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="list disable-text-selection" data-check-all="checkAll">
<div class="row" ref="list" v-for="item in $store.getters.getListData(section)" v-bind:key="item.id" :data="item">
<div class="col">
<slot name="list" :data="item"></slot>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col">
<pagination-component :section="section" class="mb-5" ref="pagination"></pagination-component>
</div>
</div>
</div>
</div>
</div>
</div>
</transition-component>
</template>
<script>
export default {
props: {
section:{
type: String,
required: true
},
endpoint: {
type: String,
required: true
},
options: {
default () {
return {}
}
},
emptyListSection: {
type: Boolean,
default: true
}
},
data(){
return {
filters: this.options
}
},
created(){
this.setDecoratorDefault();
this.$store.dispatch('updateListQueue', {'name': this.section, 'page': 1, 'filters': this.filters});
},
computed: {
pendingList () {
return this.$store.getters.isInCompleteQueue(this.section);
}
},
watch: {
pendingList(inComplete){
if(inComplete){
this.fetchList();
}
}
},
methods: {
fetchList(){
let listDecorators = this.$store.getters.getListDetails(this.section);
this.submit(this.endpoint + '?page=' + listDecorators.page + '&filters=' + JSON.stringify(listDecorators.filters), 'get', this.section, false, false)
},
updateFilters(filters){
this.filters = filters;
this.setDecoratorDefault();
this.submit(this.endpoint + '?page=1&filters=' + JSON.stringify(this.filters), 'get', this.section, false, false)
},
successHandler(response){
this.$store.dispatch('completeList', {'name': this.section, 'data': response.payload.data});
this.$refs.pagination.makePagination(response.payload.meta, response.payload.links);
},
}
}
</script>
@@ -0,0 +1,38 @@
<template>
<div class="row align-items-center justify-content-center w-100" style="left: 15px;">
<div class="col">
<hollow-dots-spinner :animation-duration="1000" :dots-num="5" :color="getColor" class="m-auto"></hollow-dots-spinner>
</div>
</div>
</template>
<script>
import { HollowDotsSpinner } from 'epic-spinners';
export default {
props: {
color: {
type: String,
default: 'primary'
}
},
components: {
HollowDotsSpinner
},
computed: {
getColor(){
switch (this.color) {
case 'primary':
return '#912873';
case 'success':
return '#349128';
case 'danger':
return '#F3201F';
case 'white':
return '#ffffff';
case 'black':
return '#000000'
}
}
}
}
</script>
@@ -0,0 +1,28 @@
<template>
<div class="modal modalContainer fade" :class="styleType" :data-type="type">
<div class="modal-dialog" v-bind:class="[{'modal-lg': size === 'large'}, {'modal-xl': size === 'extra-large'}, {'modal-sm': size === 'small'}]">
<div class="modal-content">
<div class="modal-body">
<slot></slot>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
type: {
type: String,
},
size: {
type: String,
default: ''
},
styleType: {
type: String,
default: "stick-up"
}
}
}
</script>
@@ -0,0 +1,68 @@
<template>
<div class="row no-margin" v-if="Object.keys(pagination).length > 0">
<div class="col no-padding">
<div class="row justify-content-end" v-if="pagination.last_page !== 1">
<div class="col-auto b-a p-t-5 p-b-5 m-l-5 pointer b-grey pointer" @click="callPage(1)" v-if="pagination.current_page !== 1 && !pageNumbers().includes(1)">
<i class="fa fa-angle-double-left fs-14 muted lh-16"></i>
</div>
<div class="col-auto b-a p-t-5 p-b-5 m-l-5" v-for="n in pageNumbers()" @click="callPage(n)" :class="[{'b-grey': n !== pagination.current_page}, {'pointer': n !== pagination.current_page}, {'b-complete': n === pagination.current_page}, {'bg-complete': n === pagination.current_page}]">
<small class="fs-11" :class="[{'muted': n !== pagination.current_page}, {'text-white': n === pagination.current_page}, {'bold': n === pagination.current_page}]">{{n}}</small>
</div>
<div class="col-auto b-a p-t-5 p-b-5 m-l-5 pointer b-grey pointer" @click="callPage(pagination.last_page)" v-if="pagination.current_page !== pagination.last_page && !pageNumbers().includes(pagination.last_page)">
<i class="fa fa-angle-double-right fs-14 muted lh-16"></i>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
section:{
type: String,
required: true
}
},
data(){
return {
pagination: {}
}
},
methods: {
makePagination(pagination){
this.pagination = pagination;
},
callPage(page){
if(page !== this.pagination.current_page){
this.$store.dispatch('updateListQueue', {'name': this.section, 'page': page, 'filters': this.$store.getters.getListDetails(this.section).filters});
}
},
pageNumbers(){
let pages = 5;
let numbers = [],
partition = (pages - 1) / 2,
previousOverflow = -(this.pagination.current_page - partition - 1),
nextOverflow = -(this.pagination.last_page - (this.pagination.current_page + partition)),
previous = partition + (nextOverflow > 0 ? nextOverflow : 0),
next = partition + (previousOverflow > 0 ? previousOverflow : 0);
for (let i = this.pagination.current_page - previous; i < this.pagination.current_page; i++) {
if(i >= 1) {
numbers.push(i);
}
}
numbers.push(this.pagination.current_page);
for (let i = this.pagination.current_page + 1; i <= (this.pagination.current_page + next); i++) {
if(i <= this.pagination.last_page) {
numbers.push(i);
}
}
return numbers
}
}
}
</script>
@@ -0,0 +1,56 @@
<!-- <template>
<div>
<div class="row">
<div class="col-sm-4">
<a :href="fileUrl">
<canvas ref="canvas" />
</a>
</div>
</div>
</div>
</template>
<script>
import * as pdfjsLib from 'pdfjs-dist/es5/build/pdf.js';
pdfjsLib.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjsLib.version}/pdf.worker.js`;
export default {
props: {
fileUrl: {
type: String,
},
width: {
type: Number,
default: 200,
},
height: {
type: Number,
default: 200,
},
},
mounted() {
this.renderThumbnails()
},
methods: {
async renderThumbnails() {
const worker = new pdfjsLib.PDFWorker();
let pdf = await pdfjsLib
.getDocument({ data: this.src, worker: worker })
.promise.then((pdf) => pdf);
const page = await pdf.getPage(1);
let viewport = page.getViewport({ scale: 1.0 });
viewport = page.getViewport({ scale: this.width / viewport.width });
let canvas = $(this.$refs.canvas);
canvas.height = viewport.height;
canvas.width = viewport.width;
const context = canvas.getContext('2d');
await page.render({ canvasContext: context, viewport: viewport })
},
},
}
</script> -->
@@ -0,0 +1,81 @@
<template>
<div class="row">
<div class="col">
<div class="row">
<div class="col">
<div class="row">
<div class="col">
<img class="w-100" src="/images/search-illustration.png" />
</div>
</div>
</div>
</div>
<div class="row no-margin hint-text">
<div class="col bg-master-lightest p-b-15 hint-text">
<div class="row m-b-15 p-t-10 p-b-10 bg-master-lighter">
<div class="col">
<small class="all-caps muted fs-10">Filters</small>
</div>
<div class="col-auto">
<div class="row align-items-center text-info pointer">
<div class="col-auto p-r-0"><small class="all-caps fs-10">Advance</small></div>
<div class="col-auto p-l-0"><i class="fa fa-chevron-down fs-8 m-l-5" style=" margin-bottom: 3px; "></i></div>
</div>
</div>
</div>
<user-filters-component ref="filters_form"></user-filters-component>
<div class="row m-t-15">
<div class="col">
<div class="bg-transparent text-center b-success b-a text-success fs-10 all-caps bold b-rad-none p-t-10 p-b-10 p-r-25 p-l-25 pointer" @click="updateFilters()">
Apply filters
</div>
</div>
</div>
<div class="row m-t-10 text-center">
<div class="col">
<small class="all-caps fs-9 text-danger pointer" @click="resetForm();updateFilters()">Clear
Filters
</small>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
section: {
type: String,
required: true
}
},
data(){
return {
filters: {},
}
},
methods:{
updateFilters(){
this.$store.getters.isInQueue(this.section) ? this.filters = this.$store.getters.getListDetails(this.section).filters : this.setDecoratorDefault();
let vm = this;
$.each(this.$refs.filters_form.parameters, function(key, value) {
value ? (vm.filters[key] = value) : (key in vm.filters && delete vm.filters[key]);
});
this.$store.dispatch('updateListQueue', {'name': this.section, 'page': 1, 'filters': this.filters});
},
resetForm(){
if(!this.$refs.filters_form.data) {
Object.assign(this.$refs.filters_form.$data, this.$refs.filters_form.$options.data.call(this));
}
}
}
}
</script>
@@ -0,0 +1,58 @@
<template>
<component :is="type"
:tag="tag"
:enter-active-class="enterClass"
:leave-active-class="leaveClass"
v-on="hooks">
<slot></slot>
</component>
</template>
<script>
export default {
props: {
speed: {
type: String,
default: 'normal'
},
enterClass: {
type: String,
default: 'slide-in-right'
},
leaveClass: {
type: String,
default: 'slide-out-right'
},
group: {
type: Boolean,
default: false
},
tag: {
type: String,
default: "div"
}
},
computed: {
type() {
return this.group ? "transition-group" : "transition";
},
hooks() {
return {
beforeEnter: this.setAbsolutePosition,
afterEnter: this.cleanUp,
beforeLeave: this.setAbsolutePosition,
afterLeave: this.cleanUp
};
}
},
methods: {
setAbsolutePosition(el){
el.style.width = "calc(100% + 30px)";
el.style.position = "absolute";
},
cleanUp(el) {
el.style.width = "";
el.style.position = "";
}
}
};
</script>
@@ -0,0 +1,35 @@
<template>
<div v-if="validator.$error" class="text-danger">
<small class="bold" v-for="(object, param) in validator.$params">
<span v-if="object.type === 'minLength'">{{object.min}} characters</span>
<span v-if="object.type === 'minValue'">{{object.min}}</span>
<span v-if="object.type === 'sameAs'">{{object.eq}} field</span>
</small>
</div>
</template>
<script>
export default {
props: {
validator: {
required: true
}
},
data(){
return {
errorMessages:{
required: 'this field is required',
email: 'enter a valid email address',
minLength: 'this field must have at least',
sameAs: 'this field must match the',
minValue: 'this field must at least be',
},
}
},
computed: {
Validation(){
return this.validator;
}
}
}
</script>
@@ -0,0 +1,24 @@
<template>
<div class="row bear parentContainer">
<div class="col">
<div class="absolute" style="width: 50px;top: 73px;right: 15px;"><img src="/images/easter-egg.png" class="w-100 pointer requestModal" data-type="openBear" ></div>
<modal-component class="animate__animated animate__fast animate__fadeIn" size="small" styleType="fill-in" type="openBear">
<div class="row">
<div class="col p-t-50 p-b-50">
</div>
</div>
</modal-component>
</div>
</div>
</template>
<script>
import ModalComponent from "./ModalComponent";
export default {
components: {ModalComponent},
methods:{
}
}
</script>
@@ -0,0 +1,53 @@
<template>
<div class="row no-margin">
<div class="col b-a " :class="[{'b-grey': !validator.$error}, {'b-danger': validator.$error}]">
<div class="row align-items-center b-b b-grey b-dashed">
<div class="col p-t-10 p-b-10">
<slot name="label"></slot>
</div>
<div class="col-auto">
<div class="row align-items-center">
<div class="col-auto no-padding">
<validation-error-component :validator="validator"></validation-error-component>
</div>
<div class="col-auto">
<div class="fs-12 icon-thumbnail btn-rounded icon-25 m-r-0" :class="[{'bg-master-lightest': !validator.$error}, {'bg-danger': validator.$error}, {'text-white': validator.$error}]" v-show="!files.length">!</div>
<div class="bg-success fs-11 text-white icon-thumbnail btn-rounded icon-25 m-r-0" v-show="!!files.length">
<i class="fa fa-check fs-11"></i>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col p-t-15 p-b-15">
<div class="row" v-show="!files.length">
<div class="col">
<slot name="tips"></slot>
</div>
</div>
<file-upload-component v-model="files" :value="value" v-on:input="$emit('input', $event)"></file-upload-component>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
value: {
type: Array,
required: false
},
validator: {
required: true
}
},
data(){
return {
files: []
}
}
}
</script>
@@ -0,0 +1,150 @@
<template>
<div class="dropzone no-border no-padding text-center" style="min-height: auto;">
<div class="dz-message hide"></div>
<div class="dragzone row m-l-0 m-r-0 bg-master-lightest" :class="[{'m-b-15': hasFile}]" style="border-width: 1px;">
<div class="col">
<loading-component style="height: 200px; top: 0;" color="success" v-show="isLoading"></loading-component>
<div class="row" v-show="!isLoading">
<div class="col">
<div class="row p-b-20 p-t-15" v-show="!hasFile" style="min-height: 150px;">
<div class="col">
<div class="row justify-content-center m-b-10 m-t-10">
<div class="col-auto">
<div class="icon-thumbnail bg-transparent">
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
viewBox="0 0 172 172"
style=" fill:#000000;"><defs><linearGradient x1="86" y1="79.28125" x2="86" y2="149.85769" gradientUnits="userSpaceOnUse" id="color-1_48264_gr1"><stop offset="0" stop-color="#4ec9ff"></stop><stop offset="1" stop-color="#2bffe6"></stop></linearGradient><linearGradient x1="86" y1="19.48438" x2="86" y2="131.01831" gradientUnits="userSpaceOnUse" id="color-2_48264_gr2"><stop offset="0" stop-color="#009add"></stop><stop offset="1" stop-color="#00baa4"></stop></linearGradient></defs><g fill="none" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><path d="M0,172v-172h172v172z" fill="none"></path><g><path d="M104.8125,104.8125l-16.60337,-23.71987c-1.075,-1.53456 -3.34594,-1.53456 -4.41825,0l-16.60338,23.71988h13.4375v40.3125c0,1.4835 1.204,2.6875 2.6875,2.6875h5.375c1.4835,0 2.6875,-1.204 2.6875,-2.6875v-40.3125z" fill="url(#color-1_48264_gr1)"></path><path d="M137.60269,67.97763c1.41362,-3.66575 2.14731,-7.53037 2.14731,-11.54013c0,-17.78319 -14.46681,-32.25 -32.25,-32.25c-13.87287,0 -25.95319,8.82306 -30.41444,21.55912c-0.16394,-0.13437 -0.34937,-0.23919 -0.516,-0.36819c-0.52406,-0.40581 -1.05888,-0.79281 -1.61519,-1.15563c-0.35206,-0.22844 -0.7095,-0.44344 -1.06963,-0.65306c-0.52137,-0.301 -1.05619,-0.57781 -1.60175,-0.84119c-0.31712,-0.15319 -0.62619,-0.3225 -0.95137,-0.45956c-0.8385,-0.36012 -1.70119,-0.66919 -2.58537,-0.93256c-0.29025,-0.086 -0.58588,-0.1505 -0.87881,-0.22575c-0.69875,-0.18006 -1.40825,-0.33325 -2.13119,-0.44881c-0.301,-0.05106 -0.59663,-0.10213 -0.90031,-0.13706c-0.99438,-0.12631 -1.99681,-0.21231 -3.02344,-0.21231c-13.33537,0 -24.1875,10.84944 -24.1875,24.1875v8.0625c-11.85456,0 -21.5,9.64544 -21.5,21.5c0,11.85456 9.64544,21.5 21.5,21.5h2.6875v2.6875c0,4.44512 3.61738,8.0625 8.0625,8.0625h24.1875v-5.375h-24.1875c-1.48081,0 -2.6875,-1.204 -2.6875,-2.6875v-2.6875h26.875v-5.375h-34.9375c-8.89294,0 -16.125,-7.23206 -16.125,-16.125c0,-8.89294 7.23206,-16.125 16.125,-16.125h10.75v-5.375h-5.375v-8.0625c0,-10.37106 8.43875,-18.8125 18.8125,-18.8125c0.7955,0 1.57756,0.06719 2.35156,0.16394c0.23112,0.02956 0.45956,0.06719 0.688,0.1075c0.56975,0.09406 1.12875,0.21231 1.68238,0.35475c0.22037,0.05644 0.44075,0.10481 0.65844,0.16931c0.69338,0.20694 1.37063,0.44881 2.03175,0.73369c0.23381,0.10213 0.45956,0.22306 0.688,0.33325c0.44613,0.215 0.88688,0.44344 1.31419,0.69069c0.26337,0.15319 0.52406,0.30906 0.77669,0.473c0.47569,0.30906 0.93794,0.63963 1.38406,0.99169c0.19081,0.1505 0.38431,0.29831 0.56975,0.45688c0.50525,0.43 0.98631,0.88687 1.44319,1.37063c0.14781,0.15588 0.28756,0.31444 0.43,0.473c0.47837,0.5375 0.93525,1.0965 1.3545,1.69312c0.02419,0.03225 0.04838,0.06181 0.06987,0.09406c0.48375,0.69875 0.92181,1.43781 1.31419,2.21181c1.30612,2.55313 2.05594,5.43413 2.05594,8.49519h5.375c0,-3.913 -0.95406,-7.59756 -2.60956,-10.86825l0.00806,-0.00269c-0.01613,-0.02956 -0.03494,-0.05644 -0.05106,-0.086c-0.4945,-0.96481 -1.04006,-1.89738 -1.6555,-2.78425c-0.05644,-0.08331 -0.12363,-0.15856 -0.18275,-0.24188c-0.05106,-0.06987 -0.10481,-0.13975 -0.15587,-0.20962c2.81919,-12.09106 13.60144,-20.74481 26.14669,-20.74481c14.81888,0 26.875,12.05613 26.875,26.875c0,3.77056 -0.80088,7.3745 -2.29512,10.7715l-8.4495,-0.0215l-0.01344,5.375l8.44144,0.0215c10.1695,0.19888 18.44163,8.62956 18.44163,18.791c0,10.37106 -8.43875,18.8125 -18.8125,18.8125h-32.25v5.375h26.875v2.6875c0,1.4835 -1.20669,2.6875 -2.6875,2.6875h-24.1875v5.375h24.1875c4.44512,0 8.0625,-3.61738 8.0625,-8.0625v-2.6875c13.33538,0 24.1875,-10.84944 24.1875,-24.1875c0,-11.18537 -7.80181,-20.71256 -18.27231,-23.39737z" fill="url(#color-2_48264_gr2)"></path></g></g></svg>
</div>
</div>
</div>
<div class="row m-b-10">
<div class="col">
<div class="all-caps fs-12 hint-text" style="letter-spacing: 1px;">Drag and drop files here</div>
</div>
</div>
<div class="row m-b-10 justify-content-center">
<div class="col-4">
<div class="row align-items-center">
<div class="col b-t b-grey"></div>
<div class="col-auto all-caps fs-10 hint-text muted">Or</div>
<div class="col b-t b-grey"></div>
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="btn btn-sm btn-outline-complete b-rad-none pointer select-btn hint-text">Browse files</div>
</div>
</div>
</div>
</div>
<div class="row text-left" v-show="hasFile">
<div class="col p-b-15 p-t-15">
<div class="all-caps fs-12 hint-text" style="letter-spacing: 1px;">Drag and drop files here</div>
</div>
<div class="col-2 no-padding">
<div class="btn btn-xs btn-primary btn-block b-rad-none pointer select-btn h-100">
<div class="row align-items-center h-100">
<div class="col">
<i class="fa fa-plus"></i>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
value: {
type: Array,
required: false
}
},
data(){
return {
isLoading: false,
hasFile: false,
files: []
}
},
mounted(){
let vm = this;
var dropzone = new Dropzone(this.$el, {
url: '#',
autoQueue: false,
processQueue: false,
acceptedFiles: 'image/*, application/pdf',
uploadMultiple: true,
clickable: '.select-btn',
previewTemplate: '<div class="row m-l-0 m-r-0 align-items-center m-t-5 m-b-5 bg-master-lightest text-left p-t-10 p-b-10 "> <div class="col-auto p-r-0"> <img data-dz-thumbnail style="width: 35px; height: 35px;" /> </div> <div class="col"> <div class="row m-b-5"> <div class="col"> <div class="dz-filename fs-8 bold"><span data-dz-name></span></div> </div> </div> <div class="row"> <div class="col"> <div class="dz-size muted light fs-10" data-dz-size></div> </div> </div> </div> <div class="col-auto"><i class="fs-16 fa fa-times-circle pointer hint-text" data-dz-remove></i></div> </div>'
});
dropzone.autoDiscover = false;
dropzone.on("removedfile", function() {
vm.updateFiles(dropzone.files);
});
dropzone.on("addedfile", function(file) {
vm.isLoading = true;
if(file.name.split('.').pop() === 'pdf'){
$(file.previewElement).closest("img[data-dz-thumbnail]").attr("src", "/images/icons/pdf.png");
}
if(file.name.split('.').pop().indexOf("xls") !== -1){
$(file.previewElement).closest("img[data-dz-thumbnail]").attr("src", "/images/icons/xlsx.png");
}
Promise.all(dropzone.files.map(function(file){
return vm.fileToBase64(file).then(function(data){
return data;
})
})).then(function(files) {
vm.isLoading = false;
vm.updateFiles(files);
})
});
dropzone.on("dragover", function() {
$(vm.$el).closest('.dragzone').css('opacity', 0.5)
});
dropzone.on("dragleave", function() {
$(vm.$el).closest('.dragzone').css('opacity', 1)
});
dropzone.on("drop", function() {
$(vm.$el).closest('.dragzone').css('opacity', 1)
});
},
methods: {
fileToBase64(file) {
return new Promise(resolve => {
var reader = new FileReader();
reader.onload = function(event) {
resolve(event.target.result);
};
reader.readAsDataURL(file);
});
},
updateFiles(files){
this.hasFile = !!files.length;
this.files = files;
this.$emit('input', files)
}
}
}
</script>
@@ -0,0 +1,31 @@
<template>
<modal-component class="animate__animated animate__fast animate__fadeInDownBig" :size="size" :type="data ? 'editModal' : 'createModal'">
<transition-component group enter-class="animate__animated animate__fadeInDown animate__faster" leave-class="animate__animated animate__fadeOutUp animate__faster">
<loading-component style="height: 300px; top: 0;" key="1" color="success" v-show="$store.getters.isLoading(section+'.form')" ></loading-component>
<div class="row" key="2" v-show="!$store.getters.isLoading(section+'.form')">
<div class="col">
<slot name="form" :section="section" :data="data"></slot>
</div>
</div>
</transition-component>
</modal-component>
</template>
<script>
export default {
props: {
section: {
type: String,
required: true
},
'size': {
type: String,
default: ''
},
data: {
type: Object,
default: null
}
}
}
</script>
@@ -0,0 +1,50 @@
<template>
<select class="form-control">
<option disabled></option>
</select>
</template>
<script>
import PerfectScrollbar from 'perfect-scrollbar';
export default {
props: {
options: {
type: Array,
required: true
},
value: {
required: false
}
},
mounted(){
let vm = this;
$(this.$el).select2({
data: this.options,
minimumResultsForSearch: 6,
theme: 'bootstrap',
containerCssClass: 'form-control',
}).val(this.value).trigger("change").on('change', function(){
vm.$emit('input', this.value);
}).on('select2:open', function(){
$('.select2-results__options').scrollbar().addClass('scrollbar-macosx')
})
},
watch: {
value: function(value){
$(this.$el).val(value).trigger('change');
},
options: function(options){
$(this.$el).select2({ data: options });
this.value ? $(this.$el).val(this.value).trigger('change'):null;
}
},
destroyed: function(){
$(this.$el).off().select2('destroy')
}
}
</script>
<style>
.select2-results__options {
position: relative;
max-height: 200px
}
</style>
@@ -0,0 +1,54 @@
<template>
<select-component :options="$store.getters.getSelectableList(section)" :value="value" @input="(val) => {$emit('input', val)}"></select-component>
</template>
<script>
export default {
props: {
value: {
required: false
},
section: {
type: String,
required: true
},
endpoint: {
type: String,
required: true
},
labelColumn: {
type: Array,
required: true
},
valueColumn: {
type: String,
required: true
}
},
created(){
if(!this.$store.getters.isInQueue(this.section)){
this.$store.dispatch('updateListQueue', {name: this.section});
this.$store.dispatch('crudRequest', {endpoint: this.endpoint, method: 'get'}).then(response => {
let success = response.ok;
response.json().then(response => {
if(!success){return;}
let vm = this;
let mappedList = $.map(response.payload.data, function(value){
let preservedValue = value;
return {'id': !isNaN(value[vm.valueColumn]) ? parseInt(value[vm.valueColumn]) : value[vm.valueColumn],
'text': vm.labelColumn.map(function(label){
return preservedValue[label]
}).join(': ')
};
});
this.$store.dispatch('completeList', {name: this.section, data: mappedList})
});
})
}
}
}
</script>
@@ -0,0 +1,32 @@
<template>
<div v-if="validator.$error" class="text-danger fs-10">
<small class="bold" v-for="(object, param) in validator.$params" v-if="!validator[param]">
{{errorMessages[param]}}
<span v-if="object.type === 'minLength'">{{object.min}} characters</span>
<span v-if="object.type === 'sameAs'">{{object.eq}} field</span>
</small>
</div>
</template>
<script>
export default {
props: {
validator: {
required: true
}
},
data(){
return {
errorMessages:{
required: 'this field is required',
email: 'enter a valid email address',
minLength: 'this field must have at least',
sameAs: 'this field must match the'
},
}
},
methods: {
}
}
</script>
@@ -0,0 +1,30 @@
<template>
<div class="animate__animated" :class="[{'animate__shake': validator.$error}]">
<div class="row">
<div class="col">
<div class="form-group no-margin form-group-default" :class="[{' has-error': validator.$error}, {'form-group-default-select2': selecatable}, {'p-b-5': selecatable}]">
<slot></slot>
</div>
</div>
</div>
<div class="row m-t-5" v-show="validator.$error">
<div class="col">
<validation-error-component :validator="validator"></validation-error-component>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
validator: {
required: true
},
selecatable: {
type: Boolean,
default: false
}
}
}
</script>
@@ -0,0 +1,129 @@
@extends('layouts.base_login')
@section('inner_content')
<div class="row h-100">
<div class="col bg-white">
<div class="row h-100 no-margin align-items-center justify-content-center">
<div class="col-12 col-md-8" v-show="!$store.getters.isShowing('registrationForm')">
<div class="row m-b-30">
<div class="col-5">
<img class="w-75" src="https://www.izyim.com/images/logo.png" alt="">
</div>
</div>
<div class="row" v-show="!$store.getters.isShowing('forgetPassword')">
<div class="col">
<loading-component style="height: 350px;" key="1" color="primary" v-show="$store.getters.isLoading('loginSection')"></loading-component>
<div class="row" v-show="!$store.getters.isLoading('loginSection')">
<div class="col">
<div class="row m-b-15">
<div class="col">
<div class="inline v-align-middle">
<div class="font-heading fs-20 all-caps no-margin lh-28 bold">Sign In</div>
<p class="no-margin fs-11 light">To keep using the service please sign in with your personal info</p>
</div>
</div>
</div>
<div class="row">
<div class="col">
<login-form-component section="loginSection"></login-form-component>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row" v-show="$store.getters.isShowing('forgetPassword')">
<div class="col">
<loading-component style="height: 350px;" key="1" color="primary" v-show="$store.getters.isLoading('forgetPasswordSection')"></loading-component>
<div class="row" v-show="!$store.getters.isLoading('forgetPasswordSection')">
<div class="col">
<div class="row m-b-15" v-show="!$store.getters.isShowing('forgetPasswordSuccess')">
<div class="col">
<div class="inline v-align-middle">
<div class="font-heading fs-20 all-caps no-margin lh-28 bold">Forget Password</div>
<p class="no-margin fs-11 light">Enter your registered email below to receive the password reset instruction</p>
</div>
</div>
</div>
<div class="row">
<div class="col">
<forget-password-form-component section="forgetPasswordSection"></forget-password-form-component>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col h-100 bg-info-primary-gradient">
<div class="row h-100 align-items-center justify-content-center">
<div class="absolute hint-text dotted-grid" style="width: 250px; height: 142px; bottom: 0; right: 0; "></div>
<div class="absolute hint-text dotted-grid" style="width: 200px; height: 135px; top: 140px; left: 100px;"></div>
<div class="col-7">
<div class="carousel slide" data-ride="carousel">
<div class="carousel-inner">
<div class="row align-items-center justify-content-center">
<div class="col">
<div class="carousel-item active">
<div class="row">
<div class="col bg-white">
<div class="row justify-content-center">
<div class="col-8">
<img class="w-100" src="https://image.freepik.com/free-vector/transportation-parcel-carton-box-container-qr-code-closed-parcel-box-package-paper-box-package-service_257312-49.jpg" alt="">
</div>
</div>
</div>
</div>
<div class="row">
<div class="col text-center text-white">
<h5 class="bold text-white">SKU-Level Accountability</h5>
<p class="fs-12">We make your business goals our own, working directly with your team. Our platform tracks shipment level activity and communication to give you complete accountability, across every stage of your supply chain down to the individual SKU.</p>
</div>
</div>
</div>
<div class="carousel-item">
<div class="row">
<div class="col bg-white">
<div class="row justify-content-center">
<div class="col-8">
<img class="w-100" src="https://image.freepik.com/free-vector/transportation-parcel-carton-box-container-qr-code-closed-parcel-box-package-paper-box-package-service_257312-49.jpg" alt="">
</div>
</div>
</div>
</div>
<div class="row">
<div class="col text-center text-white">
<h5 class="bold text-white">SKU-Level Accountability</h5>
<p class="fs-12">We make your business goals our own, working directly with your team. Our platform tracks shipment level activity and communication to give you complete accountability, across every stage of your supply chain down to the individual SKU.</p>
</div>
</div>
</div>
<div class="carousel-item">
<div class="row">
<div class="col bg-white">
<div class="row justify-content-center">
<div class="col-8">
<img class="w-100" src="https://image.freepik.com/free-vector/transportation-parcel-carton-box-container-qr-code-closed-parcel-box-package-paper-box-package-service_257312-49.jpg" alt="">
</div>
</div>
</div>
</div>
<div class="row">
<div class="col text-center text-white">
<h5 class="bold text-white">SKU-Level Accountability</h5>
<p class="fs-12">We make your business goals our own, working directly with your team. Our platform tracks shipment level activity and communication to give you complete accountability, across every stage of your supply chain down to the individual SKU.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
+1 -1
View File
@@ -27,7 +27,7 @@ Route::group(['prefix' => 'swagger'], function () {
});
Route::get('', function () {
return view('welcome');//temporary showing welcome page.
return view('pages.accounts.login');//temporary showing welcome page.
})->name('login');
Route::get('/account/email/verification/{token}', function ($token) {