fix filter and ...

master
sajjad 3 years ago
parent 0b535dc2ce
commit 623b825769

18
package-lock.json generated

@ -4554,6 +4554,11 @@
"integrity": "sha1-P7rwIL/XlIhAcuomsel5HUWmKfA=",
"dev": true
},
"dropzone": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/dropzone/-/dropzone-5.9.3.tgz",
"integrity": "sha512-Azk8kD/2/nJIuVPK+zQ9sjKMRIpRvNyqn9XwbBHNq+iNuSccbJS6hwm1Woy0pMST0erSo0u4j+KJaodndDk4vA=="
},
"duplexer": {
"version": "0.1.2",
"resolved": "https://registry.npm.taobao.org/duplexer/download/duplexer-0.1.2.tgz?cache=0&sync_timestamp=1597221020457&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fduplexer%2Fdownload%2Fduplexer-0.1.2.tgz",
@ -11548,6 +11553,14 @@
"integrity": "sha1-HuO8mhbsv1EYvjNLsV+cRvgvWCU=",
"dev": true
},
"vue2-dropzone": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/vue2-dropzone/-/vue2-dropzone-3.6.0.tgz",
"integrity": "sha512-YXC1nCWIZvfa98e/i6h+EshZCkFSxFEh0Sxr9ODfThAPPDVhAzLLlz/4XIx0NGO1QeSy6htwSstte47R7vVhLQ==",
"requires": {
"dropzone": "^5.5.1"
}
},
"vuetify": {
"version": "2.5.8",
"resolved": "https://registry.nlark.com/vuetify/download/vuetify-2.5.8.tgz?cache=0&sync_timestamp=1630370704981&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fvuetify%2Fdownload%2Fvuetify-2.5.8.tgz",
@ -12294,6 +12307,11 @@
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
"dev": true
},
"willatoast": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/willatoast/-/willatoast-1.1.1.tgz",
"integrity": "sha512-tf37LFQSErMh2+apOlQZAdan00MaqKeDAE2SEmglHzU+dQi3ykNy1VXSuDYmE3BQ3PSLKVwzBB9tItCC2+FXew=="
},
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npm.taobao.org/word-wrap/download/word-wrap-1.2.3.tgz",

@ -22,8 +22,10 @@
"vue-advanced-cropper": "^1.8.2",
"vue-meta": "^2.4.0",
"vue-router": "^3.5.2",
"vue2-dropzone": "^3.6.0",
"vuetify": "^2.4.0",
"vuex": "^3.6.2"
"vuex": "^3.6.2",
"willatoast": "^1.1.1"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",

@ -1,5 +0,0 @@
import { getArray } from '../resources/programSerieWorkoutsResource';
export default class ProgramSerieWorkoutsRepository {
}

