mirror of
https://framagit.org/les/gancio.git
synced 2025-01-31 16:42:22 +01:00
fix due hour selection when event ends on next day
This commit is contained in:
parent
1f42fc00f1
commit
fcae78f427
2 changed files with 68 additions and 59 deletions
|
@ -2,19 +2,18 @@
|
||||||
v-col(cols=12)
|
v-col(cols=12)
|
||||||
.text-center
|
.text-center
|
||||||
v-btn-toggle.v-col-6.flex-column.flex-sm-row(v-model='type' color='primary' @change='type => change("type", type)')
|
v-btn-toggle.v-col-6.flex-column.flex-sm-row(v-model='type' color='primary' @change='type => change("type", type)')
|
||||||
v-btn(value='normal' label="normal") {{$t('event.normal')}}
|
v-btn(value='normal' label="normal") {{ $t('event.normal') }}
|
||||||
v-btn(value='multidate' label='multidate') {{$t('event.multidate')}}
|
v-btn(value='multidate' label='multidate') {{ $t('event.multidate') }}
|
||||||
v-btn(v-if='settings.allow_recurrent_event' value='recurrent' label="recurrent") {{$t('event.recurrent')}}
|
v-btn(v-if='settings.allow_recurrent_event' value='recurrent' label="recurrent") {{ $t('event.recurrent') }}
|
||||||
|
|
||||||
p {{$t(`event.${type}_description`)}}
|
p {{ $t(`event.${type}_description`) }}
|
||||||
|
|
||||||
v-btn-toggle.v-col-6.flex-column.flex-sm-row(v-if='type === "recurrent"' color='primary' :value='value.recurrent.frequency' @change='fq => change("frequency", fq)')
|
v-btn-toggle.v-col-6.flex-column.flex-sm-row(v-if='type === "recurrent"' color='primary' :value='value.recurrent.frequency' @change='fq => change("frequency", fq)')
|
||||||
v-btn(v-for='f in frequencies' :key='f.value' :value='f.value') {{f.text}}
|
v-btn(v-for='f in frequencies' :key='f.value' :value='f.value') {{ f.text }}
|
||||||
|
|
||||||
client-only
|
client-only
|
||||||
.datePicker.mt-3
|
.datePicker.mt-3
|
||||||
v-input(:value='fromDate'
|
v-input(:value='fromDate' :rules="[$validators.required('common.when')]")
|
||||||
:rules="[$validators.required('common.when')]")
|
|
||||||
vc-date-picker(
|
vc-date-picker(
|
||||||
v-model='fromDate'
|
v-model='fromDate'
|
||||||
:is-range='type === "multidate"'
|
:is-range='type === "multidate"'
|
||||||
|
@ -28,9 +27,9 @@ v-col(cols=12)
|
||||||
:min-date='type !== "recurrent" && new Date()')
|
:min-date='type !== "recurrent" && new Date()')
|
||||||
|
|
||||||
div.text-center.mb-2(v-if='type === "recurrent"')
|
div.text-center.mb-2(v-if='type === "recurrent"')
|
||||||
span(v-if='value.recurrent.frequency !== "1m" && value.recurrent.frequency !== "2m"') {{whenPatterns}}
|
span(v-if='value.recurrent.frequency !== "1m" && value.recurrent.frequency !== "2m"') {{ whenPatterns }}
|
||||||
v-btn-toggle.mt-1.flex-column.flex-sm-row(v-else :value='value.recurrent.type' color='primary' @change='fq => change("recurrentType", fq)')
|
v-btn-toggle.mt-1.flex-column.flex-sm-row(v-else :value='value.recurrent.type' color='primary' @change='fq => change("recurrentType", fq)')
|
||||||
v-btn(v-for='whenPattern in whenPatterns' :value='whenPattern.key' :key='whenPatterns.key' small) {{whenPattern.label}}
|
v-btn(v-for='whenPattern in whenPatterns' :value='whenPattern.key' :key='whenPatterns.key' small) {{ whenPattern.label }}
|
||||||
|
|
||||||
v-row.mt-3.col-md-6.mx-auto
|
v-row.mt-3.col-md-6.mx-auto
|
||||||
v-col.col-12.col-sm-6
|
v-col.col-12.col-sm-6
|
||||||
|
@ -42,6 +41,9 @@ v-col(cols=12)
|
||||||
transition="scale-transition")
|
transition="scale-transition")
|
||||||
template(v-slot:activator="{ on, attrs }")
|
template(v-slot:activator="{ on, attrs }")
|
||||||
v-text-field(
|
v-text-field(
|
||||||
|
clearable
|
||||||
|
:clear-icon='mdiClose'
|
||||||
|
@click:clear='() => change("fromHour")'
|
||||||
:label="$t('event.from')"
|
:label="$t('event.from')"
|
||||||
:value="fromHour"
|
:value="fromHour"
|
||||||
:disabled='!value.from'
|
:disabled='!value.from'
|
||||||
|
@ -55,7 +57,7 @@ v-col(cols=12)
|
||||||
v-model="fromHour"
|
v-model="fromHour"
|
||||||
:allowedMinutes='allowedMinutes'
|
:allowedMinutes='allowedMinutes'
|
||||||
format='24hr'
|
format='24hr'
|
||||||
@click:minute='menuFromHour=false'
|
@click:minute='menuFromHour = false'
|
||||||
@change='hr => change("fromHour", hr)')
|
@change='hr => change("fromHour", hr)')
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,6 +70,9 @@ v-col(cols=12)
|
||||||
transition="scale-transition")
|
transition="scale-transition")
|
||||||
template(v-slot:activator="{ on, attrs }")
|
template(v-slot:activator="{ on, attrs }")
|
||||||
v-text-field(
|
v-text-field(
|
||||||
|
clearable
|
||||||
|
:clear-icon='mdiClose'
|
||||||
|
@click:clear='() => change("dueHour")'
|
||||||
:label="$t('event.due')"
|
:label="$t('event.due')"
|
||||||
:value="dueHour"
|
:value="dueHour"
|
||||||
:disabled='!fromHour'
|
:disabled='!fromHour'
|
||||||
|
@ -80,10 +85,10 @@ v-col(cols=12)
|
||||||
v-model="dueHour"
|
v-model="dueHour"
|
||||||
:allowedMinutes='allowedMinutes'
|
:allowedMinutes='allowedMinutes'
|
||||||
format='24hr'
|
format='24hr'
|
||||||
@click:minute='menuDueHour=false'
|
@click:minute='menuDueHour = false'
|
||||||
@change='hr => change("dueHour", hr)')
|
@change='hr => change("dueHour", hr)')
|
||||||
|
|
||||||
List(v-if='type==="normal" && todayEvents.length' :events='todayEvents' :title='$t("event.same_day")')
|
List(v-if='type === "normal" && todayEvents.length' :events='todayEvents' :title='$t("event.same_day")')
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
@ -91,7 +96,7 @@ import dayjs from 'dayjs'
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
import List from '@/components/List'
|
import List from '@/components/List'
|
||||||
import { attributesFromEvents } from '../assets/helper'
|
import { attributesFromEvents } from '../assets/helper'
|
||||||
import { mdiClockTimeFourOutline, mdiClockTimeEightOutline } from '@mdi/js'
|
import { mdiClockTimeFourOutline, mdiClockTimeEightOutline, mdiClose } from '@mdi/js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DateInput',
|
name: 'DateInput',
|
||||||
|
@ -100,7 +105,7 @@ export default {
|
||||||
value: { type: Object, default: () => ({ from: null, due: null, recurrent: null }) },
|
value: { type: Object, default: () => ({ from: null, due: null, recurrent: null }) },
|
||||||
event: { type: Object, default: () => null }
|
event: { type: Object, default: () => null }
|
||||||
},
|
},
|
||||||
data () {
|
data() {
|
||||||
let fromDate
|
let fromDate
|
||||||
if (this.value.from) {
|
if (this.value.from) {
|
||||||
if (this.value.multidate) {
|
if (this.value.multidate) {
|
||||||
|
@ -110,7 +115,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
mdiClockTimeFourOutline, mdiClockTimeEightOutline,
|
mdiClockTimeFourOutline, mdiClockTimeEightOutline, mdiClose,
|
||||||
allowedMinutes: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55],
|
allowedMinutes: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55],
|
||||||
menuFromHour: false,
|
menuFromHour: false,
|
||||||
fromDate,
|
fromDate,
|
||||||
|
@ -128,15 +133,15 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['settings']),
|
...mapState(['settings']),
|
||||||
todayEvents () {
|
todayEvents() {
|
||||||
const start = dayjs.tz(this.value.from).startOf('day').unix()
|
const start = dayjs.tz(this.value.from).startOf('day').unix()
|
||||||
const end = dayjs.tz(this.value.from).endOf('day').unix()
|
const end = dayjs.tz(this.value.from).endOf('day').unix()
|
||||||
return this.events.filter(e => e.start_datetime >= start && e.start_datetime <= end)
|
return this.events.filter(e => e.start_datetime >= start && e.start_datetime <= end)
|
||||||
},
|
},
|
||||||
attributes () {
|
attributes() {
|
||||||
return attributesFromEvents(this.events)
|
return attributesFromEvents(this.events)
|
||||||
},
|
},
|
||||||
whenPatterns () {
|
whenPatterns() {
|
||||||
if (!this.value.from) { return }
|
if (!this.value.from) { return }
|
||||||
const date = dayjs(this.value.from)
|
const date = dayjs(this.value.from)
|
||||||
|
|
||||||
|
@ -180,7 +185,7 @@ export default {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted () {
|
async mounted() {
|
||||||
if (this.value.multidate) {
|
if (this.value.multidate) {
|
||||||
this.type = 'multidate'
|
this.type = 'multidate'
|
||||||
} else if (this.value.recurrent) {
|
} else if (this.value.recurrent) {
|
||||||
|
@ -195,10 +200,10 @@ export default {
|
||||||
this.events = this.events.filter(e => e.id !== this.event.id)
|
this.events = this.events.filter(e => e.id !== this.event.id)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateRecurrent (value) {
|
updateRecurrent(value) {
|
||||||
this.$emit('input', { ...this.value, recurrent: value || null })
|
this.$emit('input', { ...this.value, recurrent: value || null })
|
||||||
},
|
},
|
||||||
change (what, value) {
|
change(what, value) {
|
||||||
// change event's type
|
// change event's type
|
||||||
if (what === 'type') {
|
if (what === 'type') {
|
||||||
if (typeof value === 'undefined') { this.type = 'normal' }
|
if (typeof value === 'undefined') { this.type = 'normal' }
|
||||||
|
@ -222,55 +227,59 @@ export default {
|
||||||
} else if (what === 'recurrentType') {
|
} else if (what === 'recurrentType') {
|
||||||
this.$emit('input', { ...this.value, recurrent: { ...this.value.recurrent, type: value } })
|
this.$emit('input', { ...this.value, recurrent: { ...this.value.recurrent, type: value } })
|
||||||
} else if (what === 'fromHour') {
|
} else if (what === 'fromHour') {
|
||||||
if (value) {
|
// if (value) {
|
||||||
const [hour, minute] = value.split(':')
|
const [hour, minute] = value ? value.split(':') : [0, 0]
|
||||||
let from = dayjs.tz(this.value.from).hour(hour).minute(minute).second(0)
|
let from = dayjs.tz(this.value.from).hour(hour).minute(minute).second(0).toDate()
|
||||||
this.$emit('input', { ...this.value, from, fromHour: true })
|
this.$emit('input', { ...this.value, from })
|
||||||
} else {
|
if (!value) {
|
||||||
this.$emit('input', { ...this.value, fromHour: false })
|
this.fromHour = null
|
||||||
}
|
}
|
||||||
|
// } else {
|
||||||
|
// this.$emit('input', { ...this.value })
|
||||||
|
// }
|
||||||
} else if (what === 'dueHour') {
|
} else if (what === 'dueHour') {
|
||||||
if (value) {
|
if (value) {
|
||||||
const [hour, minute] = value.split(':')
|
const [hour, minute] = value.split(':')
|
||||||
let due = dayjs.tz(this.value.due).hour(hour).minute(minute).second(0)
|
let due = dayjs.tz(this.value.due || this.value.from).hour(Number(hour)).minute(Number(minute)).second(0)
|
||||||
|
|
||||||
// add a day
|
// add a day
|
||||||
if (dayjs.tz(this.value.from).hour() > Number(hour) && !this.value.multidate) {
|
if (dayjs(this.value.from).hour() > Number(hour) && !this.value.multidate) {
|
||||||
due = due.add(1, 'day')
|
due = due.add(1, 'day')
|
||||||
}
|
}
|
||||||
due = due.hour(hour).minute(minute).second(0)
|
due = due.hour(hour).minute(minute).second(0)
|
||||||
this.$emit('input', { ...this.value, due, dueHour: true })
|
this.$emit('input', { ...this.value, due: due.toDate() })
|
||||||
} else {
|
} else {
|
||||||
this.$emit('input', { ...this.value, due: null, dueHour: false })
|
this.$emit('input', { ...this.value, due: null })
|
||||||
|
this.dueHour = null
|
||||||
}
|
}
|
||||||
// change date in calendar (could be a range or a recurrent event...)
|
// change date in calendar (could be a range or a recurrent event...)
|
||||||
} else if (what === 'date') {
|
} else if (what === 'date') {
|
||||||
if (value === null) {
|
if (value === null) {
|
||||||
this.$emit('input', { ...this.value, from: null, fromHour: false })
|
this.$emit('input', { ...this.value, from: null, due: null })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (this.value.multidate) {
|
if (this.value.multidate) {
|
||||||
let from = value.start
|
let from = value.start
|
||||||
let due = value.end
|
let due = value.end
|
||||||
if (this.fromHour) {
|
if (this.fromHour) {
|
||||||
const [ hour, minute ] = this.fromHour.split(':')
|
const [hour, minute] = this.fromHour.split(':')
|
||||||
from = dayjs.tz(from).hour(hour).minute(minute)
|
from = dayjs.tz(from).hour(hour).minute(minute).second(0).toDate()
|
||||||
}
|
}
|
||||||
if (this.dueHour) {
|
if (this.dueHour) {
|
||||||
const [ hour, minute ] = this.dueHour.split(':')
|
const [hour, minute] = this.dueHour.split(':')
|
||||||
due = dayjs.tz(due).hour(hour).minute(minute)
|
due = dayjs.tz(due).hour(hour).minute(minute).second(0).toDate()
|
||||||
}
|
}
|
||||||
this.$emit('input', { ...this.value, from, due })
|
this.$emit('input', { ...this.value, from, due })
|
||||||
} else {
|
} else {
|
||||||
let from = value
|
let from = value
|
||||||
let due = this.value.due
|
let due = this.value.due || from
|
||||||
if (this.fromHour) {
|
if (this.fromHour) {
|
||||||
const [ hour, minute ] = this.fromHour.split(':')
|
const [hour, minute] = this.fromHour.split(':')
|
||||||
from = dayjs.tz(value).hour(hour).minute(minute)
|
from = dayjs.tz(value).hour(hour).minute(minute).second(0).toDate()
|
||||||
}
|
}
|
||||||
if (this.dueHour) {
|
if (this.dueHour) {
|
||||||
const [ hour, minute ] = this.dueHour.split(':')
|
const [hour, minute] = this.dueHour.split(':')
|
||||||
due = dayjs.tz(value).hour(hour).minute(minute)
|
due = dayjs.tz(value).hour(hour).minute(minute).second(0).toDate()
|
||||||
}
|
}
|
||||||
this.$emit('input', { ...this.value, from, due })
|
this.$emit('input', { ...this.value, from, due })
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
v-container.container.pa-0.pa-md-3
|
v-container.container.pa-0.pa-md-3
|
||||||
v-card
|
v-card
|
||||||
v-card-title
|
v-card-title
|
||||||
h4 {{edit?$t('common.edit_event'):$t('common.add_event')}}
|
h4 {{ edit ? $t('common.edit_event') : $t('common.add_event') }}
|
||||||
v-spacer
|
v-spacer
|
||||||
v-btn(link text color='primary' @click='openImportDialog=true')
|
v-btn(link text color='primary' @click='openImportDialog = true')
|
||||||
<v-icon v-text='mdiFileImport'></v-icon> {{$t('common.import')}}
|
<v-icon v-text='mdiFileImport'></v-icon> {{ $t('common.import') }}
|
||||||
v-dialog(v-model='openImportDialog' :fullscreen='$vuetify.breakpoint.xsOnly')
|
v-dialog(v-model='openImportDialog' :fullscreen='$vuetify.breakpoint.xsOnly')
|
||||||
ImportDialog(@close='openImportDialog=false' @imported='eventImported')
|
ImportDialog(@close='openImportDialog = false' @imported='eventImported')
|
||||||
|
|
||||||
v-card-text.px-0.px-xs-2
|
v-card-text.px-0.px-xs-2
|
||||||
v-form(v-model='valid' ref='form' lazy-validation)
|
v-form(v-model='valid' ref='form' lazy-validation)
|
||||||
|
@ -44,7 +44,7 @@ v-container.container.pa-0.pa-md-3
|
||||||
|
|
||||||
//- MEDIA / FLYER / POSTER
|
//- MEDIA / FLYER / POSTER
|
||||||
v-col(cols=12 md=6)
|
v-col(cols=12 md=6)
|
||||||
MediaInput(v-model='event.media[0]' :event='event' @remove='event.media=[]')
|
MediaInput(v-model='event.media[0]' :event='event' @remove='event.media = []')
|
||||||
|
|
||||||
//- tags
|
//- tags
|
||||||
v-col(cols=12 md=6)
|
v-col(cols=12 md=6)
|
||||||
|
@ -57,14 +57,14 @@ v-container.container.pa-0.pa-md-3
|
||||||
:items="tags"
|
:items="tags"
|
||||||
:menu-props="{ maxWidth: 400, eager: true }"
|
:menu-props="{ maxWidth: 400, eager: true }"
|
||||||
:label="$t('common.tags')")
|
:label="$t('common.tags')")
|
||||||
template(v-slot:selection="{ item, on, attrs, selected, parent}")
|
template(v-slot:selection="{ item, on, attrs, selected, parent }")
|
||||||
v-chip(v-bind="attrs" close :close-icon='mdiCloseCircle' @click:close='parent.selectItem(item)'
|
v-chip(v-bind="attrs" close :close-icon='mdiCloseCircle' @click:close='parent.selectItem(item)'
|
||||||
:input-value="selected" label small) {{item}}
|
:input-value="selected" label small) {{ item }}
|
||||||
|
|
||||||
v-card-actions
|
v-card-actions
|
||||||
v-spacer
|
v-spacer
|
||||||
v-btn(@click='done' :loading='loading' :disabled='!valid || loading' outlined
|
v-btn(@click='done' :loading='loading' :disabled='!valid || loading' outlined
|
||||||
color='primary') {{edit?$t('common.save'):$t('common.send')}}
|
color='primary') {{ edit ? $t('common.save') : $t('common.send') }}
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
@ -91,10 +91,10 @@ export default {
|
||||||
WhereInput,
|
WhereInput,
|
||||||
DateInput
|
DateInput
|
||||||
},
|
},
|
||||||
validate ({ store }) {
|
validate({ store }) {
|
||||||
return (store.state.auth.loggedIn || store.state.settings.allow_anon_event)
|
return (store.state.auth.loggedIn || store.state.settings.allow_anon_event)
|
||||||
},
|
},
|
||||||
async asyncData ({ params, $axios, error }) {
|
async asyncData({ params, $axios, error }) {
|
||||||
if (params.edit) {
|
if (params.edit) {
|
||||||
const data = { event: { place: {}, media: [] } }
|
const data = { event: { place: {}, media: [] } }
|
||||||
data.id = params.edit
|
data.id = params.edit
|
||||||
|
@ -127,7 +127,7 @@ export default {
|
||||||
}
|
}
|
||||||
return {}
|
return {}
|
||||||
},
|
},
|
||||||
data () {
|
data() {
|
||||||
const month = dayjs.tz().month() + 1
|
const month = dayjs.tz().month() + 1
|
||||||
const year = dayjs.tz().year()
|
const year = dayjs.tz().year()
|
||||||
return {
|
return {
|
||||||
|
@ -151,26 +151,26 @@ export default {
|
||||||
disableAddress: false
|
disableAddress: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
head () {
|
head() {
|
||||||
return {
|
return {
|
||||||
title: `${this.settings.title} - ${this.$t('common.add_event')}`
|
title: `${this.settings.title} - ${this.$t('common.add_event')}`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['settings']),
|
...mapState(['settings']),
|
||||||
filteredTags () {
|
filteredTags() {
|
||||||
if (!this.tagName) { return this.tags.slice(0, 10).map(t => t.tag) }
|
if (!this.tagName) { return this.tags.slice(0, 10).map(t => t.tag) }
|
||||||
const tagName = this.tagName.trim().toLowerCase()
|
const tagName = this.tagName.trim().toLowerCase()
|
||||||
return this.tags.filter(t => t.tag.toLowerCase().includes(tagName)).map(t => t.tag)
|
return this.tags.filter(t => t.tag.toLowerCase().includes(tagName)).map(t => t.tag)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
searchTags: debounce( async function(ev) {
|
searchTags: debounce(async function (ev) {
|
||||||
const search = ev.target.value
|
const search = ev.target.value
|
||||||
if (!search) return
|
if (!search) return
|
||||||
this.tags = await this.$axios.$get(`/tag?search=${search}`)
|
this.tags = await this.$axios.$get(`/tag?search=${search}`)
|
||||||
}, 100),
|
}, 100),
|
||||||
eventImported (event) {
|
eventImported(event) {
|
||||||
this.event = Object.assign(this.event, event)
|
this.event = Object.assign(this.event, event)
|
||||||
this.$refs.where.selectPlace({ name: event.place.name || event.place, create: true })
|
this.$refs.where.selectPlace({ name: event.place.name || event.place, create: true })
|
||||||
this.date = {
|
this.date = {
|
||||||
|
@ -183,7 +183,7 @@ export default {
|
||||||
}
|
}
|
||||||
this.openImportDialog = false
|
this.openImportDialog = false
|
||||||
},
|
},
|
||||||
async done () {
|
async done() {
|
||||||
if (!this.$refs.form.validate()) {
|
if (!this.$refs.form.validate()) {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const el = document.querySelector('.v-input.error--text:first-of-type')
|
const el = document.querySelector('.v-input.error--text:first-of-type')
|
||||||
|
@ -217,7 +217,7 @@ export default {
|
||||||
formData.append('description', this.event.description)
|
formData.append('description', this.event.description)
|
||||||
formData.append('multidate', !!this.date.multidate)
|
formData.append('multidate', !!this.date.multidate)
|
||||||
formData.append('start_datetime', dayjs(this.date.from).unix())
|
formData.append('start_datetime', dayjs(this.date.from).unix())
|
||||||
formData.append('end_datetime', this.date.due ? dayjs(this.date.due).unix() : this.date.from.add(2, 'hour').unix())
|
formData.append('end_datetime', this.date.due ? dayjs(this.date.due).unix() : dayjs(this.date.from).add(2, 'hour').unix())
|
||||||
|
|
||||||
if (this.edit) {
|
if (this.edit) {
|
||||||
formData.append('id', this.event.id)
|
formData.append('id', this.event.id)
|
||||||
|
|
Loading…
Reference in a new issue