sajjad 3 years ago
parent 4e694c8fbd
commit 6de0e23fd0

160
package-lock.json generated

@ -2844,6 +2844,63 @@
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
"dev": true
},
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"optional": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"optional": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"optional": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true,
"optional": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"optional": true
},
"loader-utils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
"dev": true,
"optional": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
}
},
"ssri": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
@ -2852,6 +2909,28 @@
"requires": {
"minipass": "^3.1.1"
}
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"optional": true,
"requires": {
"has-flag": "^4.0.0"
}
},
"vue-loader-v16": {
"version": "npm:vue-loader@16.8.3",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
"integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
"dev": true,
"optional": true,
"requires": {
"chalk": "^4.1.0",
"hash-sum": "^2.0.0",
"loader-utils": "^2.0.0"
}
}
}
},
@ -12411,87 +12490,6 @@
}
}
},
"vue-loader-v16": {
"version": "npm:vue-loader@16.8.3",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
"integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
"dev": true,
"optional": true,
"requires": {
"chalk": "^4.1.0",
"hash-sum": "^2.0.0",
"loader-utils": "^2.0.0"
},
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"optional": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"optional": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"optional": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true,
"optional": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"optional": true
},
"loader-utils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
"dev": true,
"optional": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
}
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"optional": true,
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"vue-meta": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/vue-meta/-/vue-meta-2.4.0.tgz",

