diff --git a/html/src/app.js b/html/src/app.js index 1ec4c157..f78fae36 100644 --- a/html/src/app.js +++ b/html/src/app.js @@ -3360,6 +3360,61 @@ speechSynthesis.getVoices(); } }, 5000); + // Countdown timer + + var $countDownTimers = []; + + Vue.component('countdown-timer', { + template: '', + props: { + datetime: { + type: String, + default() { + return ''; + } + }, + hours: { + type: Number, + default() { + return 1; + } + } + }, + data() { + return { + text: '' + }; + }, + methods: { + update() { + var epoch = new Date(this.datetime).getTime() + (1000 * 60 * 60 * this.hours) - Date.now(); + if (epoch >= 0) { + this.text = timeToText(epoch); + } else { + this.text = ''; + } + } + }, + watch: { + date() { + this.update(); + } + }, + mounted() { + $countDownTimers.push(this); + this.update(); + }, + destroyed() { + removeFromArray($countDownTimers, this); + } + }); + + setInterval(function () { + for (var $countDownTimer of $countDownTimers) { + $countDownTimer.update(); + } + }, 5000); + // initialise var $app = { @@ -5760,6 +5815,27 @@ speechSynthesis.getVoices(); } }; $app.data.VRCPlusIconsTable = {}; + $app.data.inviteMessageTable = { + data: [], + tableProps: { + stripe: true, + size: 'mini' + } + }; + $app.data.inviteResponseMessageTable = { + data: [], + tableProps: { + stripe: true, + size: 'mini' + } + }; + $app.data.inviteRequestMessageTable = { + data: [], + tableProps: { + stripe: true, + size: 'mini' + } + }; $app.data.visits = 0; $app.data.openVR = configRepository.getBool('openVR'); $app.data.openVRAlways = configRepository.getBool('openVRAlways'); @@ -8104,6 +8180,96 @@ speechSynthesis.getVoices(); return '-'; }; + // App: Invite Messages + + API.$on('LOGIN', function () { + $app.inviteMessageTable.data = []; + $app.inviteResponseMessageTable.data = []; + $app.inviteRequestMessageTable.data = []; + }); + + API.refreshInviteMessageTableData = function (messageType) { + return this.call(`message/${this.currentUser.id}/${messageType}`, { + method: 'GET' + }).then((json) => { + var args = { + json + }; + this.$emit(`INVITE:${messageType.toUpperCase()}`, args); + return args; + }); + }; + + API.$on('INVITE:MESSAGE', function (args) { + $app.inviteMessageTable.data = args.json; + }); + + API.$on('INVITE:RESPONSE', function (args) { + $app.inviteResponseMessageTable.data = args.json; + }); + + API.$on('INVITE:REQUEST', function (args) { + $app.inviteRequestMessageTable.data = args.json; + }); + + API.editInviteMessage = function (params, messageType, slot) { + return this.call(`message/${this.currentUser.id}/${messageType}/${slot}`, { + method: 'PUT', + params + }).then((json) => { + var args = { + json, + params + }; + return args; + }); + }; + + // App: Edit Invite Message Dialog + + $app.data.editInviteMessageDialog = { + visible: false + }; + + $app.methods.showEditInviteMessageDialog = function (messageType, inviteMessage) { + this.$nextTick(() => adjustDialogZ(this.$refs.editInviteMessageDialog.$el)); + var D = this.editInviteMessageDialog; + //D.newMessage = inviteMessage.message; + D.visible = true; + D.inviteMessage = inviteMessage; + D.messageType = messageType; + }; + + $app.methods.saveInviteMessage = function () { + var D = this.editInviteMessageDialog; + D.visible = false; + if (D.inviteMessage.message !== D.newMessage) { + var slot = D.inviteMessage.slot; + var messageType = D.messageType; + var params = { + message: D.newMessage + }; + API.editInviteMessage(params, messageType, slot).catch((err) => { + throw err; + }).then((args) => { + this.$message({ + message: 'Invite message updated', + type: 'success' + }); + return args; + }).finally(() => { + API.refreshInviteMessageTableData(messageType); + }); + } + //D.newMessage = ''; + }; + + $app.methods.cancelInviteMessage = function () { + var D = this.editInviteMessageDialog; + D.visible = false; + //D.newMessage = ''; + }; + $app = new Vue($app); window.$app = $app; }()); diff --git a/html/src/index.pug b/html/src/index.pug index 46ec7634..2b63900e 100644 --- a/html/src/index.pug +++ b/html/src/index.pug @@ -438,6 +438,63 @@ html el-button(size="small" @click="promptUserDialog()") User el-button(size="small" @click="promptWorldDialog()") World el-button(size="small" @click="promptAvatarDialog()") Avatar + div.options-container(style="margin-top:30px") + span.header Invite Messages + el-tooltip(placement="top") + template(#content) + span Refresh + el-button(type="default" @click="API.refreshInviteMessageTableData('message')" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") + el-tooltip(placement="top") + template(#content) + span Clear results + el-button(type="default" @click="inviteMessageTable.data = []" size="mini" icon="el-icon-delete" circle style="margin-left:0") + data-tables(v-if="inviteMessageTable.data.length > 0" v-bind="inviteMessageTable" style="margin-top:10px") + el-table-column(label="Slot" prop="slot" sortable="custom" width="70") + el-table-column(label="Message" prop="message") + el-table-column(label="Cool Down" prop="updatedAt" sortable="custom" width="110" align="right") + template(v-once #default="scope") + countdown-timer(:datetime="scope.row.updatedAt" :hours="1") + el-table-column(label="Action" width="60" align="right") + template(v-once #default="scope") + el-button(type="text" icon="el-icon-edit" size="mini" @click="showEditInviteMessageDialog('message', scope.row)") + div.options-container(style="margin-top:30px") + span.header Invite Response Messages + el-tooltip(placement="top") + template(#content) + span Refresh + el-button(type="default" @click="API.refreshInviteMessageTableData('response')" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") + el-tooltip(placement="top") + template(#content) + span Clear results + el-button(type="default" @click="inviteResponseMessageTable.data = []" size="mini" icon="el-icon-delete" circle style="margin-left:0") + data-tables(v-if="inviteResponseMessageTable.data.length > 0" v-bind="inviteResponseMessageTable" style="margin-top:10px") + el-table-column(label="Slot" prop="slot" sortable="custom" width="70") + el-table-column(label="Message" prop="message") + el-table-column(label="Cool Down" prop="updatedAt" sortable="custom" width="110" align="right") + template(v-once #default="scope") + countdown-timer(:datetime="scope.row.updatedAt" :hours="1") + el-table-column(label="Action" width="60" align="right") + template(v-once #default="scope") + el-button(type="text" icon="el-icon-edit" size="mini" @click="showEditInviteMessageDialog('response', scope.row)") + div.options-container(style="margin-top:30px") + span.header Invite Request Messages + el-tooltip(placement="top") + template(#content) + span Refresh + el-button(type="default" @click="API.refreshInviteMessageTableData('request')" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") + el-tooltip(placement="top") + template(#content) + span Clear results + el-button(type="default" @click="inviteRequestMessageTable.data = []" size="mini" icon="el-icon-delete" circle style="margin-left:0") + data-tables(v-if="inviteRequestMessageTable.data.length > 0" v-bind="inviteRequestMessageTable" style="margin-top:10px") + el-table-column(label="Slot" prop="slot" sortable="custom" width="70") + el-table-column(label="Message" prop="message") + el-table-column(label="Cool Down" prop="updatedAt" sortable="custom" width="110" align="right") + template(v-once #default="scope") + countdown-timer(:datetime="scope.row.updatedAt" :hours="1") + el-table-column(label="Action" width="60" align="right") + template(v-once #default="scope") + el-button(type="text" icon="el-icon-edit" size="mini" @click="showEditInviteMessageDialog('request', scope.row)") div.options-container(v-if="API.currentUser.$isVRCPlus" style="margin-top:30px") span.header VRCPlus Icons el-tooltip(placement="top") @@ -447,7 +504,7 @@ html el-tooltip(placement="top") template(#content) span Clear results - el-button(type="default" @click="VRCPlusIconsTable = []" size="mini" icon="el-icon-delete" circle style="margin-left:0") + el-button(type="default" @click="VRCPlusIconsTable = {}" size="mini" icon="el-icon-delete" circle style="margin-left:0") el-tooltip(placement="top") template(#content) span Reset icon @@ -1383,6 +1440,15 @@ html template(#footer) el-button(type="small" @click="cancelSharedFeedFilters") Cancel el-button(type="primary" size="small" @click="saveSharedFeedFilters") Save + + //- dialog: Edit Invite Message + el-dialog.x-dialog(ref="editInviteMessageDialog" :visible.sync="editInviteMessageDialog.visible" title="Edit Invite Message" width="400px") + div(style='font-size:12px') + span Edit cool down time 1 hour. + el-input(type="textarea" v-model="editInviteMessageDialog.newMessage" size="mini" maxlength="64" show-word-limit :autosize="{ minRows:2, maxRows:5 }" placeholder="" style="margin-top:10px") + template(#footer) + el-button(type="small" @click="cancelInviteMessage") Cancel + el-button(type="primary" size="small" @click="saveInviteMessage") Save //- dialog: open source software notice el-dialog.x-dialog(:visible.sync="ossDialog" title="Open Source Software Notice" width="650px")