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")