@ -16,7 +16,16 @@ export default class ProgramRepository {
// }
let params = setQuery(data);
let response = await axios.get(url("indexProgram"), {
headers: { 'accept-language': 'en' },
params
});
if (response.status === 200) {
return getArray(response.data);
}
}
async indexMyPrograms(data) {
console.log('repository');
let params = setQuery(data);
let response = await axios.get(url("indexMyProgram"), {
params
});
if (response.status === 200) {

@ -3,7 +3,7 @@ import url from "@/router/url";
import { getArray, getJson } from "../resources/sportCategoryResource";
export default class SportCategoryRepository {
async index() {
let response = await axios.get(url("indexSportCategories"));
let response = await axios.get(url("indexClientSportCategories"));
if (response.status === 200) {
return getArray(response.data);
}

@ -22,6 +22,7 @@ export const getJson = (data) => ({
roles: data.roles
});
export const setData = (data, isUpdate = false) => {
console.log(data);
let formData = {
first_name: data.first_name,
last_name: data.last_name,
@ -33,6 +34,7 @@ export const setData = (data, isUpdate = false) => {
details: data.details,
address: data.address,
email: data.email,
batch_id: data.batch_id,
cell_number: data.cell_number,
country_id: data.country_id,
};

@ -20,8 +20,6 @@ export const getJson = (data) => {
address: data.address,
email: data.email,
cell_number: data.cell_number,
is_admin: data.is_admin,
is_trainer: data.is_trainer,
type: type,
role: data.roles,
role_id: role_id,

@ -20,6 +20,7 @@
label="manager image"
:url.sync="form.thumbnail"
v-model="fileForm"
:stencilProps="{ aspectRatio: 1, checkImageOrigin: false }"
/>
</div>
</div>
@ -239,7 +240,7 @@ export default {
},
fileForm: {
batch_id: RANDOM_TOKEN,
collection: "thumbnail",
collection: "main_image",
crop_data: {},
},
noResultsText: "No results found.",

@ -134,6 +134,7 @@ import SectionTitle from "../Global/Section/SectionTitle.vue";
import ImageCropper from "../Global/Input/ImageCropper.vue";
import FileRepository from "../../abstraction/repository/fileRepository";
import { mapGetters, mapActions } from "vuex";
// import _ from "lodash";
import { makeid } from "@/utils/math";
const RANDOM_TOKEN = makeid(50);
@ -143,12 +144,13 @@ export default {
ImageCropper,
},
data: () => ({
// perviousCropData: {},
form: {
batch_id: RANDOM_TOKEN,
},
fileForm: {
batch_id: RANDOM_TOKEN,
collection: "thumbnail",
collection: "main_image",
crop_data: {},
},
}),
@ -171,7 +173,11 @@ export default {
try {
let repository = new FileRepository();
if (this.programId) {
if (this.fileForm.file) {
if (
this.fileForm.file
// ||
// !_.isEqual(this.fileForm.crop_data, this.perviousCropData)
) {
await repository.store(this.fileForm);
}
await this.updateProgram(this.form);
@ -189,6 +195,7 @@ export default {
await this.loadProgram(this.programId);
this.form = this.getProgram;
this.form["batch_id"] = RANDOM_TOKEN;
// this.perviousCropData = this.fileForm.crop_data;
},
removeTags(item) {
this.form.tags.splice(this.form.tags.indexOf(item), 1);

@ -181,6 +181,7 @@ import SectionTitle from "../Global/Section/SectionTitle.vue";
import ImageCropper from "../Global/Input/ImageCropper.vue";
import FileRepository from "../../abstraction/repository/fileRepository";
import { mapActions, mapGetters } from "vuex";
// import _ from 'lodash';
import { makeid } from "@/utils/math";
const RANDOM_TOKEN = makeid(50);
@ -190,12 +191,13 @@ export default {
ImageCropper,
},
data: () => ({
// perviousCropData: {},
form: {
batch_id: RANDOM_TOKEN,
},
fileForm: {
batch_id: RANDOM_TOKEN,
collection: "thumbnail",
collection: "main_image",
crop_data: {}
},
}),
@ -223,7 +225,9 @@ export default {
try {
let repository = new FileRepository();
if (this.workoutId) {
if (this.fileForm.file) {
if (this.fileForm.file
// || !_.isEqual(this.fileForm.crop_data, this.perviousCropData)
) {
await repository.store(this.fileForm);
}
await this.updateWorkout(this.form);
@ -242,6 +246,7 @@ export default {
this.form = this.getWorkout;
this.form["batch_id"] = RANDOM_TOKEN;
this.loadWorkoutCategories(this.form.sport_category_id);
// this.perviousCropData = this.fileForm.crop_data;
},
changeSportCategories() {
this.loadWorkoutCategories(this.form.sport_category_id);

@ -105,6 +105,7 @@ export default {
},
onChangeCropper({ coordinates }) {
this.form = { ...this.value, ...{ crop_data: coordinates } };
this.$emit("update:crop_data", coordinates);
},
},
};

@ -111,14 +111,14 @@ export default {
{
id: 2,
text: "my profile",
link: "profile",
active: this.$route.name === "profile",
link: "trainerProfile",
active: this.$route.name === "trainerProfile",
},
{
id: 3,
text: "my programs",
link: "trainsPrograms",
active: this.$route.name === "trainsPrograms",
link: "programs",
active: this.$route.name === "programs",
},
{
id: 4,

@ -1,17 +1,22 @@
<template>
<div class="user">
<div class="welcome">welcome</div>
<div class="wa__f__ta user__name">Patrick James</div>
<div class="wa__f__ta user__name">{{ first_name }} {{ last_name }}</div>
<div class="text-uppercase user__role">
current role: &nbsp; <span class="wa__f__m__eb">{{ role }}</span>
</div>
</div>
</template>
<script>
import { UserStorage } from "@/utils/storage";
export default {
props: {
role: {},
},
data: () => ({
first_name: UserStorage.get() ? UserStorage.get().first_name : null,
last_name: UserStorage.get() ? UserStorage.get().last_name : null,
}),
};
</script>
<style scoped>

@ -5,10 +5,22 @@
>
<div class="product__card">
<div class="product__image">
<div
<!-- <div
class="product__img"
:style="{ backgroundImage: `url('${product.thumbnail}')` }"
></div>
></div> -->
<img
class="w-100"
:src="
product.thumbnail ? product.thumbnail : 'https://via.placeholder.com/1080'
"
alt="product image"
/>
<!-- <v-img
:src="
product.thumbnail ? product.thumbnail : 'https://via.placeholder.com/1080'
"
></v-img> -->
</div>
<div class="product__name">
<div class="product__title mt-2">{{ product.title }}</div>

@ -0,0 +1,232 @@
<template>
<div class="h-100">
<main-back height="100%">
<div class="py-12 px-10">
<div>
<SectionTitle
backText="home page"
link="dashboard"
icon="WMi-left-open"
title="my profile"
subTitle="let us know you better, it comes handy."
/>
</div>
<v-form @submit.prevent="submit">
<v-row class="mt-4">
<v-col cols="3">
<div class="pb-14 h-100">
<div class="w-100 h-100">
<ImageCropper
label="manager image"
:url.sync="form.profile"
v-model="fileForm"
/>
</div>
</div>
</v-col>
<v-col cols="9">
<v-row class="mt-4">
<v-col class="12" sm="3">
<v-text-field
placeholder="your email address"
label="your email address"
class="no-error-msg pt-0"
dark
v-model="form.email"
></v-text-field>
</v-col>
<v-col class="12" sm="3">
<v-text-field
placeholder="your name"
label="your name"
class="no-error-msg pt-0"
dark
v-model="form.first_name"
></v-text-field>
</v-col>
<v-col class="12" sm="3">
<v-text-field
placeholder="your family name"
label="your family name"
class="no-error-msg pt-0"
dark
v-model="form.last_name"
></v-text-field>
</v-col>
<v-col class="12" sm="3">
<v-text-field
placeholder="your cell number"
label="your cell number"
class="no-error-msg pt-0"
dark
v-model="form.cell_number"
></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col cols="3">
<v-autocomplete
placeholder="your country"
label="your country"
class="no-error-msg pt-0"
dark
item-value="id"
item-text="name"
:items="getCountries"
v-model="form.country_id"
></v-autocomplete>
</v-col>
<v-col cols="3">
<v-text-field
placeholder="address"
label="address"
class="no-error-msg pt-0"
dark
v-model="form.address"
></v-text-field>
</v-col>
<v-col cols="3"
><DateInput
class="no-error-msg"
label="Birthday"
dark
:max="new Date()"
v-model="form.birthday"
/></v-col>
<v-col cols="3"></v-col>
</v-row>
<v-divider dark></v-divider>
<v-row class="w-100">
<v-col cols="3"
><v-text-field
placeholder="weight"
label="weight"
class="no-error-msg pt-0"
suffix="kg"
dark
v-model="form.weight"
></v-text-field
></v-col>
<v-col cols="3"
><v-text-field
placeholder="height"
label="height"
class="no-error-msg pt-0"
suffix="cm"
dark
v-model="form.height"
></v-text-field
></v-col>
<v-col cols="3"
><v-text-field
placeholder="arm diameter"
label="arm diameter"
class="no-error-msg pt-0"
suffix="cm"
dark
v-model="form.arm_diameter"
></v-text-field
></v-col>
<v-col cols="3"
><v-text-field
placeholder="lge diameter"
label="lge diameter"
class="no-error-msg pt-0"
suffix="cm"
dark
v-model="form.leg_diameter"
></v-text-field
></v-col>
</v-row>
<v-row class="mb-16">
<v-col cols="12">
<v-textarea
placeholder="about you"
label="about you"
class="no-error-msg"
rows="4"
dark
v-model="form.details"
></v-textarea>
</v-col>
</v-row>
</v-col>
</v-row>
<div class="mt-16">
<v-divider dark class="mb-2"></v-divider>
<div class="d-flex justify-space-between">
<router-link :to="{ name: 'dashboard' }">
<RectangleButton
text="IVE CHANGED MY MIND"
icon="WMi-cancel"
class="px-0"
height="19"
/></router-link>
<RectangleButton
text="SAVE THE INFO"
class="custom-btn save-btn"
height="25"
type="submit"
/>
</div>
</div>
</v-form>
</div>
</main-back>
</div>
</template>
<script>
import { mapActions, mapGetters } from "vuex";
import SectionTitle from "../Global/Section/SectionTitle.vue";
import ImageCropper from "../Global/Input/ImageCropper.vue";
import FileRepository from "../../abstraction/repository/fileRepository";
import { makeid } from "@/utils/math";
const RANDOM_TOKEN = makeid(50);
export default {
components: {
SectionTitle,
ImageCropper,
},
data: () => ({
form: {
batch_id: RANDOM_TOKEN,
},
fileForm: {
batch_id: RANDOM_TOKEN,
collection: "main_image",
crop_data: {},
},
}),
computed: {
...mapGetters("profile", ["getProfile"]),
...mapGetters("countries", ["getCountries"]),
},
methods: {
...mapActions("profile", ["updateProfile", "loadProfile"]),
...mapActions("countries", ["loadCountries"]),
async setProfile() {
await this.loadProfile();
this.form = this.getProfile;
this.form["batch_id"] = RANDOM_TOKEN;
},
async submit() {
if (this.fileForm.file) {
let repository = new FileRepository();
await repository.store(this.fileForm);
}
await this.updateProfile(this.form);
this.$router.push({ name: "dashboard" });
},
},
async created() {
await this.loadCountries();
this.setProfile();
},
};
</script>
<style scoped>
.save-btn {
padding-right: 100px !important;
padding-left: 100px !important;
}
</style>

@ -9,6 +9,11 @@
}')`,
}"
></div>
<!-- <img
:src="program.thumbnail ? program.thumbnail : `http://via.placeholder.com/200`"
class="rounded offer__detail--image"
alt=""
/> -->
<div class="wa__program__image__button">
<div class="wa__program__image__button--icon">
<RectangleButton
@ -17,6 +22,7 @@
class="custom-btn ml-1"
height="32"
:icon="program.verified ? 'WMi-cancel' : 'WMi-ok'"
v-if="type === 'admin'"
/>
<router-link
class="text-decoration-none"
@ -77,8 +83,12 @@
<script>
import { mapActions } from "vuex";
import toast from "@/utils/toast";
import { UserStorage } from "@/utils/storage";
export default {
data: () => ({
type: UserStorage.get() ? UserStorage.get().type : null,
}),
props: {
program: {
type: Object,

@ -58,18 +58,21 @@ import FiltersModal from "./Modals/FiltersModal.vue";
import SectionTitle from "../Global/Section/SectionTitle.vue";
import ProgramItem from "./Item.vue";
import { mapGetters, mapActions, mapMutations } from "vuex";
// import _ from "lodash";
import { UserStorage } from "@/utils/storage";
export default {
components: {
SectionTitle,
ProgramItem,
FiltersModal,
},
data: () => ({
type: UserStorage.get() ? UserStorage.get().type : null,
}),
computed: {
...mapGetters("programs", ["getPrograms", "getPaginationProgram", "getFilterCount"]),
},
methods: {
...mapActions("programs", ["loadPrograms"]),
...mapActions("programs", ["loadPrograms", "loadMyPrograms"]),
...mapMutations("programs", ["SET_PAGINATION"]),
changePagination(page) {
if (this.getPaginationProgram.page !== page) {
@ -78,7 +81,7 @@ export default {
}
},
async load() {
await this.loadPrograms();
this.type === "admin" ? await this.loadPrograms() : await this.loadMyPrograms();
},
},
created() {

@ -35,7 +35,7 @@
class="no-error-msg pt-0"
placeholder="mentor name"
label="mentor name"
v-model="filter.first_name.val"
v-model="filter.name.val"
></v-text-field>
</div>
</div>
@ -105,7 +105,7 @@ const defaultFilter = {
type: "like",
val: null,
},
first_name: {
name: {
type: "like",
val: null,
},

@ -39,7 +39,13 @@ export default [
path: '/profile',
view: 'Profile',
name: 'profile',
meta: { auth: true }
meta: { auth: true, roles: ["trainee", "admin"] }
},
{
path: '/trainer-profile',
view: 'TrainerProfile',
name: 'trainerProfile',
meta: { auth: true, roles: ["trainer"] }
},
{
path: '/workouts',
@ -51,7 +57,7 @@ export default [
path: '/add-program',
view: 'AddProgram',
name: 'addProgram',
meta: { auth: true, roles: ["admin"] }
meta: { auth: true, roles: ["admin", "trainer"] }
},
{
path: '/edit-program/:id?',

@ -13,10 +13,13 @@ const urls = {
verifyProgram: "admin/courses/verify-course/:course",
destroyProgram: "admin/courses/:course",
updateProgram: "trainer/courses/:course",
// trainer programs
indexMyProgram: "trainer/courses",
// user programs
indexUserProgram: "my-courses",
// sport categories
indexSportCategories: "admin/sport-categories",
indexClientSportCategories: "sport-categories",
showSportCategory: "admin/sport-categories/:sportCategory",
// workout categories
indexWorkoutCategories: "admin/workout-categories",

@ -15,6 +15,20 @@ export default {
return e;
}
},
async loadMyPrograms({ state, commit }) {
try {
let data = { pagination: state.pagination, filters: state.filters };
let repository = new ProgramRepository();
const resource = await repository.indexMyPrograms(data);
let filterCount = setQuery({ filters: state.filters })
commit("SET_FILTER_COUNT", Object.keys(filterCount).length);
commit("SET_PROGRAMS", resource.data);
commit("SET_PAGINATION", resource.pagination);
}
catch (e) {
return e;
}
},
async loadProgram({ commit }, courseId) {
let repository = new ProgramRepository();
const resource = await repository.show(courseId);

@ -0,0 +1,31 @@
<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">
<SideBar />
</v-col>
<v-col cols="10">
<ProfileHome />
</v-col>
</v-row>
</div>
</main>
</v-container>
</template>
<script>
import ProfileHome from "../components/Profile/Trainer";
export default {
components: {
ProfileHome,
},
};
</script>
Loading…
Cancel
Save