@ -3,13 +3,20 @@ import url from "@/router/url";
import { getArray, setQuery } from "../resources/usersResource";
export default class UsersRepository {
async index(data) {
async indexUsers(data) {
let params = setQuery(data)
let response = await axios.get(url('indexUsers'), { params })
if (response.status === 200) {
return getArray(response.data)
}
}
async loadTrainerTrainee(data) {
let params = setQuery(data)
let response = await axios.get(url('indexTrainerTrainee'), { params })
if (response.status === 200) {
return getArray(response.data)
}
}
async delete(userId) {
await axios.delete(url("destroyUser", { user: userId }));
}

@ -3,7 +3,6 @@ import url from "@/router/url";
import { getJson, getArray, setQuery, setData } from "../resources/workoutResource.js";
export default class WorkoutToSerieRepository {
async index(data) {
console.log(data);
let response = await axios.get(url("indexSerieWorkouts", { serie: data.serieId, course: data.courseId }));
if (response.status === 200) {
return getArray(response.data);

@ -184,13 +184,7 @@
<v-col cols="12">
<div class="upload">
<div class="add__product dark w-100 h-100">
<div class="add__workout__picture d-flex align-center">
<i class="WMi-picture add__workout__picture--icon"></i>
<div class="add__workout__picture--text">
please upload or drag & Drop <br />
product images here
</div>
</div>
<Dropzone :batchId="random_token" />
</div>
</div>
</v-col>
@ -226,15 +220,20 @@ import { mapActions, mapGetters } from "vuex";
import SectionTitle from "../Global/Section/SectionTitle.vue";
import FileRepository from "../../abstraction/repository/FileRepository";
import ImageCropper from "../Global/Input/ImageCropper.vue";
import Dropzone from "../Global/Input/Dropzone.vue";
import toast from "@/utils/toast";
import { makeid } from "@/utils/math";
const RANDOM_TOKEN = makeid(50);
//
export default {
components: {
SectionTitle,
ImageCropper,
Dropzone,
},
data: () => ({
random_token: RANDOM_TOKEN,
form: {
batch_id: RANDOM_TOKEN,
},
@ -276,9 +275,8 @@ export default {
async submit() {
try {
let valid = this.$refs.form.validate();
console.log(valid);
if (valid) {
if (this.fileForm.media !== this.fileForm.media) {
if (this.fileForm.media) {
let repository = new FileRepository();
await repository.store(this.fileForm);
}
@ -287,6 +285,8 @@ export default {
} else {
this.addProduct(this.form);
}
} else {
toast.error("The information entered is incorrect", "Error");
}
} catch (e) {
return e;
@ -320,53 +320,4 @@ export default {
padding-right: 100px !important;
padding-left: 100px !important;
}
.add__workout__picture {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.add__workout__picture--text {
width: max-content;
line-height: 18px;
text-transform: uppercase;
}
.add__workout__picture--icon {
font-size: 40px;
margin-right: 20px;
}
.upload {
height: 148px;
}
</style>
<style>
.vue-treeselect {
margin-top: 7px;
}
.vue-treeselect__menu-container {
color: var(--color-black) !important;
}
.vue-treeselect__control {
padding-left: 5 px;
padding-right: 5 px;
display: table;
table-layout: fixed;
width: 100%;
height: 36 px;
border-color: rgb(255, 255, 255);
border-style: solid;
border-width: 0 0 1px 0;
border-radius: 0;
background: transparent;
transition-duration: 200ms;
transition-property: border-color, box-shadow, width, height, background-color,
opacity;
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
.vue-treeselect__single-value {
color: var(--color-white);
}
.vue-treeselect__placeholder {
text-transform: uppercase;
}
</style>

@ -1,27 +0,0 @@
<template>
<div class="h-100">
<main-back height="100%">
<div class="mt-16">
<ul class="pl-0 ml-0">
<MenuItem text="Home" />
<MenuItem text="my profile" />
<MenuItem text="my programs" />
<MenuItem text="my trainee" />
<MenuItem text="my bookmarks" />
<MenuItem :active="true" text="products" />
<MenuItem text="admins" />
<MenuItem text="traniners" />
<MenuItem text="workouts" />
</ul>
</div>
</main-back>
</div>
</template>
<script>
import MenuItem from "../Global/Section/MenuItem.vue";
export default {
components: {
MenuItem,
},
};
</script>

@ -1,27 +0,0 @@
<template>
<div class="h-100">
<main-back height="100%">
<div class="mt-16">
<ul class="pl-0 ml-0">
<MenuItem text="Home" />
<MenuItem text="my profile" />
<MenuItem :active="true" text="my programs" />
<MenuItem text="my trainee" />
<MenuItem text="my bookmarks" />
<MenuItem text="products" />
<MenuItem text="admins" />
<MenuItem text="traniners" />
<MenuItem text="workouts" />
</ul>
</div>
</main-back>
</div>
</template>
<script>
import MenuItem from "../Global/Section/MenuItem.vue";
export default {
components: {
MenuItem,
},
};
</script>

@ -1,27 +0,0 @@
<template>
<div class="h-100">
<main-back height="100%">
<div class="mt-16">
<ul class="pl-0 ml-0">
<MenuItem text="Home" />
<MenuItem text="my profile" />
<MenuItem text="my programs" />
<MenuItem text="my trainee" />
<MenuItem text="my bookmarks" />
<MenuItem text="products" />
<MenuItem text="admins" />
<MenuItem text="traniners" />
<MenuItem :active="true" text="workouts" />
</ul>
</div>
</main-back>
</div>
</template>
<script>
import MenuItem from "../Global/Section/MenuItem.vue";
export default {
components: {
MenuItem,
},
};
</script>

@ -6,7 +6,7 @@
<div>
<SectionTitle
backText="home page"
link="dashboardTrainee"
link="dashboard"
icon="WMi-left-open"
title="my bookmarks"
subTitle="let us know you better, it comes handy."

@ -1,27 +0,0 @@
<template>
<div class="h-100">
<main-back height="100%">
<div class="mt-16">
<ul class="pl-0 ml-0">
<MenuItem text="Home" />
<MenuItem text="my profile" />
<MenuItem text="my programs" />
<MenuItem text="my trainee" />
<MenuItem :active="true" text="my bookmarks" />
<MenuItem text="products" />
<MenuItem text="admins" />
<MenuItem text="traniners" />
<MenuItem text="workouts" />
</ul>
</div>
</main-back>
</div>
</template>
<script>
import MenuItem from "../Global/Section/MenuItem.vue";
export default {
components: {
MenuItem,
},
};
</script>

@ -0,0 +1,126 @@
<template>
<div>
<vue-dropzone
ref="myVueDropzone"
id="dropzone"
:destroyDropzone="false"
@vdropzone-sending="setParams"
@vdropzone-removed-file="removeFile"
:options="dropzoneOptions"
@vdropzone-success="responseSuccess"
>
</vue-dropzone>
</div>
</template>
<script>
import vue2Dropzone from "vue2-dropzone";
import { TokenStorage } from "@/utils/storage";
import url from "@/router/url";
import axios from "axios";
import "vue2-dropzone/dist/vue2Dropzone.min.css";
export default {
props: {
defaultMessage: {
default:
"<div class='add__workout__picture d-flex align-center'> <i class='WMi-picture add__workout__picture--icon'></i> <div class='add__workout__picture--text'> please upload or drag & Drop <br /> product images here</div></div>",
},
files: { default: () => [] },
collection: { default: "image" },
modelName: { default: "model" },
batchId: {
type: String,
default: "asdfghjklqwertyuiopmnbvcxasdfghjklqwertyuiopmnbvcx",
},
},
components: {
vueDropzone: vue2Dropzone,
},
data() {
return {
dropzoneOptions: {
url: "https://app.champya-dev.ir" + url("storeFile"),
thumbnailWidth: 200,
headers: {
authorization: `Bearer ${TokenStorage.getToken()}`,
"accept-language": "en",
},
addRemoveLinks: true,
dictDefaultMessage: this.defaultMessage,
sendingMultiple: true,
removeType: "server",
paramName: "media",
},
};
},
methods: {
responseSuccess(file, response) {
if (response.data && response.data.id) {
file["id"] = response.data.id;
this.$emit("success", response.data);
}
},
removeFile(file) {
if (this.dropzoneOptions.removeType == "server") {
axios.delete(url("destroyFile", { media: file.id }));
}
},
manuallyLoadFiles(files) {
//file =[ {size: 123, name: "Icon", type: "image/png", url: "https://myvizo.com/img/logo_sm.png"}]
if (Array.isArray(files) && files.length) {
for (const file of files) {
this.$refs.myVueDropzone.manuallyAddFile(
{
name: file.file_name,
type: file.mime_type,
id: file.id,
size: file.size,
},
file.thumbnail
);
}
}
},
manuallyRemoveAllFiles() {
this.dropzoneOptions.removeType = "client";
this.$refs.myVueDropzone.removeAllFiles();
this.dropzoneOptions.removeType = "server";
},
setParams(file, xhr, formData) {
formData.append("batch_id", this.batchId);
formData.append("collection", this.collection);
},
},
watch: {
files(files) {
this.manuallyRemoveAllFiles();
this.manuallyLoadFiles(files);
},
},
};
</script>
<style>
.vue-dropzone {
border: none;
background: var(--color-black);
border-radius: 5px;
display: flex;
justify-content: center;
align-items: center;
}
.add__workout__picture {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.add__workout__picture--text {
width: max-content;
line-height: 18px;
text-transform: uppercase;
}
.add__workout__picture--icon {
font-size: 40px;
margin-right: 20px;
}
</style>

@ -5,22 +5,25 @@
:width="width"
:transition="transition"
dark
:tag="tag"
>
<main-back height="100%" :is-modal="true">
<v-card class="wa__modal">
<div class="wa__modal-header">
<slot name="header" :modal="modal" :data="data" v-if="modal"></slot>
</div>
<v-card-text class="wa__modal-content pb-0">
<slot :modal="modal" :data="data" v-if="modal"></slot>
</v-card-text>
<template v-if="!notFooter">
<v-divider class="mb-0"></v-divider>
</template>
<v-card-actions class="wa__modal-footer px-0">
<slot name="footer" :modal="modal" :data="data" v-if="modal"></slot>
</v-card-actions>
</v-card>
<component :is="tag === 'form' ? 'v-form' : 'div'">
<v-card class="wa__modal">
<div class="wa__modal-header">
<slot name="header" :modal="modal" :data="data" v-if="modal"></slot>
</div>
<v-card-text class="wa__modal-content pb-0">
<slot :modal="modal" :data="data" v-if="modal"></slot>
</v-card-text>
<template v-if="!notFooter">
<v-divider class="mb-0"></v-divider>
</template>
<v-card-actions class="wa__modal-footer px-0">
<slot name="footer" :modal="modal" :data="data" v-if="modal"></slot>
</v-card-actions>
</v-card>
</component>
</main-back>
</v-dialog>
</template>
@ -28,7 +31,6 @@
<script>
import { mapGetters } from "vuex";
export default {
props: {
width: { default: null },
@ -38,6 +40,9 @@ export default {
notFooter: {
default: false,
},
tag: {
default: "div",
},
},
data: () => ({
isOpenModal: false,

@ -6,20 +6,20 @@
<template v-if="role === 'admin'">
<MenuItem :active="true" text="Home" link="dashboard" />
<MenuItem text="my profile" link="profile" />
<MenuItem text="my bookmarks" link="dashboard" />
<MenuItem text="my bookmarks" link="bookmarks" />
<MenuItem text="programs" link="programs" />
<MenuItem text="users" link="users" />
<MenuItem text="products" link="products" />
<MenuItem text="workouts" link="workouts" />
</template>
<template v-if="role === 'trainee'">
<MenuItem :active="true" text="Home" link="dashboardTrainee" />
<MenuItem :active="true" text="Home" link="dashboard" />
<MenuItem text="my profile" link="profile" />
<MenuItem text="my programs" link="trainPrograms" />
<MenuItem text="my bookmarks" link="bookmarks" />
</template>
<template v-if="role === 'trainer'">
<MenuItem :active="true" text="Home" link="dashboardTrainer" />
<MenuItem :active="true" text="Home" link="dashboard" />
<MenuItem text="my profile" link="profile" />
<MenuItem text="my programs" link="trainPrograms" />
<MenuItem text="my trainees" link="users" />

@ -1,27 +0,0 @@
<template>
<div class="h-100">
<main-back height="100%">
<div class="mt-16">
<ul class="pl-0 ml-0">
<MenuItem text="Home" />
<MenuItem text="my profile" />
<MenuItem text="my programs" />
<MenuItem text="my trainee" />
<MenuItem text="my bookmarks" />
<MenuItem :active="true" text="products" />
<MenuItem text="admins" />
<MenuItem text="traniners" />
<MenuItem text="workouts" />
</ul>
</div>
</main-back>
</div>
</template>
<script>
import MenuItem from "../Global/Section/MenuItem.vue";
export default {
components: {
MenuItem,
},
};
</script>

@ -5,7 +5,7 @@
<div>
<SectionTitle
backText="home page"
link="dashboardTrainee"
link="dashboard"
icon="WMi-left-open"
title="my profile"
subTitle="let us know you better, it comes handy."

@ -1,27 +0,0 @@
<template>
<div class="h-100">
<main-back height="100%">
<div class="mt-16">
<ul class="pl-0 ml-0">
<MenuItem text="Home" />
<MenuItem :active="true" text="my profile" />
<MenuItem text="my programs" />
<MenuItem text="my trainee" />
<MenuItem text="my bookmarks" />
<MenuItem text="products" />
<MenuItem text="admins" />
<MenuItem text="traniners" />
<MenuItem text="workouts" />
</ul>
</div>
</main-back>
</div>
</template>
<script>
import MenuItem from "../Global/Section/MenuItem.vue";
export default {
components: {
MenuItem,
},
};
</script>

@ -17,7 +17,7 @@
</div>
</v-col>
<v-col cols="3">
<div class="d-flex align-center mt-n4">
<div class="d-flex align-center justify-center mt-n4">
<div class="series__per__week--quantity wa__f__m__eb mr-2">
{{ series.repeat }}
</div>
@ -28,7 +28,7 @@
</div>
</v-col>
<v-col cols="3">
<div class="d-flex align-center mt-n4">
<div class="d-flex align-center justify-center mt-n4">
<div class="series__per__week--quantity wa__f__m__eb mr-2">
{{ series.workouts_count ? series.workouts_count : 0 }}
</div>
@ -110,5 +110,9 @@ export default {
text-transform: uppercase;
letter-spacing: 5px;
margin-top: 8px;
white-space: nowrap;
text-overflow: ellipsis;
word-wrap: break-word;
overflow: hidden;
}
</style>

@ -1,27 +0,0 @@
<template>
<div class="h-100">
<main-back height="100%">
<div class="mt-16">
<ul class="pl-0 ml-0">
<MenuItem text="Home" />
<MenuItem text="my profile" />
<MenuItem :active="true" text="my programs" />
<MenuItem text="my trainee" />
<MenuItem text="my bookmarks" />
<MenuItem text="products" />
<MenuItem text="admins" />
<MenuItem text="traniners" />
<MenuItem text="workouts" />
</ul>
</div>
</main-back>
</div>
</template>
<script>
import MenuItem from "../Global/Section/MenuItem.vue";
export default {
components: {
MenuItem,
},
};
</script>

@ -55,7 +55,7 @@
</div>
</main-back>
<div class="text-center">
<FiltersModal />
<FiltersModal @filter="load" />
</div>
</div>
</template>
@ -82,9 +82,12 @@ export default {
this.loadPrograms();
}
},
async load() {
await this.loadPrograms();
},
},
created() {
this.loadPrograms();
this.load();
},
};
</script>

@ -14,43 +14,59 @@
/>
</div>
<div class="mt-4 mb-10">
<div class="my-6">
<div>
<v-text-field
class="no-error-msg"
placeholder="course name"
label="course name"
></v-text-field>
<v-form @submit.prevent="filterPrograms">
<div class="my-6">
<div>
<v-text-field
class="no-error-msg"
placeholder="course name"
label="course name"
v-model="filter.title.val"
></v-text-field>
</div>
</div>
</div>
<div class="my-6">
<div>
<v-text-field
class="no-error-msg pt-0"
placeholder="mentor name"
label="mentor name"
></v-text-field>
<div class="my-6">
<div>
<v-text-field
class="no-error-msg pt-0"
placeholder="mentor name"
label="mentor name"
v-model="filter.first_name.val"
></v-text-field>
</div>
</div>
</div>
<div class="my-6">
<div>
<v-autocomplete
class="no-error-msg pt-0"
placeholder="status"
label="status"
></v-autocomplete>
<div class="my-6">
<div>
<v-autocomplete
class="no-error-msg pt-0"
placeholder="status"
label="status"
:items="programStatus"
item-text="text"
item-value="verified"
v-model="filter.verified.val"
></v-autocomplete>
</div>
</div>
</div>
<div class="my-6">
<div>
<DateInput class="no-error-msg" label="date, after" />
<div class="my-6">
<div>
<DateInput
class="no-error-msg"
label="date, after"
v-model="filter.created_at.val1"
/>
</div>
</div>
</div>
<div class="my-6">
<div>
<DateInput class="no-error-msg" label="date, before" />
<div class="my-6">
<div>
<DateInput
class="no-error-msg"
label="date, before"
v-model="filter.created_at.val2"
/>
</div>
</div>
</div>
</v-form>
</div>
</template>
<template #footer>
@ -64,13 +80,15 @@
size="large"
:is-modal="true"
height="29"
@click.native="$_closeModal()"
@click.native="clearFilter"
/>
<RectangleButton
height="29"
class="btn__modal--execute custom-btn wa__f__m__eb"
text="execute"
icon="WMi-filter"
type="submit"
@click.native="filterPrograms"
/>
</div>
</template>
@ -78,8 +96,59 @@
</template>
<script>
import SectionTitle from "../../Global/Section/SectionTitle.vue";
import { cloneDeep } from "lodash";
import { mapMutations } from "vuex";
const defaultFilter = {
title: {
type: "like",
val: null,
},
first_name: {
type: "like",
val: null,
},
verified: {
type: "in",
val: null,
},
created_at: {
type: "between",
val1: null,
val2: null,
},
};
export default {
name: "modal_filters",
components: { SectionTitle },
data: () => ({
filter: cloneDeep(defaultFilter),
programStatus: [
{
id: "1",
text: "verified",
verified: "true",
},
{
id: "2",
text: "not verified",
verified: "false",
},
],
}),
methods: {
...mapMutations("programs", ["SET_FILTER_PROGRAMS"]),
filterPrograms() {
console.log(this.filter);
this.SET_FILTER_PROGRAMS(this.filter);
this.$emit("filter");
this.$_closeModal();
},
clearFilter() {
this.filter = cloneDeep(defaultFilter);
this.SET_FILTER_PROGRAMS(this.filter);
this.$emit("filter");
this.$_closeModal();
},
},
};
</script>

@ -1,27 +0,0 @@
<template>
<div class="h-100">
<main-back height="100%">
<div class="mt-16">
<ul class="pl-0 ml-0">
<MenuItem text="Home" />
<MenuItem text="my profile" />
<MenuItem :active="true" text="my programs" />
<MenuItem text="my trainee" />
<MenuItem text="my bookmarks" />
<MenuItem text="products" />
<MenuItem text="admins" />
<MenuItem text="traniners" />
<MenuItem text="workouts" />
</ul>
</div>
</main-back>
</div>
</template>
<script>
import MenuItem from "../Global/Section/MenuItem.vue";
export default {
components: {
MenuItem,
},
};
</script>

@ -6,7 +6,7 @@
<div>
<SectionTitle
backText="home"
link="dashboardTrainee"
link="dashboard"
icon="WMi-left-open"
title="my programs"
subTitle="There are programs you started in Champya Application, for more details and stats please use the application."

@ -1,22 +0,0 @@
<template>
<div class="h-100">
<main-back height="100%">
<div class="mt-16">
<ul class="pl-0 ml-0">
<MenuItem text="Home" />
<MenuItem text="my profile" />
<MenuItem :active="true" text="my programs" />
<MenuItem text="my bookmarks" />
</ul>
</div>
</main-back>
</div>
</template>
<script>
import MenuItem from "../Global/Section/MenuItem.vue";
export default {
components: {
MenuItem,
},
};
</script>

@ -1,86 +0,0 @@
<template>
<div class="h-100">
<main-back height="100%">
<div class="px-16 pb-10">
<div class="mt-11">
<div class="d-flex justify-center"><UserName role="trainee" /></div>
</div>
<v-row class="mt-3">
<v-col cols="12">
<div class="">
<div class="text-left description">
here is your dashboard home, feel free navigate from right side
menu or choose from shortcuts we prepared for you.
</div>
</div>
</v-col>
</v-row>
<div class="mb-16 mt-10">
<div class="d-sm-grid d-flex justify-center">
<div class="mr-5 section">
<box text="bookmarks" link="bookmarks" icon="WMi-bookmark" />
</div>
<div class="mr-5 section">
<box text="programs" link="trainPrograms" icon="WMi-align-left" />
</div>
<div class="mr-5 section">
<box text="profile" link="profile" icon="WMi-user" />
</div>
</div>
</div>
<v-divider dark></v-divider>
<v-row class="mt-3">
<v-col cols="12">
<div class="d-flex justify-center pr-16">
<div class="text-left description">
and here is some stats we hope it gives you a great overview of
your status
</div>
</div>
</v-col>
</v-row>
<div class="mx-md-16 mx-0 d-flex justify-center">
<div>
<div class="mr-16">
<Notification text="programs joined" quantity="4" />
</div>
</div>
<div>
<div class="ml-16">
<Notification text="moves done" quantity="344" />
</div>
</div>
</div>
</div>
</main-back>
</div>
</template>
<script>
import Box from "../Global/Section/Box.vue";
import Notification from "../Global/Section/Notification.vue";
import UserName from "../Global/Section/UserName.vue";
export default {
components: {
UserName,
Box,
Notification,
},
};
</script>
<style scoped>
.section {
width: 157px;
height: 157px;
}
.description {
color: var(--color-gray);
font-size: 26px;
margin-left: 150px;
}
@media screen and (max-width: 1264px) {
.description {
margin-left: 0;
}
}
</style>

@ -1,22 +0,0 @@
<template>
<div class="h-100">
<main-back height="100%">
<div class="mt-16">
<ul class="pl-0 ml-0">
<MenuItem :active="true" text="Home" link="dashboardTrainee" />
<MenuItem text="my profile" link="profile" />
<MenuItem text="my programs" link="trainPrograms" />
<MenuItem text="my bookmarks" link="bookmarks" />
</ul>
</div>
</main-back>
</div>
</template>
<script>
import MenuItem from "../Global/Section/MenuItem.vue";
export default {
components: {
MenuItem,
},
};
</script>

@ -1,88 +0,0 @@
<template>
<div class="h-100">
<main-back height="100%">
<div class="px-16 pb-10">
<div class="mt-11">
<div class="d-flex justify-center"><UserName role="trainer" /></div>
</div>
<v-row class="mt-3">
<v-col cols="12">
<div class="">
<div class="text-left description">
here is your dashboard home, feel free navigate from right side
menu or choose from shortcuts we prepared for you.
</div>
</div>
</v-col>
</v-row>
<div class="mb-16 mt-10">
<div class="d-sm-grid d-flex justify-center">
<div class="mr-5 section">
<box text="programs" link="programs" icon="WMi-align-left" />
</div>
<div class="mr-5 section">
<box text="bookmarks" link="bookmarks" icon="WMi-bookmark" />
</div>
<div class="mr-5 section">
<box text="trainees" link="users" icon=" WMi-users" />
</div>
<div class="mr-5 section">
<box text="profile" link="profile" icon="WMi-user" />
</div>
</div>
</div>
<v-divider dark></v-divider>
<v-row class="mt-3">
<v-col cols="12">
<div class="d-flex justify-center pr-16">
<div class="text-left description">
and here is some stats we hope it gives you a great overview of
your status
</div>
</div>
</v-col>
</v-row>
<div class="mx-md-16 mx-0 d-flex justify-center">
<div>
<div class="mr-16">
<Notification text="programs joined" quantity="4" />
</div>
</div>
<div>
<div class="ml-16">
<Notification text="moves done" quantity="344" />
</div>
</div>
</div>
</div>
</main-back>
</div>
</template>
<script>
import Box from "../Global/Section/Box.vue";
import Notification from "../Global/Section/Notification.vue";
import UserName from "../Global/Section/UserName.vue";
export default {
components: {
UserName,
Box,
Notification,
},
};
</script>
<style scoped>
.section {
width: 157px;
height: 157px;
}
.description {
color: var(--color-gray);
font-size: 26px;
margin-left: 150px;
}
@media screen and (max-width: 1264px) {
.description {
margin-left: 0;
}
}
</style>

@ -1,23 +0,0 @@
<template>
<div class="h-100">
<main-back height="100%">
<div class="mt-16">
<ul class="pl-0 ml-0">
<MenuItem :active="true" text="Home" link="dashboardTrainer" />
<MenuItem text="my profile" link="profile" />
<MenuItem text="my programs" link="trainPrograms" />
<MenuItem text="my trainees" link="users" />
<MenuItem text="my bookmarks" link="bookmarks" />
</ul>
</div>
</main-back>
</div>
</template>
<script>
import MenuItem from "../Global/Section/MenuItem.vue";
export default {
components: {
MenuItem,
},
};
</script>

@ -12,7 +12,7 @@
</div>
</v-col>
<v-col cols="3">
<div class="d-flex align-center h-100">
<div class="d-flex align-center justify-center h-100">
<div class="user__role">
<small>Role:</small>
<div class="wa__f__m__eb text-uppercase">
@ -22,7 +22,7 @@
</div>
</v-col>
<v-col cols="3">
<div class="d-flex align-center h-100">
<div class="d-flex align-center justify-center h-100">
<div v-if="userRole == 'trainer'" class="d-flex align-center">
<div class="user__program--quantity wa__f__m__eb mr-2">
{{ user.created_courses_count }}

@ -35,7 +35,9 @@
/>
</div>
</main-back>
<div class="text-center"><ChangeRoleModal /><FiltersModal /></div>
<div class="text-center">
<ChangeRoleModal /><FiltersModal @filter="load" />
</div>
</div>
</template>
<script>
@ -44,6 +46,8 @@ import ChangeRoleModal from "./Modals/ChangeRoleModal.vue";
import FiltersModal from "./Modals/FiltersModal.vue";
import UserItem from "./Item.vue";
import { mapActions, mapGetters, mapMutations } from "vuex";
import { UserStorage } from "@/utils/storage";
export default {
components: {
SectionTitle,
@ -51,11 +55,14 @@ export default {
ChangeRoleModal,
FiltersModal,
},
data: () => ({
role: UserStorage.get() ? UserStorage.get().role : null,
}),
computed: {
...mapGetters("users", ["getUsers", "getPaginationUser"]),
},
methods: {
...mapActions("users", ["loadUsers"]),
...mapActions("users", ["loadUsers", "loadTrainerTrainee"]),
...mapMutations("users", ["SET_PAGINATION"]),
changePagination(page) {
if (this.getPaginationUser.page !== page) {
@ -63,9 +70,14 @@ export default {
this.loadUsers();
}
},
async load() {
this.role === "admin"
? await this.loadUsers()
: await this.loadTrainerTrainee();
},
},
created() {
this.loadUsers();
this.load();
},
};
</script>

@ -20,6 +20,7 @@
class="no-error-msg"
placeholder="user name"
label="user name"
v-model="filter.first_name.val"
></v-text-field>
</div>
</div>
@ -34,12 +35,20 @@
</div>
<div class="my-6">
<div>
<DateInput class="no-error-msg" label="joined date, after" />
<DateInput
class="no-error-msg"
label="joined date, after"
v-model="filter.created_at.val1"
/>
</div>
</div>
<div class="my-6">
<div>
<DateInput class="no-error-msg" label="joined date, before" />
<DateInput
class="no-error-msg"
label="joined date, before"
v-model="filter.created_at.val2"
/>
</div>
</div>
</div>
@ -55,13 +64,14 @@
size="large"
:is-modal="true"
height="29"
@click.native="$_closeModal()"
@click.native="clearFilter"
/>
<RectangleButton
height="29"
class="btn__modal--execute custom-btn wa__f__m__eb"
text="execute"
icon="WMi-filter"
@click.native="filterUser"
/>
</div>
</template>
@ -69,8 +79,38 @@
</template>
<script>
import SectionTitle from "../../Global/Section/SectionTitle.vue";
import { mapMutations } from "vuex";
import { cloneDeep } from "lodash";
const defaultFilter = {
first_name: {
type: "like",
val: null,
},
created_at: {
type: "between",
val1: null,
val2: null,
},
};
export default {
name: "modal_filters",
components: { SectionTitle },
data: () => ({
filter: cloneDeep(defaultFilter),
}),
methods: {
...mapMutations("users", ["SET_FILTER_USER"]),
filterUser() {
this.SET_FILTER_USER(this.filter);
this.$emit("filter");
this.$_closeModal();
},
clearFilter() {
this.filter = cloneDeep(defaultFilter);
this.SET_FILTER_USER(this.filter);
this.$emit("filter");
this.$_closeModal();
},
},
};
</script>

@ -1,27 +0,0 @@
<template>
<div class="h-100">
<main-back height="100%">
<div class="mt-16">
<ul class="pl-0 ml-0">
<MenuItem text="Home" />
<MenuItem text="my profile" />
<MenuItem text="my programs" />
<MenuItem text="my trainee" />
<MenuItem text="my bookmarks" />
<MenuItem text="products" />
<MenuItem text="admins" />
<MenuItem :active="true" text="traniners" />
<MenuItem text="workouts" />
</ul>
</div>
</main-back>
</div>
</template>
<script>
import MenuItem from "../Global/Section/MenuItem.vue";
export default {
components: {
MenuItem,
},
};
</script>

@ -50,7 +50,7 @@
/>
</div>
</main-back>
<div class="text-center"><FiltersModal /></div>
<div class="text-center"><FiltersModal @filter="load" /></div>
</div>
</template>
<script>
@ -76,9 +76,12 @@ export default {
this.loadWorkouts();
}
},
load() {
this.loadWorkouts();
},
},
created() {
this.loadWorkouts();
this.load();
},
};
</script>

@ -20,6 +20,7 @@
class="no-error-msg"
placeholder="workout name"
label="workout name"
v-model="filter.name.val"
></v-text-field>
</div>
</div>
@ -29,26 +30,26 @@
class="no-error-msg pt-0"
placeholder="mentor name"
label="mentor name"
v-model="filter.first_name.val"
></v-text-field>
</div>
</div>
<div class="my-6">
<div>
<v-autocomplete
class="no-error-msg pt-0"
placeholder="status"
label="status"
></v-autocomplete>
</div>
</div>
<div class="my-6">
<div>
<DateInput class="no-error-msg" label="date, after" />
<DateInput
class="no-error-msg"
label="date, after"
v-model="filter.created_at.val1"
/>
</div>
</div>
<div class="my-6">
<div>
<DateInput class="no-error-msg" label="date, before" />
<DateInput
class="no-error-msg"
label="date, before"
v-model="filter.created_at.val2"
/>
</div>
</div>
</div>
@ -64,13 +65,14 @@
size="large"
:is-modal="true"
height="29"
@click.native="$_closeModal()"
@click.native="clearFilter"
/>
<RectangleButton
height="29"
class="btn__modal--execute custom-btn wa__f__m__eb"
text="execute"
icon="WMi-filter"
@click.native="filterWorkotus"
/>
</div>
</template>
@ -78,8 +80,44 @@
</template>
<script>
import SectionTitle from "../../Global/Section/SectionTitle.vue";
import { cloneDeep } from "lodash";
import { mapMutations } from "vuex";
const defaultFilter = {
name: {
type: "like",
val: null,
},
first_name: {
type: "like",
val: null,
},
created_at: {
type: "between",
val1: null,
val2: null,
},
};
export default {
name: "modal_filters",
components: { SectionTitle },
data: () => ({
filter: cloneDeep(defaultFilter),
}),
methods: {
...mapMutations("workouts", ["SET_FILTER_WORKOUTS"]),
filterWorkotus() {
this.SET_FILTER_WORKOUTS(this.filter);
this.$emit("filter");
this.$_closeModal();
},
clearFilter() {
this.filter = cloneDeep(defaultFilter);
this.SET_FILTER_WORKOUTS(this.filter);
this.$emit("filter");
this.$_closeModal();
},
},
};
</script>

@ -1,27 +0,0 @@
<template>
<div class="h-100">
<main-back height="100%">
<div class="mt-16">
<ul class="pl-0 ml-0">
<MenuItem text="Home" />
<MenuItem text="my profile" />
<MenuItem text="my programs" />
<MenuItem text="my trainee" />
<MenuItem text="my bookmarks" />
<MenuItem text="products" />
<MenuItem text="admins" />
<MenuItem text="traniners" />
<MenuItem :active="true" text="workouts" />
</ul>
</div>
</main-back>
</div>
</template>
<script>
import MenuItem from "../Global/Section/MenuItem.vue";
export default {
components: {
MenuItem,
},
};
</script>

@ -1,27 +0,0 @@
<template>
<div class="h-100">
<main-back height="100%">
<div class="mt-16">
<ul class="pl-0 ml-0">
<MenuItem text="Home" />
<MenuItem text="my profile" />
<MenuItem :active="true" text="my programs" />
<MenuItem text="my trainee" />
<MenuItem text="my bookmarks" />
<MenuItem text="products" />
<MenuItem text="admins" />
<MenuItem text="traniners" />
<MenuItem text="workouts" />
</ul>
</div>
</main-back>
</div>
</template>
<script>
import MenuItem from "../Global/Section/MenuItem.vue";
export default {
components: {
MenuItem,
},
};
</script>

@ -16,7 +16,7 @@ export default [
},
{
path: '/',
view: 'AdminHome',
view: 'Dashboard',
name: 'dashboard'
},
{

@ -47,6 +47,7 @@ const urls = {
// users
indexUsers: "admin/users",
destroyUser: "admin/users/:user",
indexTrainerTrainee: 'trainer/trainees',
// countries
indexCountries: "countries",
// profile
@ -62,7 +63,8 @@ const urls = {
indexStatisticTrainer: "trainer-dashboard-statistic",
indexStatisticTrainee: "trainee-dashboard-statistic",
// file
storeFile: 'media'
storeFile: 'media',
destroyFile: 'media/:media'
};
export default urlGenerator(urls);

@ -2,7 +2,7 @@ import ProgramRepository from "@/abstraction/repository/programRepository";
export default {
async loadPrograms({ state, commit }) {
try {
let data = { pagination: state.pagination };
let data = { pagination: state.pagination, filters: state.filters };
let repository = new ProgramRepository();
const resource = await repository.index(data);
commit("SET_PROGRAMS", resource.data);

@ -10,6 +10,10 @@ export default {
pagination = { ...state.pagination, ...pagination };
Vue.set(state, "pagination", pagination);
},
SET_FILTER_PROGRAMS(state, payload) {
Vue.set(state, "filters", payload);
state.pagination.page = 1
},
ADD_PROGRAM(state, payload) {
state.programs.push(payload);
},

@ -4,4 +4,5 @@ export default {
pagination: {
itemsPerPage: 12
},
filters: {}
};

@ -1,9 +1,16 @@
import UsersRepository from "@/abstraction/repository/usersRepository";
export default {
async loadUsers({ state, commit }) {
let data = { pagination: state.pagination, filters: state.filters }
let repository = new UsersRepository();
const resource = await repository.indexUsers(data);
commit("SET_USERS", resource.data);
commit("SET_PAGINATION", resource.pagination);
},
async loadTrainerTrainee({ state, commit }) {
let data = { pagination: state.pagination }
let repository = new UsersRepository();
const resource = await repository.index(data);
const resource = await repository.loadTrainerTrainee(data);
commit("SET_USERS", resource.data);
commit("SET_PAGINATION", resource.pagination);
},

@ -7,6 +7,10 @@ export default {
pagination = { ...state.pagination, ...pagination };
Vue.set(state, "pagination", pagination);
},
SET_FILTER_USER(state, payload) {
Vue.set(state, "filters", payload);
state.pagination.page = 1
},
DELETE_USER(state, userId) {
const index = state.users.findIndex((x) => x.id === userId);
// state.users.splice(index, 1);

@ -2,5 +2,6 @@ export default {
users: [],
pagination: {
itemsPerPage: 12
}
},
filters: {}
};

@ -11,6 +11,7 @@ export default {
},
SET_FILTER_WORKOUTS_TO_SERIE(state, payload) {
Vue.set(state, "filters", payload);
state.pagination.page = 1
},
ADD_WORKOUT_TO_SERIE(state, payload) {
state.workouts.push(payload);

@ -2,7 +2,7 @@ import WorkoutRepository from "@/abstraction/repository/workoutRepository";
export default {
async loadWorkouts({ state, commit }) {
try {
let data = { pagination: state.pagination };
let data = { pagination: state.pagination, filters: state.filters };
let repository = new WorkoutRepository();
const resource = await repository.index(data);
commit("SET_WORKOUTS", resource.data);

@ -10,6 +10,10 @@ export default {
pagination = { ...state.pagination, ...pagination };
Vue.set(state, "pagination", pagination);
},
SET_FILTER_WORKOUTS(state, payload) {
Vue.set(state, "filters", payload);
state.pagination.page = 1
},
ADD_WORKOUT(state, payload) {
state.workouts.push(payload);
},

@ -4,4 +4,5 @@ export default {
pagination: {
itemsPerPage: 12
},
filters: {}
};

@ -247,8 +247,6 @@ textarea {
input::placeholder {
text-transform: uppercase;
}
/* -------------------- button on modal ------------------------------*/
/* -------------------- button on modal ------------------------------*/
.close__modal {
position: absolute;
@ -268,3 +266,11 @@ input::placeholder {
padding: 0 45px !important;
font-size: 14px !important;
}
/* -------------------- toast ------------------------------*/
.willaToast-message {
font-family: "Montserrat-regular" !important;
}
.willaToast.willaToast-color-black > .willaToast-body .willaToast-title {
font-family: "cizel" !important;
color: var(--color-social-yellow) !important;
}

@ -1,22 +1,42 @@
import "izitoast/dist/css/iziToast.min.css";
import iZtoast from "izitoast";
import "willatoast/dist/main.css";
import willaToast from "willatoast";
const toast = {
error: (message, title = "Error") => {
return iZtoast.error({
return willaToast.normal({
title: title,
titleColor: "#ffd600",
message: message,
rtl: true,
position: "bottomCenter"
});
},
success: (message, title = "Success") => {
return iZtoast.success({
return willaToast.normal({
title: title,
message: message,
rtl: true,
position: "bottomCenter"
});
},
question: (message, title = "Success", callback) => {
return willaToast.normal({
title: title,
message: message,
position: "center",
timeout: false,
theme: 'dark',
buttons: [
['<button style="border: 1px dashed white;" >yes</button>', function (instance, toast) {
callback();
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
}, true],
['<button>no</button>', function (instance, toast) {
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
}]
],
});
}
};

@ -11,7 +11,7 @@
<div>
<v-row>
<v-col cols="2">
<AddProductSections />
<SideBar />
</v-col>
<v-col cols="10">
<AddProductHome />
@ -23,11 +23,9 @@
</template>
<script>
import AddProductHome from "../components/AddProduct/Main";
import AddProductSections from "../components/AddProduct/Sections";
export default {
components: {
AddProductHome,
AddProductSections,
},
};
</script>

@ -11,7 +11,7 @@
<div>
<v-row>
<v-col cols="2">
<AddProgramSections />
<SideBar />
</v-col>
<v-col cols="10">
<AddProgram />
@ -23,11 +23,9 @@
</template>
<script>
import AddProgram from "../components/AddProgram/Main";
import AddProgramSections from "../components/AddProgram/Sections";
export default {
components: {
AddProgram,
AddProgramSections,
},
};
</script>

@ -11,7 +11,7 @@
<div>
<v-row>
<v-col cols="2">
<AddWorkoutSections />
<SideBar />
</v-col>
<v-col cols="10">
<AddWorkoutHome />
@ -23,11 +23,9 @@
</template>
<script>
import AddWorkoutHome from "../components/AddWorkout/Main";
import AddWorkoutSections from "../components/AddWorkout/Sections";
export default {
components: {
AddWorkoutHome,
AddWorkoutSections,
},
};
</script>

@ -1,33 +0,0 @@
<template>
<v-container fluid>
<header class="pt-3">
<v-row>
<v-col cols="12">
<site-header></site-header>
</v-col>
</v-row>
</header>
<main class="pb-10 mt-5">
<div>
<v-row>
<v-col cols="2">
<TraineeSections />
</v-col>
<v-col cols="10">
<TraineeHome />
</v-col>
</v-row>
</div>
</main>
</v-container>
</template>
<script>
import TraineeHome from "../components/Trainee/Main";
import TraineeSections from "../components/Trainee/Sections";
export default {
components: {
TraineeHome,
TraineeSections,
},
};
</script>

@ -1,33 +0,0 @@
<template>
<v-container fluid>
<header class="pt-3">
<v-row>
<v-col cols="12">
<site-header></site-header>
</v-col>
</v-row>
</header>
<main class="pb-10 mt-5">
<div>
<v-row>
<v-col cols="2">
<TrainerSections />
</v-col>
<v-col cols="10">
<TrainerHome />
</v-col>
</v-row>
</div>
</main>
</v-container>
</template>
<script>
import TrainerHome from "../components/Trainer/Main";
import TrainerSections from "../components/Trainer/Sections";
export default {
components: {
TrainerHome,
TrainerSections,
},
};
</script>

@ -11,7 +11,7 @@
<div>
<v-row>
<v-col cols="2">
<BookmarksSections />
<SideBar />
</v-col>
<v-col cols="10">
<BookmarksHome />
@ -23,11 +23,9 @@
</template>
<script>
import BookmarksHome from "../components/Bookmarks/Main";
import BookmarksSections from "../components/Bookmarks/Sections";
export default {
components: {
BookmarksHome,
BookmarksSections,
},
};
</script>

@ -23,11 +23,9 @@
</template>
<script>
import AdminHome from "../components/Dashboard/Main";
// import AdminSections from "../components/Admin/Sections";
export default {
components: {
AdminHome,
// AdminSections,
},
};
</script>

@ -11,7 +11,7 @@
<div>
<v-row>
<v-col cols="2">
<ProductsSections />
<SideBar />
</v-col>
<v-col cols="10">
<ProductsHome />
@ -23,11 +23,9 @@
</template>
<script>
import ProductsHome from "../components/Products/Main";
import ProductsSections from "../components/Products/Sections";
export default {
components: {
ProductsHome,
ProductsSections,
},
};
</script>

@ -11,7 +11,7 @@
<div>
<v-row>
<v-col cols="2">
<ProfileSections />
<SideBar />
</v-col>
<v-col cols="10">
<ProfileHome />
@ -23,11 +23,9 @@
</template>
<script>
import ProfileHome from "../components/Profile/Main";
import ProfileSections from "../components/Profile/Sections";
export default {
components: {
ProfileHome,
ProfileSections,
},
};
</script>

@ -11,7 +11,7 @@
<div>
<v-row>
<v-col cols="2">
<ProgramSeriesSections />
<SideBar />
</v-col>
<v-col cols="10">
<ProgramSeriesHome />
@ -23,11 +23,9 @@
</template>
<script>
import ProgramSeriesHome from "../components/ProgramSeries/Main";
import ProgramSeriesSections from "../components/ProgramSeries/Sections";
export default {
components: {
ProgramSeriesHome,
ProgramSeriesSections,
},
};
</script>

@ -11,7 +11,7 @@
<div>
<v-row>
<v-col cols="2">
<ProgramsSections />
<SideBar />
</v-col>
<v-col cols="10">
<ProgramsHome />
@ -23,11 +23,9 @@
</template>
<script>
import ProgramsHome from "../components/Programs/Main";
import ProgramsSections from "../components/Programs/Sections";
export default {
components: {
ProgramsHome,
ProgramsSections,
},
};
</script>

@ -11,7 +11,7 @@
<div>
<v-row>
<v-col cols="2">
<TrainProgramsSections />
<SideBar />
</v-col>
<v-col cols="10">
<TrainProgramsHome />
@ -23,11 +23,9 @@
</template>
<script>
import TrainProgramsHome from "../components/TrainPrograms/Main";
import TrainProgramsSections from "../components/TrainPrograms/Sections";
export default {
components: {
TrainProgramsHome,
TrainProgramsSections,
},
};
</script>

@ -11,7 +11,7 @@
<div>
<v-row>
<v-col cols="2">
<UsersSections />
<SideBar />
</v-col>
<v-col cols="10">
<UsersHome />
@ -23,11 +23,9 @@
</template>
<script>
import UsersHome from "../components/Users/Main";
import UsersSections from "../components/Users/Sections";
export default {
components: {
UsersHome,
UsersSections,
},
};
</script>

@ -11,7 +11,7 @@
<div>
<v-row>
<v-col cols="2">
<WorkoutsSections />
<SideBar />
</v-col>
<v-col cols="10">
<WorkoutsHome />
@ -23,11 +23,9 @@
</template>
<script>
import WorkoutsHome from "../components/Workouts/Main";
import WorkoutsSections from "../components/Workouts/Sections";
export default {
components: {
WorkoutsHome,
WorkoutsSections,
},
};
</script>

@ -11,7 +11,7 @@
<div>
<v-row>
<v-col cols="2">
<WorkoutsSeriesSections />
<SideBar />
</v-col>
<v-col cols="10">
<WorkoutsSeriesHome />
@ -23,11 +23,9 @@
</template>
<script>
import WorkoutsSeriesHome from "../components/WorkoutsSeries/Main";
import WorkoutsSeriesSections from "../components/WorkoutsSeries/Sections";
export default {
components: {
WorkoutsSeriesHome,
WorkoutsSeriesSections,
},
};
</script>
Loading…
Cancel
Save