From 4af9b9e17fa5a62ca310a3f55ca7371bfebd351e Mon Sep 17 00:00:00 2001
From: DJj123dj <80536295+DJj123dj@users.noreply.github.com>
Date: Sat, 23 May 2026 14:30:56 +0200
Subject: [PATCH] (v4.2.0) Added 5 new question types
Added support for dropdown, radio select, checkbox select, file upload & text display question types.
---
.github/CONTRIBUTORS.json | 2 +
.github/CONTRIBUTORS.svg | 188 ++++++++--------
package.json | 2 +-
src/builders/embeds.ts | 18 +-
src/builders/modals.ts | 173 ---------------
src/commands/claim.ts | 2 +-
src/commands/close.ts | 2 +-
src/commands/delete.ts | 2 +-
src/commands/pin.ts | 2 +-
src/commands/reopen.ts | 2 +-
src/commands/ticket.ts | 67 ++++--
src/commands/unclaim.ts | 2 +-
src/commands/unpin.ts | 2 +-
src/components/modals.ts | 302 ++++++++++++++++++++++++++
src/core/api/question.ts | 265 ++++++++++++++++------
src/core/api/ticket.ts | 3 +-
src/core/cli/quickSetup.ts | 13 ++
src/core/mappings/action.ts | 3 +-
src/core/mappings/builder.ts | 9 +-
src/core/mappings/component.ts | 11 +-
src/core/mappings/config.ts | 30 ++-
src/core/startup/migration.ts | 13 ++
src/data/framework/checkerLoader.ts | 16 +-
src/data/framework/configLoader.ts | 15 ++
src/data/openticket/questionLoader.ts | 90 ++++++--
src/index.ts | 4 +-
26 files changed, 837 insertions(+), 401 deletions(-)
delete mode 100644 src/builders/modals.ts
create mode 100644 src/components/modals.ts
diff --git a/.github/CONTRIBUTORS.json b/.github/CONTRIBUTORS.json
index 2803e3e..f703118 100644
--- a/.github/CONTRIBUTORS.json
+++ b/.github/CONTRIBUTORS.json
@@ -50,6 +50,7 @@
{"sectionId":"contributor","name":"Ashish5180","pictureUrl":"https://github.com/Ashish5180.png","profileUrl":"https://github.com/Ashish5180"},
{"sectionId":"contributor","name":"duboiss","pictureUrl":"https://github.com/duboiss.png","profileUrl":"https://github.com/duboiss"},
{"sectionId":"contributor","name":"sdehaarte","pictureUrl":"https://github.com/sdehaarte.png","profileUrl":"https://github.com/sdehaarte"},
+ {"sectionId":"contributor","name":"MauroDruwel","pictureUrl":"https://github.com/MauroDruwel.png","profileUrl":"https://github.com/MauroDruwel"},
{"sectionId":"support","name":"smetsliam","pictureUrl":"https://github.com/smetsliam.png","profileUrl":"https://github.com/smetsliam"},
{"sectionId":"support","name":"Sank34","pictureUrl":"https://github.com/Sank34.png","profileUrl":"https://github.com/Sank34"},
{"sectionId":"support","name":"FrankVissers","pictureUrl":"https://github.com/FrankVissers.png","profileUrl":"https://github.com/FrankVissers"},
@@ -58,6 +59,7 @@
{"sectionId":"plugin-dev","name":"Imperatorix17","pictureUrl":"https://github.com/imperatorix17.png","profileUrl":"https://github.com/imperatorix17"},
{"sectionId":"plugin-dev","name":"DanoGlez","pictureUrl":"https://github.com/DanoGlez.png","profileUrl":"https://github.com/DanoGlez"},
{"sectionId":"plugin-dev","name":"yowsef","pictureUrl":"https://github.com/Yow-sef.png","profileUrl":"https://github.com/Yow-sef"},
+ {"sectionId":"plugin-dev","name":"MeneerSouf","pictureUrl":"https://github.com/MeneerSouf.png","profileUrl":"https://github.com/MeneerSouf"},
{"sectionId":"plugin-dev","name":"challenger_nova","pictureUrl":"https://apis.dj-dj.be/cdn/openticket/default-avatar.png","profileUrl":""},
{"sectionId":"translator","name":"HanumeshGupta","pictureUrl":"https://github.com/HanumeshGupta.png","profileUrl":"https://github.com/HanumeshGupta"},
{"sectionId":"translator","name":"benzorich","pictureUrl":"https://github.com/benzorich.png","profileUrl":"https://github.com/benzorich"},
diff --git a/.github/CONTRIBUTORS.svg b/.github/CONTRIBUTORS.svg
index 647121e..97cec2f 100644
--- a/.github/CONTRIBUTORS.svg
+++ b/.github/CONTRIBUTORS.svg
@@ -15,262 +15,274 @@
}
๐ ๏ธ Contributors
-
+
-
+
DJj123dj
-
+
-
+
guillee3
-
+
-
+
SKaranjaN
-
+
-
+
Ashish5180
-
+
-
+
duboiss
-
+
-
+
sdehaarte
+
+
+
+
+
+ MauroDruwel
๐ Discord Support
-
+
-
+
smetsliam
-
+
-
+
Sank34
-
+
-
+
FrankVissers
๐งฉ Plugin Developers
-
+
-
+
Rapid-Fast
-
+
-
+
NotMukundOP
-
+
-
+
Imperatorix17
-
+
-
+
DanoGlez
-
+
-
+
yowsef
-
-
+
+
-
- challenger_nova
+
+ MeneerSouf
+
+
+
+
+
+ challenger_nova
๐ฌ Translators
-
+
-
+
HanumeshGupta
-
+
-
+
benzorich
-
+
-
+
Reddishye
-
+
-
+
josuens
-
+
-
+
quiradon
-
+
-
+
Imperatorix17
-
+
-
+
NoOneNook
-
+
-
+
guillee3
-
+
-
+
Mods HD
-
+
-
+
anderskiy
-
+
-
+
SpyEye2
-
+
-
+
Sank34
-
+
-
+
thegamer5095
-
+
-
+
danoglez
-
+
-
+
zhavis
-
+
-
+
yuuslokrobjakkroval
-
+
-
+
imLudwig
-
+
-
+
iamnotmega
-
+
-
+
Ronalds13424
-
+
-
+
dysashop
-
+
-
+
fraden1mvp.
-
+
-
+
palestinian
-
+
-
+
challenger_nova
-
+
-
+
erxg
-
+
-
+
tsgindrius
-
+
-
+
kornel0706
-
+
-
+
me.october
-
+
-
+
ngocdiep2006
\ No newline at end of file
diff --git a/package.json b/package.json
index 3bb9c7c..83b1c84 100644
--- a/package.json
+++ b/package.json
@@ -27,7 +27,7 @@
"license": "GPL-3.0-only",
"dependencies": {
"@discordjs/rest": "^2.6.1",
- "@open-discord-bots/framework": "^0.4.4",
+ "@open-discord-bots/framework": "^0.5.2",
"@types/node": "^22.5.0",
"@types/terminal-kit": "^2.5.7",
"ansis": "^4.2.0",
diff --git a/src/builders/embeds.ts b/src/builders/embeds.ts
index c8e7f7e..c5651fd 100644
--- a/src/builders/embeds.ts
+++ b/src/builders/embeds.ts
@@ -626,11 +626,19 @@ const ticketEmbeds = () => {
if (generalConfig.data.ticketSystem.displayFieldsWithQuestions) instance.addFields(...embedOptions.fields)
const answers = ticket.get("opendiscord:answers").value
- answers.forEach((answer) => {
- if (!answer.value || answer.value.length == 0) return
- if (generalConfig.data.ticketSystem.questionFieldsInCodeBlock) instance.addFields({name:answer.name,value:"```"+answer.value.slice(0,1024-6)+"```",inline:false})
- else instance.addFields({name:answer.name,value:answer.value,inline:false})
- })
+ for (const answer of answers){
+ if (answer.type == "file-upload"){
+ //render file upload fields
+ if (!answer.files) continue
+ const renderedFiles = answer.files.map((file) => `- [${file.name}](${file.url})`).join("\n")
+ instance.addFields({name:answer.name,value:renderedFiles,inline:false})
+
+ }else if (typeof answer.value == "string" && answer.value.length > 0){
+ //render other fields
+ if (generalConfig.data.ticketSystem.questionFieldsInCodeBlock) instance.addFields({name:answer.name,value:"```"+answer.value.slice(0,1024-6)+"```",inline:false})
+ else instance.addFields({name:answer.name,value:answer.value,inline:false})
+ }
+ }
}else if (embedOptions.fields){
instance.setFields(embedOptions.fields)
}
diff --git a/src/builders/modals.ts b/src/builders/modals.ts
deleted file mode 100644
index 281e93f..0000000
--- a/src/builders/modals.ts
+++ /dev/null
@@ -1,173 +0,0 @@
-///////////////////////////////////////
-//MODAL BUILDERS
-///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index.js"
-import * as discord from "discord.js"
-
-const modals = opendiscord.builders.modals
-const lang = opendiscord.languages
-
-export async function registerAllModals(){
- ticketModals()
-}
-const ticketModals = () => {
- //TICKET QUESTIONS
- modals.add(new api.ODModal("opendiscord:ticket-questions"))
- modals.get("opendiscord:ticket-questions").workers.add(
- new api.ODWorker("opendiscord:ticket-questions",0,async (instance,params,origin) => {
- const {option} = params
-
- instance.setCustomId("od:ticket-questions_"+option.id.value+"_"+origin)
- instance.setTitle(option.exists("opendiscord:name") ? option.get("opendiscord:name").value : option.id.value)
- const questionIds = option.get("opendiscord:questions").value
- questionIds.forEach((id) => {
- const question = opendiscord.questions.get(id)
- if (!question) return
- if (question instanceof api.ODShortQuestion) instance.addQuestion({
- customId:question.id.value,
- label:question.get("opendiscord:name").value,
- style:"short",
- required:question.get("opendiscord:required").value,
- placeholder:(question.get("opendiscord:placeholder").value) ? question.get("opendiscord:placeholder").value : undefined,
- minLength:(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-min").value : undefined,
- maxLength:Math.min(1024-6,(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-max").value : (1024-6)) //embed field limit - 6x` characters
- })
- else if (question instanceof api.ODParagraphQuestion) instance.addQuestion({
- customId:question.id.value,
- label:question.get("opendiscord:name").value,
- style:"paragraph",
- required:question.get("opendiscord:required").value,
- placeholder:(question.get("opendiscord:placeholder").value) ? question.get("opendiscord:placeholder").value : undefined,
- minLength:(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-min").value : undefined,
- maxLength:Math.min(1024-6,(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-max").value : (1024-6)) //embed field limit - 6x` characters
- })
- })
- })
- )
-
- //CLOSE TICKET REASON
- modals.add(new api.ODModal("opendiscord:close-ticket-reason"))
- modals.get("opendiscord:close-ticket-reason").workers.add(
- new api.ODWorker("opendiscord:close-ticket-reason",0,async (instance,params,origin) => {
- const {channel,message} = params
-
- instance.setCustomId("od:close-ticket-reason|"+channel.id+"|"+message.id)
- instance.setTitle(lang.getTranslation("actions.buttons.close"))
- instance.addQuestion({
- customId:"reason",
- label:lang.getTranslation("params.uppercase.reason"),
- style:"paragraph",
- required:true,
- placeholder:lang.getTranslation("actions.modal.closePlaceholder")
- })
- })
- )
-
- //REOPEN TICKET REASON
- modals.add(new api.ODModal("opendiscord:reopen-ticket-reason"))
- modals.get("opendiscord:reopen-ticket-reason").workers.add(
- new api.ODWorker("opendiscord:reopen-ticket-reason",0,async (instance,params,origin) => {
- const {channel,message} = params
-
- instance.setCustomId("od:reopen-ticket-reason|"+channel.id+"|"+message.id)
- instance.setTitle(lang.getTranslation("actions.buttons.reopen"))
- instance.addQuestion({
- customId:"reason",
- label:lang.getTranslation("params.uppercase.reason"),
- style:"paragraph",
- required:true,
- placeholder:lang.getTranslation("actions.modal.reopenPlaceholder")
- })
- })
- )
-
- //DELETE TICKET REASON
- modals.add(new api.ODModal("opendiscord:delete-ticket-reason"))
- modals.get("opendiscord:delete-ticket-reason").workers.add(
- new api.ODWorker("opendiscord:delete-ticket-reason",0,async (instance,params,origin) => {
- const {channel,message} = params
-
- instance.setCustomId("od:delete-ticket-reason|"+channel.id+"|"+message.id)
- instance.setTitle(lang.getTranslation("actions.buttons.delete"))
- instance.addQuestion({
- customId:"reason",
- label:lang.getTranslation("params.uppercase.reason"),
- style:"paragraph",
- required:true,
- placeholder:lang.getTranslation("actions.modal.deletePlaceholder")
- })
- })
- )
-
- //CLAIM TICKET REASON
- modals.add(new api.ODModal("opendiscord:claim-ticket-reason"))
- modals.get("opendiscord:claim-ticket-reason").workers.add(
- new api.ODWorker("opendiscord:claim-ticket-reason",0,async (instance,params,origin) => {
- const {channel,message} = params
-
- instance.setCustomId("od:claim-ticket-reason|"+channel.id+"|"+message.id)
- instance.setTitle(lang.getTranslation("actions.buttons.claim"))
- instance.addQuestion({
- customId:"reason",
- label:lang.getTranslation("params.uppercase.reason"),
- style:"paragraph",
- required:true,
- placeholder:lang.getTranslation("actions.modal.claimPlaceholder")
- })
- })
- )
-
- //UNCLAIM TICKET REASON
- modals.add(new api.ODModal("opendiscord:unclaim-ticket-reason"))
- modals.get("opendiscord:unclaim-ticket-reason").workers.add(
- new api.ODWorker("opendiscord:unclaim-ticket-reason",0,async (instance,params,origin) => {
- const {channel,message} = params
-
- instance.setCustomId("od:unclaim-ticket-reason|"+channel.id+"|"+message.id)
- instance.setTitle(lang.getTranslation("actions.buttons.unclaim"))
- instance.addQuestion({
- customId:"reason",
- label:lang.getTranslation("params.uppercase.reason"),
- style:"paragraph",
- required:true,
- placeholder:lang.getTranslation("actions.modal.unclaimPlaceholder")
- })
- })
- )
-
- //PIN TICKET REASON
- modals.add(new api.ODModal("opendiscord:pin-ticket-reason"))
- modals.get("opendiscord:pin-ticket-reason").workers.add(
- new api.ODWorker("opendiscord:pin-ticket-reason",0,async (instance,params,origin) => {
- const {channel,message} = params
-
- instance.setCustomId("od:pin-ticket-reason|"+channel.id+"|"+message.id)
- instance.setTitle(lang.getTranslation("actions.buttons.pin"))
- instance.addQuestion({
- customId:"reason",
- label:lang.getTranslation("params.uppercase.reason"),
- style:"paragraph",
- required:true,
- placeholder:lang.getTranslation("actions.modal.pinPlaceholder")
- })
- })
- )
-
- //UNPIN TICKET REASON
- modals.add(new api.ODModal("opendiscord:unpin-ticket-reason"))
- modals.get("opendiscord:unpin-ticket-reason").workers.add(
- new api.ODWorker("opendiscord:unpin-ticket-reason",0,async (instance,params,origin) => {
- const {channel,message} = params
-
- instance.setCustomId("od:unpin-ticket-reason|"+channel.id+"|"+message.id)
- instance.setTitle(lang.getTranslation("actions.buttons.unpin"))
- instance.addQuestion({
- customId:"reason",
- label:lang.getTranslation("params.uppercase.reason"),
- style:"paragraph",
- required:true,
- placeholder:lang.getTranslation("actions.modal.unpinPlaceholder")
- })
- })
- )
-}
\ No newline at end of file
diff --git a/src/commands/claim.ts b/src/commands/claim.ts
index 555e573..a2eb3a9 100644
--- a/src/commands/claim.ts
+++ b/src/commands/claim.ts
@@ -169,7 +169,7 @@ export async function registerVerifyBars(){
}
}else if (params.selectedButtonId == "accept-with-reason"){
//CLAIM WITH REASON (MODAL)
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:claim-ticket-reason").build("other",{guild,channel,user,ticket,message}))
+ instance.modal(await opendiscord.components.modals.get("opendiscord:claim-ticket-reason").build("other",{guild,channel,user,ticket,message}))
}
})
])
diff --git a/src/commands/close.ts b/src/commands/close.ts
index 64f9595..ce0526d 100644
--- a/src/commands/close.ts
+++ b/src/commands/close.ts
@@ -177,7 +177,7 @@ export async function registerVerifyBars(){
}
}else if (params.selectedButtonId == "accept-with-reason"){
//CLOSE WITH REASON (MODAL)
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:close-ticket-reason").build("other",{guild,channel,user,ticket,message}))
+ instance.modal(await opendiscord.components.modals.get("opendiscord:close-ticket-reason").build("other",{guild,channel,user,ticket,message}))
}
})
])
diff --git a/src/commands/delete.ts b/src/commands/delete.ts
index 8c153a8..400fdf3 100644
--- a/src/commands/delete.ts
+++ b/src/commands/delete.ts
@@ -202,7 +202,7 @@ export async function registerVerifyBars(){
}
}else if (params.selectedButtonId == "accept-with-reason"){
//DELETE WITH REASON (MODAL)
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:delete-ticket-reason").build("other",{guild,channel,user,ticket,message}))
+ instance.modal(await opendiscord.components.modals.get("opendiscord:delete-ticket-reason").build("other",{guild,channel,user,ticket,message}))
}
})
])
diff --git a/src/commands/pin.ts b/src/commands/pin.ts
index 8ca9fc0..413be79 100644
--- a/src/commands/pin.ts
+++ b/src/commands/pin.ts
@@ -169,7 +169,7 @@ export async function registerVerifyBars(){
}
}else if (params.selectedButtonId == "accept-with-reason"){
//PIN WITH REASON (MODAL)
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:pin-ticket-reason").build("other",{guild,channel,user,ticket,message}))
+ instance.modal(await opendiscord.components.modals.get("opendiscord:pin-ticket-reason").build("other",{guild,channel,user,ticket,message}))
}
})
])
diff --git a/src/commands/reopen.ts b/src/commands/reopen.ts
index 2ba0772..d2fcc55 100644
--- a/src/commands/reopen.ts
+++ b/src/commands/reopen.ts
@@ -185,7 +185,7 @@ export async function registerVerifyBars(){
}
}else if (params.selectedButtonId == "accept-with-reason"){
//REOPEN WITH REASON (MODAL)
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:reopen-ticket-reason").build("other",{guild,channel,user,ticket,message}))
+ instance.modal(await opendiscord.components.modals.get("opendiscord:reopen-ticket-reason").build("other",{guild,channel,user,ticket,message}))
}
})
])
diff --git a/src/commands/ticket.ts b/src/commands/ticket.ts
index 92c1c86..19f4192 100644
--- a/src/commands/ticket.ts
+++ b/src/commands/ticket.ts
@@ -50,7 +50,7 @@ export async function registerCommandResponders(){
//start ticket creation
if (option.exists("opendiscord:questions") && option.get("opendiscord:questions").value.length > 0){
//SEND MODAL
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:ticket-questions").build(origin,{guild,channel,user,option}))
+ instance.modal(await opendiscord.components.modals.get("opendiscord:ticket-questions").build(origin,{guild,channel,user,option}))
}else{
//check ticket permissions (modals need check after submit)
if (!(await checkTicketCreationPerms(instance,origin,guild,user,option))) return cancel()
@@ -99,7 +99,7 @@ export async function registerButtonResponders(){
//start ticket creation
if (option.exists("opendiscord:questions") && option.get("opendiscord:questions").value.length > 0){
//SEND MODAL
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:ticket-questions").build("panel-button",{guild,channel,user,option}))
+ instance.modal(await opendiscord.components.modals.get("opendiscord:ticket-questions").build("panel-button",{guild,channel,user,option}))
}else{
//check ticket permissions (modals need check after submit)
if (!(await checkTicketCreationPerms(instance,"panel-button",guild,user,option))) return cancel()
@@ -141,7 +141,7 @@ export async function registerDropdownResponders(){
//start ticket creation
if (option.exists("opendiscord:questions") && option.get("opendiscord:questions").value.length > 0){
//SEND MODAL
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:ticket-questions").build("panel-dropdown",{guild,channel,user,option}))
+ instance.modal(await opendiscord.components.modals.get("opendiscord:ticket-questions").build("panel-dropdown",{guild,channel,user,option}))
}else{
//check ticket permissions (modals need check after submit)
if (!(await checkTicketCreationPerms(instance,"panel-dropdown",guild,user,option))) return cancel()
@@ -193,26 +193,47 @@ export async function registerModalResponders(){
if (!(await checkTicketCreationPerms(instance,originalOrigin,guild,user,option))) return cancel()
//get answers
- const answers: {id:string,name:string,type:"short"|"paragraph",value:string|null}[] = []
- option.get("opendiscord:questions").value.forEach((id) => {
- const question = opendiscord.questions.get(id)
- if (!question) return
- if (question instanceof api.ODShortQuestion){
- answers.push({
- id,
- name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : id,
- type:"short",
- value:instance.values.getTextField(id,false)
- })
- }else if (question instanceof api.ODParagraphQuestion){
- answers.push({
- id,
- name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : id,
- type:"paragraph",
- value:instance.values.getTextField(id,false)
- })
- }
- })
+ const answers: api.ODQuestionAnswer[] = []
+ for (const questionId of option.get("opendiscord:questions").value){
+ const question = opendiscord.questions.get(questionId)
+ if (!question) continue
+ if (question instanceof api.ODShortQuestion) answers.push({
+ id:questionId,
+ name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : questionId,
+ type:"short",
+ value:instance.values.getTextField(questionId,false)
+ })
+ else if (question instanceof api.ODParagraphQuestion) answers.push({
+ id:questionId,
+ name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : questionId,
+ type:"paragraph",
+ value:instance.values.getTextField(questionId,false)
+ })
+ else if (question instanceof api.ODDropdownQuestion) answers.push({
+ id:questionId,
+ name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : questionId,
+ type:"dropdown",
+ value:instance.values.getStringDropdownValues(questionId)[0] ?? null
+ })
+ else if (question instanceof api.ODRadioSelectQuestion) answers.push({
+ id:questionId,
+ name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : questionId,
+ type:"radio-select",
+ value:instance.values.getRadioGroup(questionId,false)
+ })
+ else if (question instanceof api.ODCheckboxSelectQuestion) answers.push({
+ id:questionId,
+ name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : questionId,
+ type:"checkbox-select",
+ value:(instance.values.getCheckboxGroup(questionId).length > 0) ? instance.values.getCheckboxGroup(questionId).map((opt) => "> "+opt).join("\n") : null
+ })
+ else if (question instanceof api.ODFileUploadQuestion) answers.push({
+ id:questionId,
+ name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : questionId,
+ type:"file-upload",
+ files:(instance.values.getUploadedFiles(questionId).length > 0) ? instance.values.getUploadedFiles(questionId).map(({id,url,name,title,description,contentType}) => ({id,url,name,title,description,contentType})) : []
+ })
+ }
await instance.defer((generalConfig.data.ticketSystem.replyOnTicketCreation) ? "reply" : "update",true)
diff --git a/src/commands/unclaim.ts b/src/commands/unclaim.ts
index 6250061..ba48bba 100644
--- a/src/commands/unclaim.ts
+++ b/src/commands/unclaim.ts
@@ -168,7 +168,7 @@ export async function registerVerifyBars(){
}
}else if (params.selectedButtonId == "accept-with-reason"){
//UNCLAIM WITH REASON (MODAL)
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:unclaim-ticket-reason").build("other",{guild,channel,user,ticket,message}))
+ instance.modal(await opendiscord.components.modals.get("opendiscord:unclaim-ticket-reason").build("other",{guild,channel,user,ticket,message}))
}
})
])
diff --git a/src/commands/unpin.ts b/src/commands/unpin.ts
index a49d772..627e156 100644
--- a/src/commands/unpin.ts
+++ b/src/commands/unpin.ts
@@ -168,7 +168,7 @@ export async function registerVerifyBars(){
}
}else if (params.selectedButtonId == "accept-with-reason"){
//UNPIN WITH REASON (MODAL)
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:unpin-ticket-reason").build("other",{guild,channel,user,ticket,message}))
+ instance.modal(await opendiscord.components.modals.get("opendiscord:unpin-ticket-reason").build("other",{guild,channel,user,ticket,message}))
}
})
])
diff --git a/src/components/modals.ts b/src/components/modals.ts
new file mode 100644
index 0000000..c1ed285
--- /dev/null
+++ b/src/components/modals.ts
@@ -0,0 +1,302 @@
+///////////////////////////////////////
+//REGISTER MODAL COMPONENTS
+///////////////////////////////////////
+import {opendiscord, api, utilities} from "../index.js"
+import * as discord from "discord.js"
+
+const modals = opendiscord.components.modals
+const lang = opendiscord.languages
+const generalConfig = opendiscord.configs.get("opendiscord:general")
+
+export async function registerModalComponents(){
+ //TICKET QUESTIONS
+ modals.add(new api.ODComponentFactory("opendiscord:ticket-questions"))
+ modals.get("opendiscord:ticket-questions").workers.add(
+ new api.ODWorker("opendiscord:ticket-questions",0,(instance,params,origin) => {
+ const {option} = params
+
+ const modal = instance.setComponent(new api.ODModalComponent("opendiscord:questions-modal",{
+ customId:"od:ticket-questions|"+option.id.value+"|"+origin,
+ title:lang.getTranslation("params.uppercase.ticket")+": "+(option.exists("opendiscord:name")) ? option.get("opendiscord:name").value : option.id.value
+ }))
+
+ for (const questionId of option.get("opendiscord:questions").value){
+ const question = opendiscord.questions.get(questionId)
+ if (!question) continue
+
+ if (question instanceof api.ODShortQuestion){
+ //SHORT QUESTION
+ const component = new api.ODLabelComponent(question.id.value,{
+ title:question.get("opendiscord:name").value,
+ description:(question.get("opendiscord:description").value) ? question.get("opendiscord:description").value : undefined,
+ })
+ component.setComponent(new api.ODShortInputComponent(question.id.value,{
+ customId:question.id.value,
+ required:question.get("opendiscord:required").value,
+ placeholder:(question.get("opendiscord:placeholder").value) ? question.get("opendiscord:placeholder").value : undefined,
+ minLength:(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-min").value : undefined,
+ maxLength:Math.min(1024-6,(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-max").value : (1024-6)) //embed field limit - 6x` characters
+ }))
+ modal.addComponent(component,"end")
+ }else if (question instanceof api.ODParagraphQuestion){
+ //PARAGRAPH QUESTION
+ const component = new api.ODLabelComponent(question.id.value,{
+ title:question.get("opendiscord:name").value,
+ description:(question.get("opendiscord:description").value) ? question.get("opendiscord:description").value : undefined,
+ })
+ component.setComponent(new api.ODParagraphInputComponent(question.id.value,{
+ customId:question.id.value,
+ required:question.get("opendiscord:required").value,
+ placeholder:(question.get("opendiscord:placeholder").value) ? question.get("opendiscord:placeholder").value : undefined,
+ minLength:(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-min").value : undefined,
+ maxLength:Math.min(1024-6,(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-max").value : (1024-6)) //embed field limit - 6x` characters
+ }))
+ modal.addComponent(component,"end")
+ }else if (question instanceof api.ODDropdownQuestion){
+ //DROPDOWN QUESTION
+ const component = new api.ODLabelComponent(question.id.value,{
+ title:question.get("opendiscord:name").value,
+ description:(question.get("opendiscord:description").value) ? question.get("opendiscord:description").value : undefined,
+ })
+ component.setComponent(new api.ODDropdownComponent(question.id.value,{
+ type:"string",
+ customId:question.id.value,
+ required:question.get("opendiscord:required").value,
+ placeholder:(question.get("opendiscord:placeholder").value) ? question.get("opendiscord:placeholder").value : undefined,
+ maxValues:1,
+ options:question.get("opendiscord:choices").value.map((choice) => ({
+ label:choice.title,
+ emoji:choice.emoji,
+ description:choice.description,
+ value:choice.title
+ }))
+ }))
+ modal.addComponent(component,"end")
+ }else if (question instanceof api.ODRadioSelectQuestion){
+ //RADIO SELECT QUESTION
+ const component = new api.ODLabelComponent(question.id.value,{
+ title:question.get("opendiscord:name").value,
+ description:(question.get("opendiscord:description").value) ? question.get("opendiscord:description").value : undefined,
+ })
+ component.setComponent(new api.ODRadioGroupComponent(question.id.value,{
+ customId:question.id.value,
+ required:question.get("opendiscord:required").value,
+ options:question.get("opendiscord:choices").value.map((choice) => ({
+ label:choice.title,
+ default:choice.selectedByDefault,
+ description:choice.description,
+ value:choice.title
+ }))
+ }))
+ modal.addComponent(component,"end")
+ }else if (question instanceof api.ODCheckboxSelectQuestion){
+ //CHECKBOX SELECT QUESTION
+ const component = new api.ODLabelComponent(question.id.value,{
+ title:question.get("opendiscord:name").value,
+ description:(question.get("opendiscord:description").value) ? question.get("opendiscord:description").value : undefined,
+ })
+ component.setComponent(new api.ODCheckboxGroupComponent(question.id.value,{
+ customId:question.id.value,
+ required:question.get("opendiscord:required").value,
+ minValues:(question.get("opendiscord:limits-enabled").value) ? question.get("opendiscord:limits-min").value : undefined,
+ maxValues:(question.get("opendiscord:limits-enabled").value) ? question.get("opendiscord:limits-max").value : undefined,
+ options:question.get("opendiscord:choices").value.map((choice) => ({
+ label:choice.title,
+ default:choice.selectedByDefault,
+ description:choice.description,
+ value:choice.title
+ }))
+ }))
+ modal.addComponent(component,"end")
+ }else if (question instanceof api.ODFileUploadQuestion){
+ //FILE UPLOAD QUESTION
+ const component = new api.ODLabelComponent(question.id.value,{
+ title:question.get("opendiscord:name").value,
+ description:(question.get("opendiscord:description").value) ? question.get("opendiscord:description").value : undefined,
+ })
+ component.setComponent(new api.ODFileUploadComponent(question.id.value,{
+ customId:question.id.value,
+ required:question.get("opendiscord:required").value,
+ minAmount:(question.get("opendiscord:limits-enabled").value) ? question.get("opendiscord:limits-min").value : undefined,
+ maxAmount:(question.get("opendiscord:limits-enabled").value) ? question.get("opendiscord:limits-max").value : undefined,
+ }))
+ modal.addComponent(component,"end")
+ }else if (question instanceof api.ODTextDisplayQuestion){
+ //TEXT DISPLAY QUESTION
+ const component = new api.ODTextComponent(question.id.value,{
+ content:question.get("opendiscord:text-contents").value
+ })
+ modal.addComponent(component,"end")
+ }
+ }
+ })
+ )
+
+ //CLOSE TICKET REASON
+ modals.add(new api.ODComponentFactory("opendiscord:close-ticket-reason"))
+ modals.get("opendiscord:close-ticket-reason").workers.add(
+ new api.ODWorker("opendiscord:close-ticket-reason",0,async (instance,params,origin) => {
+ const {channel,message} = params
+
+ const modal = instance.setComponent(new api.ODModalComponent("opendiscord:close-ticket-reason",{
+ customId:"od:close-ticket-reason|"+channel.id+"|"+message.id,
+ title:lang.getTranslation("actions.buttons.close")
+ }))
+
+ const reasonComponent = new api.ODLabelComponent("reason",{
+ title:lang.getTranslation("params.uppercase.reason"),
+ description:lang.getTranslation("actions.modal.closePlaceholder")
+ })
+ reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{
+ customId:"reason",
+ required:true,
+ placeholder:lang.getTranslation("params.uppercase.reason")
+ }))
+ modal.addComponent(reasonComponent,"end")
+ })
+ )
+
+ //REOPEN TICKET REASON
+ modals.add(new api.ODComponentFactory("opendiscord:reopen-ticket-reason"))
+ modals.get("opendiscord:reopen-ticket-reason").workers.add(
+ new api.ODWorker("opendiscord:reopen-ticket-reason",0,async (instance,params,origin) => {
+ const {channel,message} = params
+
+ const modal = instance.setComponent(new api.ODModalComponent("opendiscord:reopen-ticket-reason",{
+ customId:"od:reopen-ticket-reason|"+channel.id+"|"+message.id,
+ title:lang.getTranslation("actions.buttons.reopen")
+ }))
+
+ const reasonComponent = new api.ODLabelComponent("reason",{
+ title:lang.getTranslation("params.uppercase.reason"),
+ description:lang.getTranslation("actions.modal.reopenPlaceholder")
+ })
+ reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{
+ customId:"reason",
+ required:true,
+ placeholder:lang.getTranslation("params.uppercase.reason")
+ }))
+ modal.addComponent(reasonComponent,"end")
+ })
+ )
+
+ //DELETE TICKET REASON
+ modals.add(new api.ODComponentFactory("opendiscord:delete-ticket-reason"))
+ modals.get("opendiscord:delete-ticket-reason").workers.add(
+ new api.ODWorker("opendiscord:delete-ticket-reason",0,async (instance,params,origin) => {
+ const {channel,message} = params
+
+ const modal = instance.setComponent(new api.ODModalComponent("opendiscord:delete-ticket-reason",{
+ customId:"od:delete-ticket-reason|"+channel.id+"|"+message.id,
+ title:lang.getTranslation("actions.buttons.delete")
+ }))
+
+ const reasonComponent = new api.ODLabelComponent("reason",{
+ title:lang.getTranslation("params.uppercase.reason"),
+ description:lang.getTranslation("actions.modal.deletePlaceholder")
+ })
+ reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{
+ customId:"reason",
+ required:true,
+ placeholder:lang.getTranslation("params.uppercase.reason")
+ }))
+ modal.addComponent(reasonComponent,"end")
+ })
+ )
+
+ //CLAIM TICKET REASON
+ modals.add(new api.ODComponentFactory("opendiscord:claim-ticket-reason"))
+ modals.get("opendiscord:claim-ticket-reason").workers.add(
+ new api.ODWorker("opendiscord:claim-ticket-reason",0,async (instance,params,origin) => {
+ const {channel,message} = params
+
+ const modal = instance.setComponent(new api.ODModalComponent("opendiscord:claim-ticket-reason",{
+ customId:"od:claim-ticket-reason|"+channel.id+"|"+message.id,
+ title:lang.getTranslation("actions.buttons.claim")
+ }))
+
+ const reasonComponent = new api.ODLabelComponent("reason",{
+ title:lang.getTranslation("params.uppercase.reason"),
+ description:lang.getTranslation("actions.modal.claimPlaceholder")
+ })
+ reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{
+ customId:"reason",
+ required:true,
+ placeholder:lang.getTranslation("params.uppercase.reason")
+ }))
+ modal.addComponent(reasonComponent,"end")
+ })
+ )
+
+ //UNCLAIM TICKET REASON
+ modals.add(new api.ODComponentFactory("opendiscord:unclaim-ticket-reason"))
+ modals.get("opendiscord:unclaim-ticket-reason").workers.add(
+ new api.ODWorker("opendiscord:unclaim-ticket-reason",0,async (instance,params,origin) => {
+ const {channel,message} = params
+
+ const modal = instance.setComponent(new api.ODModalComponent("opendiscord:unclaim-ticket-reason",{
+ customId:"od:unclaim-ticket-reason|"+channel.id+"|"+message.id,
+ title:lang.getTranslation("actions.buttons.unclaim")
+ }))
+
+ const reasonComponent = new api.ODLabelComponent("reason",{
+ title:lang.getTranslation("params.uppercase.reason"),
+ description:lang.getTranslation("actions.modal.unclaimPlaceholder")
+ })
+ reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{
+ customId:"reason",
+ required:true,
+ placeholder:lang.getTranslation("params.uppercase.reason")
+ }))
+ modal.addComponent(reasonComponent,"end")
+ })
+ )
+
+ //PIN TICKET REASON
+ modals.add(new api.ODComponentFactory("opendiscord:pin-ticket-reason"))
+ modals.get("opendiscord:pin-ticket-reason").workers.add(
+ new api.ODWorker("opendiscord:pin-ticket-reason",0,async (instance,params,origin) => {
+ const {channel,message} = params
+
+ const modal = instance.setComponent(new api.ODModalComponent("opendiscord:pin-ticket-reason",{
+ customId:"od:pin-ticket-reason|"+channel.id+"|"+message.id,
+ title:lang.getTranslation("actions.buttons.pin")
+ }))
+
+ const reasonComponent = new api.ODLabelComponent("reason",{
+ title:lang.getTranslation("params.uppercase.reason"),
+ description:lang.getTranslation("actions.modal.pinPlaceholder")
+ })
+ reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{
+ customId:"reason",
+ required:true,
+ placeholder:lang.getTranslation("params.uppercase.reason")
+ }))
+ modal.addComponent(reasonComponent,"end")
+ })
+ )
+
+ //UNPIN TICKET REASON
+ modals.add(new api.ODComponentFactory("opendiscord:unpin-ticket-reason"))
+ modals.get("opendiscord:unpin-ticket-reason").workers.add(
+ new api.ODWorker("opendiscord:unpin-ticket-reason",0,async (instance,params,origin) => {
+ const {channel,message} = params
+
+ const modal = instance.setComponent(new api.ODModalComponent("opendiscord:unpin-ticket-reason",{
+ customId:"od:unpin-ticket-reason|"+channel.id+"|"+message.id,
+ title:lang.getTranslation("actions.buttons.unpin")
+ }))
+
+ const reasonComponent = new api.ODLabelComponent("reason",{
+ title:lang.getTranslation("params.uppercase.reason"),
+ description:lang.getTranslation("actions.modal.unpinPlaceholder")
+ })
+ reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{
+ customId:"reason",
+ required:true,
+ placeholder:lang.getTranslation("params.uppercase.reason")
+ }))
+ modal.addComponent(reasonComponent,"end")
+ })
+ )
+}
\ No newline at end of file
diff --git a/src/core/api/question.ts b/src/core/api/question.ts
index bef825f..1dba0c4 100644
--- a/src/core/api/question.ts
+++ b/src/core/api/question.ts
@@ -2,6 +2,8 @@
//OPENTICKET OPTION MODULE
///////////////////////////////////////
import * as api from "@open-discord-bots/framework/api"
+import * as discord from "discord.js"
+import { ODQuestionsJsonConfig_BaseQuestion, ODQuestionsJsonConfig_DropdownChoice, ODQuestionsJsonConfig_RadioCheckboxChoice } from "../mappings/config.js"
/**## ODQuestionIdConstraint `type`
* The constraint/layout for id mappings/interfaces of the `ODQuestion` class.
@@ -14,9 +16,10 @@ export type ODQuestionIdConstraint = Record,
+ "opendiscord:description":ODQuestionData,
"opendiscord:required":ODQuestionData,
- "opendiscord:placeholder":ODQuestionData,
+ "opendiscord:placeholder":ODQuestionData,
"opendiscord:length-enabled":ODQuestionData,
"opendiscord:length-min":ODQuestionData,
"opendiscord:length-max":ODQuestionData
@@ -28,14 +31,77 @@ export interface ODShortQuestionIdMappings extends ODQuestionIdConstraint {
*/
export interface ODParagraphQuestionIdMappings extends ODQuestionIdConstraint {
"opendiscord:name":ODQuestionData,
+ "opendiscord:description":ODQuestionData,
"opendiscord:required":ODQuestionData,
- "opendiscord:placeholder":ODQuestionData,
+ "opendiscord:placeholder":ODQuestionData,
"opendiscord:length-enabled":ODQuestionData,
"opendiscord:length-min":ODQuestionData,
"opendiscord:length-max":ODQuestionData
}
+/**## ODDropdownQuestionIdMappings `interface`
+ * A list of all available IDs in the default `ODDropdownQuestion` class in `opendiscord`.
+ * It's used to generate typescript declarations for this class.
+ */
+export interface ODDropdownQuestionIdMappings extends ODQuestionIdConstraint {
+ "opendiscord:name":ODQuestionData,
+ "opendiscord:description":ODQuestionData,
+ "opendiscord:required":ODQuestionData,
+
+ "opendiscord:placeholder":ODQuestionData,
+ "opendiscord:choices":ODQuestionData
+}
+
+/**## ODRadioSelectQuestionIdMappings `interface`
+ * A list of all available IDs in the default `ODRadioSelectQuestion` class in `opendiscord`.
+ * It's used to generate typescript declarations for this class.
+ */
+export interface ODRadioSelectQuestionIdMappings extends ODQuestionIdConstraint {
+ "opendiscord:name":ODQuestionData,
+ "opendiscord:description":ODQuestionData,
+ "opendiscord:required":ODQuestionData,
+
+ "opendiscord:choices":ODQuestionData
+}
+
+/**## ODCheckboxSelectQuestionIdMappings `interface`
+ * A list of all available IDs in the default `ODCheckboxSelectQuestion` class in `opendiscord`.
+ * It's used to generate typescript declarations for this class.
+ */
+export interface ODCheckboxSelectQuestionIdMappings extends ODQuestionIdConstraint {
+ "opendiscord:name":ODQuestionData,
+ "opendiscord:description":ODQuestionData,
+ "opendiscord:required":ODQuestionData,
+
+ "opendiscord:limits-enabled":ODQuestionData,
+ "opendiscord:limits-min":ODQuestionData,
+ "opendiscord:limits-max":ODQuestionData
+ "opendiscord:choices":ODQuestionData
+}
+
+/**## ODFileUploadQuestionIdMappings `interface`
+ * A list of all available IDs in the default `ODFileUploadQuestion` class in `opendiscord`.
+ * It's used to generate typescript declarations for this class.
+ */
+export interface ODFileUploadQuestionIdMappings extends ODQuestionIdConstraint {
+ "opendiscord:name":ODQuestionData,
+ "opendiscord:description":ODQuestionData,
+ "opendiscord:required":ODQuestionData,
+
+ "opendiscord:limits-enabled":ODQuestionData,
+ "opendiscord:limits-min":ODQuestionData,
+ "opendiscord:limits-max":ODQuestionData
+}
+
+/**## ODTextDisplayQuestionIdMappings `interface`
+ * A list of all available IDs in the default `ODTextDisplayQuestion` class in `opendiscord`.
+ * It's used to generate typescript declarations for this class.
+ */
+export interface ODTextDisplayQuestionIdMappings extends ODQuestionIdConstraint {
+ "opendiscord:text-contents":ODQuestionData
+}
+
/**## ODQuestionManager `class`
* This is an Open Ticket question manager.
*
@@ -81,20 +147,19 @@ export interface ODQuestionJson {
/**## ODQuestion `class`
* This is an Open Ticket question.
*
- * This class contains all data related to this question (parsed from the config).
+ * This class contains all question data parsed from the config.
*
- * Use `ODShortQuestion` or `ODParagraphQuestion` instead!
+ * This is an abstract class. Use instances like `ODShortQuestion` or `ODParagraphQuestion` instead.
*/
-export class ODQuestion extends api.ODManager> {
+export abstract class ODQuestion extends api.ODManager> {
/**The id of this question. (from the config) */
id:api.ODId
/**The type of this question (e.g. `opendiscord:short` or `opendiscord:paragraph`) */
- type: string
+ abstract readonly type: string
- constructor(id:api.ODValidId, type:string, data:ODQuestionData[]){
+ constructor(id:api.ODValidId, data:ODQuestionData[]){
super()
this.id = new api.ODId(id)
- this.type = type
data.forEach((data) => {
this.add(data)
})
@@ -117,9 +182,25 @@ export class ODQuestion extends api.ODManager new ODQuestionData(data.id,data.value)))
+ get>(id:QuestionId): IdList[QuestionId]
+ get(id:api.ODValidId): ODQuestionData|null
+
+ get(id:api.ODValidId): ODQuestionData|null {
+ return super.get(id)
+ }
+
+ remove>(id:QuestionId): IdList[QuestionId]
+ remove(id:api.ODValidId): ODQuestionData|null
+
+ remove(id:api.ODValidId): ODQuestionData|null {
+ return super.remove(id)
+ }
+
+ exists(id:keyof api.ODNoGeneric): boolean
+ exists(id:api.ODValidId): boolean
+
+ exists(id:api.ODValidId): boolean {
+ return super.exists(id)
}
}
@@ -153,40 +234,36 @@ export class ODQuestionData extends api.OD
}
}
+/**## ODQuestionAnswer `type`
+ * A question answer stored in the database.
+ */
+export type ODQuestionAnswer = {
+ id:string,
+ name:string,
+ type:Exclude,
+ value:string|null
+}|{
+ id:string,
+ name:string,
+ type:"file-upload",
+ files:{
+ id:string,
+ url:string,
+ name:string,
+ title:string|null,
+ description:string|null,
+ contentType:string|null,
+ }[]
+}
/**## ODShortQuestion `class`
- * This is an Open Ticket short question.
- *
- * This class contains all data related to an Open Ticket short question (parsed from the config).
- *
- * Use this question in an option to add a short text field to the modal!
+ * An Open Ticket short question. It contains all config properties of the short question type.
*/
-export class ODShortQuestion extends ODQuestion {
- type: "opendiscord:short" = "opendiscord:short"
+export class ODShortQuestion extends ODQuestion {
+ readonly type: "opendiscord:short" = "opendiscord:short"
constructor(id:api.ODValidId, data:ODQuestionData[]){
- super(id,"opendiscord:short",data)
- }
-
- get>(id:QuestionId): ODShortQuestionIdMappings[QuestionId]
- get(id:api.ODValidId): ODQuestionData|null
-
- get(id:api.ODValidId): ODQuestionData|null {
- return super.get(id)
- }
-
- remove>(id:QuestionId): ODShortQuestionIdMappings[QuestionId]
- remove(id:api.ODValidId): ODQuestionData|null
-
- remove(id:api.ODValidId): ODQuestionData|null {
- return super.remove(id)
- }
-
- exists(id:keyof api.ODNoGeneric): boolean
- exists(id:api.ODValidId): boolean
-
- exists(id:api.ODValidId): boolean {
- return super.exists(id)
+ super(id,data)
}
static fromJson(json: ODQuestionJson): ODShortQuestion {
@@ -195,41 +272,91 @@ export class ODShortQuestion extends ODQuestion {
}
/**## ODParagraphQuestion `class`
- * This is an Open Ticket paragraph question.
- *
- * This class contains all data related to an Open Ticket paragraph question (parsed from the config).
- *
- * Use this question in an option to add a paragraph text field to the modal!
+ * An Open Ticket paragraph question. It contains all config properties of the paragraph question type.
*/
-export class ODParagraphQuestion extends ODQuestion {
- type: "opendiscord:paragraph" = "opendiscord:paragraph"
+export class ODParagraphQuestion extends ODQuestion {
+ readonly type: "opendiscord:paragraph" = "opendiscord:paragraph"
constructor(id:api.ODValidId, data:ODQuestionData[]){
- super(id,"opendiscord:paragraph",data)
- }
-
- get>(id:QuestionId): ODParagraphQuestionIdMappings[QuestionId]
- get(id:api.ODValidId): ODQuestionData|null
-
- get(id:api.ODValidId): ODQuestionData|null {
- return super.get(id)
- }
-
- remove>(id:QuestionId): ODParagraphQuestionIdMappings[QuestionId]
- remove(id:api.ODValidId): ODQuestionData|null
-
- remove(id:api.ODValidId): ODQuestionData|null {
- return super.remove(id)
- }
-
- exists(id:keyof api.ODNoGeneric): boolean
- exists(id:api.ODValidId): boolean
-
- exists(id:api.ODValidId): boolean {
- return super.exists(id)
+ super(id,data)
}
static fromJson(json: ODQuestionJson): ODParagraphQuestion {
return new ODParagraphQuestion(json.id,json.data.map((data) => new ODQuestionData(data.id,data.value)))
}
+}
+
+/**## ODDropdownQuestion `class`
+ * An Open Ticket dropdown question. It contains all config properties of the dropdown question type.
+ */
+export class ODDropdownQuestion extends ODQuestion {
+ readonly type: "opendiscord:dropdown" = "opendiscord:dropdown"
+
+ constructor(id:api.ODValidId, data:ODQuestionData[]){
+ super(id,data)
+ }
+
+ static fromJson(json: ODQuestionJson): ODDropdownQuestion {
+ return new ODDropdownQuestion(json.id,json.data.map((data) => new ODQuestionData(data.id,data.value)))
+ }
+}
+
+/**## ODRadioSelectQuestion `class`
+ * An Open Ticket radio-select question. It contains all config properties of the radio-select question type.
+ */
+export class ODRadioSelectQuestion extends ODQuestion {
+ readonly type: "opendiscord:radio-select" = "opendiscord:radio-select"
+
+ constructor(id:api.ODValidId, data:ODQuestionData[]){
+ super(id,data)
+ }
+
+ static fromJson(json: ODQuestionJson): ODRadioSelectQuestion {
+ return new ODRadioSelectQuestion(json.id,json.data.map((data) => new ODQuestionData(data.id,data.value)))
+ }
+}
+
+/**## ODCheckboxSelectQuestion `class`
+ * An Open Ticket checkbox-select question. It contains all config properties of the checkbox-select question type.
+ */
+export class ODCheckboxSelectQuestion extends ODQuestion {
+ readonly type: "opendiscord:checkbox-select" = "opendiscord:checkbox-select"
+
+ constructor(id:api.ODValidId, data:ODQuestionData[]){
+ super(id,data)
+ }
+
+ static fromJson(json: ODQuestionJson): ODCheckboxSelectQuestion {
+ return new ODCheckboxSelectQuestion(json.id,json.data.map((data) => new ODQuestionData(data.id,data.value)))
+ }
+}
+
+/**## ODFileUploadQuestion `class`
+ * An Open Ticket file-upload question. It contains all config properties of the file-upload question type.
+ */
+export class ODFileUploadQuestion extends ODQuestion {
+ readonly type: "opendiscord:file-upload" = "opendiscord:file-upload"
+
+ constructor(id:api.ODValidId, data:ODQuestionData[]){
+ super(id,data)
+ }
+
+ static fromJson(json: ODQuestionJson): ODFileUploadQuestion {
+ return new ODFileUploadQuestion(json.id,json.data.map((data) => new ODQuestionData(data.id,data.value)))
+ }
+}
+
+/**## ODTextDisplayQuestion `class`
+ * An Open Ticket text-display question. It contains all config properties of the text-display question type.
+ */
+export class ODTextDisplayQuestion extends ODQuestion {
+ readonly type: "opendiscord:text-display" = "opendiscord:text-display"
+
+ constructor(id:api.ODValidId, data:ODQuestionData[]){
+ super(id,data)
+ }
+
+ static fromJson(json: ODQuestionJson): ODTextDisplayQuestion {
+ return new ODTextDisplayQuestion(json.id,json.data.map((data) => new ODQuestionData(data.id,data.value)))
+ }
}
\ No newline at end of file
diff --git a/src/core/api/ticket.ts b/src/core/api/ticket.ts
index be33d65..4fd5a24 100644
--- a/src/core/api/ticket.ts
+++ b/src/core/api/ticket.ts
@@ -4,6 +4,7 @@
import * as api from "@open-discord-bots/framework/api"
import { ODTicketOption } from "./option.js"
import * as discord from "discord.js"
+import { ODQuestionAnswer } from "./question.js"
/**## ODTicketIdConstraint `type`
* The constraint/layout for id mappings/interfaces of the `ODTicket` class.
@@ -48,7 +49,7 @@ export interface ODTicketIdMappings extends ODTicketIdConstraint {
"opendiscord:autodelete-enabled":ODTicketData,
"opendiscord:autodelete-days":ODTicketData,
- "opendiscord:answers":ODTicketData<{id:string,name:string,type:"short"|"paragraph",value:string|null}[]>,
+ "opendiscord:answers":ODTicketData,
"opendiscord:priority":ODTicketData,
"opendiscord:topic":ODTicketData,
"opendiscord:message-sent":ODTicketData,
diff --git a/src/core/cli/quickSetup.ts b/src/core/cli/quickSetup.ts
index 408694b..3b3b629 100644
--- a/src/core/cli/quickSetup.ts
+++ b/src/core/cli/quickSetup.ts
@@ -1411,6 +1411,19 @@ async function saveQuickSetupConfig(){
{title:"Choice D",description:"Fear",selectedByDefault:false}
]
},
+ {
+ id:"example-question-6",
+ name:"Example Question 6",
+ description:"This is a file upload question.",
+ type:"file-upload",
+ required:true,
+
+ limits:{
+ enabled:false,
+ min:0,
+ max:1
+ }
+ },
{
id:"example-text-display",
type:"text-display",
diff --git a/src/core/mappings/action.ts b/src/core/mappings/action.ts
index b7a3478..4b1e354 100644
--- a/src/core/mappings/action.ts
+++ b/src/core/mappings/action.ts
@@ -8,6 +8,7 @@ import { ODTicket, ODTicketClearFilter } from "../api/ticket.js"
import { ODTranscriptCompiler, ODTranscriptCompilerCompileResult } from "../api/transcript.js"
import { ODRole, ODRoleUpdateMode, ODRoleUpdateResult } from "../api/role.js"
import { ODPriorityLevel } from "../api/priority.js"
+import { ODQuestionAnswer } from "../api/question.js"
/**## ODActionManagerIdMappings `interface`
* A list of all available IDs in the default `ODActionManager` class in `opendiscord`.
@@ -28,7 +29,7 @@ export interface ODActionManagerIdMappings extends api.ODActionManagerIdConstrai
},
"opendiscord:create-ticket":{
origin:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",
- params:{guild:discord.Guild,user:discord.User,option:ODTicketOption,answers:{id:string,name:string,type:"short"|"paragraph",value:string|null}[]},
+ params:{guild:discord.Guild,user:discord.User,option:ODTicketOption,answers:ODQuestionAnswer[]},
result:{channel:discord.GuildTextBasedChannel,ticket:ODTicket},
workers:"opendiscord:create-ticket"|"opendiscord:send-ticket-message"|"opendiscord:discord-logs"|"opendiscord:logs"
},
diff --git a/src/core/mappings/builder.ts b/src/core/mappings/builder.ts
index 63dcfbe..311b5d7 100644
--- a/src/core/mappings/builder.ts
+++ b/src/core/mappings/builder.ts
@@ -235,14 +235,7 @@ export interface ODMessageManagerIdMappings extends api.ODMessageManagerIdConstr
* It's used to generate typescript declarations for this class.
*/
export interface ODModalManagerIdMappings extends api.ODModalManagerIdConstraint {
- "opendiscord:ticket-questions":{origin:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,option:ODTicketOption},workers:"opendiscord:ticket-questions"}
- "opendiscord:close-ticket-reason":{origin:"ticket-message"|"reopen-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:close-ticket-reason"}
- "opendiscord:reopen-ticket-reason":{origin:"ticket-message"|"close-message"|"autoclose-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:reopen-ticket-reason"}
- "opendiscord:delete-ticket-reason":{origin:"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:delete-ticket-reason"}
- "opendiscord:claim-ticket-reason":{origin:"ticket-message"|"unclaim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:claim-ticket-reason"}
- "opendiscord:unclaim-ticket-reason":{origin:"ticket-message"|"claim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:unclaim-ticket-reason"}
- "opendiscord:pin-ticket-reason":{origin:"ticket-message"|"unpin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:pin-ticket-reason"}
- "opendiscord:unpin-ticket-reason":{origin:"ticket-message"|"pin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:unpin-ticket-reason"}
+ //Deprecated, moved to ODModalComponentManagerIdMappings
}
/////////////////////////////
diff --git a/src/core/mappings/component.ts b/src/core/mappings/component.ts
index db313c6..1e542a3 100644
--- a/src/core/mappings/component.ts
+++ b/src/core/mappings/component.ts
@@ -3,6 +3,8 @@
///////////////////////////////////////
import * as api from "@open-discord-bots/framework/api"
import * as discord from "discord.js"
+import { ODTicketOption } from "../api/option.js"
+import { ODTicket } from "../api/ticket.js"
/**## ODSharedComponentManagerIdMappings `interface`
* A list of all available IDs in the default `ODSharedComponentManager` class in `opendiscord`.
@@ -25,7 +27,14 @@ export interface ODMessageComponentManagerIdMappings extends api.ODComponentMana
* It's used to generate typescript declarations for this class.
*/
export interface ODModalComponentManagerIdMappings extends api.ODComponentManagerIdConstraint {
- //"opendiscord:example-modal":{origin:"slash"|"text"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:example-modal"},
+ "opendiscord:ticket-questions":{origin:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,option:ODTicketOption},workers:"opendiscord:ticket-questions"},
+ "opendiscord:close-ticket-reason":{origin:"ticket-message"|"reopen-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:close-ticket-reason"}
+ "opendiscord:reopen-ticket-reason":{origin:"ticket-message"|"close-message"|"autoclose-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:reopen-ticket-reason"}
+ "opendiscord:delete-ticket-reason":{origin:"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:delete-ticket-reason"}
+ "opendiscord:claim-ticket-reason":{origin:"ticket-message"|"unclaim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:claim-ticket-reason"}
+ "opendiscord:unclaim-ticket-reason":{origin:"ticket-message"|"claim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:unclaim-ticket-reason"}
+ "opendiscord:pin-ticket-reason":{origin:"ticket-message"|"unpin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:pin-ticket-reason"}
+ "opendiscord:unpin-ticket-reason":{origin:"ticket-message"|"pin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:unpin-ticket-reason"}
}
/**## ODComponentModifierManagerIdMappings `interface`
diff --git a/src/core/mappings/config.ts b/src/core/mappings/config.ts
index 4f2114b..51fc926 100644
--- a/src/core/mappings/config.ts
+++ b/src/core/mappings/config.ts
@@ -619,6 +619,18 @@ export interface ODQuestionsJsonConfig_CheckboxLimits {
max:number
}
+/**## ODQuestionsJsonConfig_FileUploadLimits `interface`
+ * Verify the amount of uploaded files in a question.
+ */
+export interface ODQuestionsJsonConfig_FileUploadLimits {
+ /**Enable file limits. */
+ enabled:boolean,
+ /**The minimum amount of uploaded files. */
+ min:number,
+ /**The maximum amount of uploaded files. */
+ max:number
+}
+
/**## ODQuestionsJsonConfig_DropdownChoice `interface`
* A dropdown choice used in `ODQuestionsJsonConfig_DropdownQuestion`
*/
@@ -654,7 +666,7 @@ export interface ODQuestionsJsonConfig_BaseQuestion {
/**The description of this question. (Leave empty for none) */
description:string,
/**The type of this question. */
- type:"short"|"paragraph"|"text-display"|"dropdown"|"radio-select"|"checkbox-select",
+ type:"short"|"paragraph"|"text-display"|"dropdown"|"radio-select"|"checkbox-select"|"file-upload",
/**Is this question required? */
required:boolean,
}
@@ -662,9 +674,7 @@ export interface ODQuestionsJsonConfig_BaseQuestion {
/**## ODQuestionsJsonConfig_TextDisplayQuestion `interface`
* All properties for a text-display in the `questions.jsonc` config!
*/
-export interface ODQuestionsJsonConfig_TextDisplayQuestion {
- /**The id of this text-display. */
- id:string,
+export interface ODQuestionsJsonConfig_TextDisplayQuestion extends Omit {
/**The type of this question. */
type:"text-display",
/**The text contents to show in the modal. */
@@ -724,6 +734,15 @@ export interface ODQuestionsJsonConfig_CheckboxSelectQuestion extends ODQuestion
choices:ODQuestionsJsonConfig_RadioCheckboxChoice[]
}
+/**## ODQuestionsJsonConfig_FileUploadQuestion `interface`
+ * All properties for checkbox select questions in the `questions.jsonc` config!
+ */
+export interface ODQuestionsJsonConfig_FileUploadQuestion extends ODQuestionsJsonConfig_BaseQuestion {
+ type:"file-upload",
+ /**Verify the amount of uploaded files (minimum/maximum). */
+ limits:ODQuestionsJsonConfig_FileUploadLimits
+}
+
/**## ODQuestionsJsonConfig_QuestionsData `type`
* All contents of the `questions.jsonc` config file.
*/
@@ -733,7 +752,8 @@ export type ODQuestionsJsonConfig_QuestionsData = (
ODQuestionsJsonConfig_TextDisplayQuestion|
ODQuestionsJsonConfig_DropdownQuestion|
ODQuestionsJsonConfig_RadioSelectQuestion|
- ODQuestionsJsonConfig_CheckboxSelectQuestion
+ ODQuestionsJsonConfig_CheckboxSelectQuestion|
+ ODQuestionsJsonConfig_FileUploadQuestion
)[]
///////////////////////////////////////
diff --git a/src/core/startup/migration.ts b/src/core/startup/migration.ts
index a62139f..3108fa6 100644
--- a/src/core/startup/migration.ts
+++ b/src/core/startup/migration.ts
@@ -311,6 +311,19 @@ export const migrations = [
{title:"Choice D",description:"Fear",selectedByDefault:false}
]
},
+ {
+ id:"example-file-upload",
+ name:"Example File Upload",
+ description:"With this question type, users can upload one or multiple files.",
+ type:"file-upload",
+ required:true,
+
+ limits:{
+ enabled:false,
+ min:0,
+ max:1
+ }
+ },
{
id:"example-text-display-question",
type:"text-display",
diff --git a/src/data/framework/checkerLoader.ts b/src/data/framework/checkerLoader.ts
index 685732d..a0b1237 100644
--- a/src/data/framework/checkerLoader.ts
+++ b/src/data/framework/checkerLoader.ts
@@ -686,7 +686,21 @@ export const defaultQuestionsStructure = new api.ODCheckerArrayStructure("opendi
],cliDisplayName:"Choice",cliDisplayDescription:"A choice for this checkbox select question."}),cliDisplayName:"Choices",cliDisplayPropertyName:"choice",cliDisplayDescription:"Manage all available choices of this checkbox select question."})}
],cliDisplayName:"Checkbox Select Question",cliDisplayDescription:"Manage, customise and configure the checkbox select question to your preference."})},
-],cliDisplayName:"Question",cliDisplayDescription:"Manage a question of one of the 6 types: short, paragraph, text-display, dropdown, radio-select, checkbox-select."}),cliDisplayName:"Questions",cliDisplayDescription:"A list of all questions in the bot. Here you can add, modify & remove existing questions or customise them to your preference."})
+ //FILE UPLOAD QUESTION
+ {name:"File Upload Question",priority:0,properties:[{key:"type",value:"file-upload"}],checker:new api.ODCheckerObjectStructure("opendiscord:file-upload-question",{cliDisplayKeyInParentArray:"name",cliDisplayAdditionalKeysInParentArray:["id","type"],children:[
+ {key:"id",checker:new api.ODCheckerCustomStructure_UniqueId("opendiscord:question-id","openticket","question-ids",{regex:/^[A-Za-z0-9-รฉรจรงร รชรขรดรปรฎ]+$/,minLength:3,maxLength:40,cliDisplayName:"Id",cliDisplayDescription:"The id of this question. Used in ticket options."})},
+ {key:"name",checker:new api.ODCheckerStringStructure("opendiscord:question-name",{minLength:3,maxLength:45,cliDisplayName:"Name",cliDisplayDescription:"The name of this question."})},
+ {key:"description",checker:new api.ODCheckerStringStructure("opendiscord:question-description",{maxLength:100,cliDisplayName:"Description",cliDisplayDescription:"The description of this question."})},
+ {key:"required",checker:new api.ODCheckerBooleanStructure("opendiscord:question-required",{cliDisplayName:"Required",cliDisplayDescription:"Is this question required? If not, it can be left empty."})},
+
+ {key:"limits",checker:new api.ODCheckerEnabledObjectStructure("opendiscord:amount",{property:"enabled",enabledValue:true,checker:new api.ODCheckerObjectStructure("opendiscord:amount",{children:[
+ {key:"enabled",checker:new api.ODCheckerBooleanStructure("opendiscord:amount-enabled",{cliDisplayName:"Enabled",cliDisplayDescription:"Enable/disable checking the min/max amount of uploaded files."})},
+ {key:"min",checker:new api.ODCheckerNumberStructure("opendiscord:amount-min",{min:0,max:10,floatAllowed:false,cliDisplayName:"Min Amount",cliDisplayDescription:"The minimum amount of uploaded files required."})},
+ {key:"max",checker:new api.ODCheckerNumberStructure("opendiscord:amount-max",{min:1,max:10,floatAllowed:false,cliInitDefaultValue:10,cliDisplayName:"Max Amount",cliDisplayDescription:"The maximum amount of uploaded files allowed."})},
+ ],cliDisplayName:"Upload Limits",cliDisplayDescription:"Verify the minimum or maximum amount of uploaded files."}),cliDisplayName:"Checkbox Limits",cliDisplayDescription:"Verify the minimum or maximum amount of uploaded files."})},
+ ],cliDisplayName:"Checkbox Select Question",cliDisplayDescription:"Manage, customise and configure the file upload question to your preference."})},
+
+],cliDisplayName:"Question",cliDisplayDescription:"Manage a question of one of the 7 types: short, paragraph, text-display, dropdown, radio-select, checkbox-select, file-upload."}),cliDisplayName:"Questions",cliDisplayDescription:"A list of all questions in the bot. Here you can add, modify & remove existing questions or customise them to your preference."})
export const defaultTranscriptsStructure = new api.ODCheckerObjectStructure("opendiscord:transcripts",{children:[
//GENERAL
diff --git a/src/data/framework/configLoader.ts b/src/data/framework/configLoader.ts
index d845586..19e3fe5 100644
--- a/src/data/framework/configLoader.ts
+++ b/src/data/framework/configLoader.ts
@@ -286,6 +286,21 @@ export const defaultQuestionsFormatter = new fjs.TopLevelCommentFormatter(new fj
new fjs.PropertyFormatter("selectedByDefault"),
])),
])},
+ {key:"type",value:"file-upload",formatter:new fjs.ObjectFormatter(null,true,[
+ new fjs.MultiCommentFormatter("A file upload modal question where users can upload one or more files."),
+ new fjs.PropertyFormatter("id"),
+ new fjs.PropertyFormatter("name"),
+ new fjs.PropertyFormatter("description",new fjs.SingleCommentFormatter("Leave empty to disable")),
+ new fjs.PropertyFormatter("type"),
+ new fjs.PropertyFormatter("required"),
+ new fjs.TextFormatter(""),
+ new fjs.ObjectFormatter("limits",true,[
+ new fjs.MultiCommentFormatter("Configure minimum/maximum amount of files to upload."),
+ new fjs.PropertyFormatter("enabled"),
+ new fjs.PropertyFormatter("min"),
+ new fjs.PropertyFormatter("max"),
+ ]),
+ ])},
])))
diff --git a/src/data/openticket/questionLoader.ts b/src/data/openticket/questionLoader.ts
index 0d5d17a..0f5bb15 100644
--- a/src/data/openticket/questionLoader.ts
+++ b/src/data/openticket/questionLoader.ts
@@ -4,13 +4,15 @@ export async function loadAllQuestions(){
const questionConfig = opendiscord.configs.get("opendiscord:questions")
if (!questionConfig) return
- questionConfig.data.forEach((question) => {
- if (question.type == "short"){
- opendiscord.questions.add(loadShortQuestion(question))
- }else if (question.type == "paragraph"){
- opendiscord.questions.add(loadParagraphQuestion(question))
- }
- })
+ for (const question of questionConfig.data){
+ if (question.type === "short") opendiscord.questions.add(loadShortQuestion(question))
+ else if (question.type === "paragraph") opendiscord.questions.add(loadParagraphQuestion(question))
+ else if (question.type === "dropdown") opendiscord.questions.add(loadDropdownQuestion(question))
+ else if (question.type === "radio-select") opendiscord.questions.add(loadRadioSelectQuestion(question))
+ else if (question.type === "checkbox-select") opendiscord.questions.add(loadCheckboxSelectQuestion(question))
+ else if (question.type === "file-upload") opendiscord.questions.add(loadFileUploadQuestion(question))
+ else if (question.type === "text-display") opendiscord.questions.add(loadTextDisplayQuestion(question))
+ }
//update questions on config reload
questionConfig.onReload(async () => {
@@ -18,22 +20,25 @@ export async function loadAllQuestions(){
await opendiscord.questions.loopAll((data,id) => {opendiscord.questions.remove(id)})
//add new questions
- questionConfig.data.forEach((question) => {
- if (question.type == "short"){
- opendiscord.questions.add(loadShortQuestion(question))
- }else if (question.type == "paragraph"){
- opendiscord.questions.add(loadParagraphQuestion(question))
- }
- })
+ for (const question of questionConfig.data){
+ if (question.type === "short") opendiscord.questions.add(loadShortQuestion(question))
+ else if (question.type === "paragraph") opendiscord.questions.add(loadParagraphQuestion(question))
+ else if (question.type === "dropdown") opendiscord.questions.add(loadDropdownQuestion(question))
+ else if (question.type === "radio-select") opendiscord.questions.add(loadRadioSelectQuestion(question))
+ else if (question.type === "checkbox-select") opendiscord.questions.add(loadCheckboxSelectQuestion(question))
+ else if (question.type === "file-upload") opendiscord.questions.add(loadFileUploadQuestion(question))
+ else if (question.type === "text-display") opendiscord.questions.add(loadTextDisplayQuestion(question))
+ }
})
}
export const loadShortQuestion = (option:api.ODQuestionsJsonConfig_ShortQuestion) => {
return new api.ODShortQuestion(option.id,[
new api.ODQuestionData("opendiscord:name",option.name),
+ new api.ODQuestionData("opendiscord:description",option.description),
new api.ODQuestionData("opendiscord:required",option.required),
+
new api.ODQuestionData("opendiscord:placeholder",option.placeholder),
-
new api.ODQuestionData("opendiscord:length-enabled",option.length.enabled),
new api.ODQuestionData("opendiscord:length-min",option.length.min),
new api.ODQuestionData("opendiscord:length-max",option.length.max),
@@ -43,11 +48,64 @@ export const loadShortQuestion = (option:api.ODQuestionsJsonConfig_ShortQuestion
export const loadParagraphQuestion = (option:api.ODQuestionsJsonConfig_ParagraphQuestion) => {
return new api.ODParagraphQuestion(option.id,[
new api.ODQuestionData("opendiscord:name",option.name),
+ new api.ODQuestionData("opendiscord:description",option.description),
new api.ODQuestionData("opendiscord:required",option.required),
+
new api.ODQuestionData("opendiscord:placeholder",option.placeholder),
-
new api.ODQuestionData("opendiscord:length-enabled",option.length.enabled),
new api.ODQuestionData("opendiscord:length-min",option.length.min),
new api.ODQuestionData("opendiscord:length-max",option.length.max),
])
+}
+
+export const loadDropdownQuestion = (option:api.ODQuestionsJsonConfig_DropdownQuestion) => {
+ return new api.ODDropdownQuestion(option.id,[
+ new api.ODQuestionData("opendiscord:name",option.name),
+ new api.ODQuestionData("opendiscord:description",option.description),
+ new api.ODQuestionData("opendiscord:required",option.required),
+
+ new api.ODQuestionData("opendiscord:placeholder",option.placeholder),
+ new api.ODQuestionData("opendiscord:choices",option.choices)
+ ])
+}
+
+export const loadRadioSelectQuestion = (option:api.ODQuestionsJsonConfig_RadioSelectQuestion) => {
+ return new api.ODRadioSelectQuestion(option.id,[
+ new api.ODQuestionData("opendiscord:name",option.name),
+ new api.ODQuestionData("opendiscord:description",option.description),
+ new api.ODQuestionData("opendiscord:required",option.required),
+
+ new api.ODQuestionData("opendiscord:choices",option.choices)
+ ])
+}
+
+export const loadCheckboxSelectQuestion = (option:api.ODQuestionsJsonConfig_CheckboxSelectQuestion) => {
+ return new api.ODCheckboxSelectQuestion(option.id,[
+ new api.ODQuestionData("opendiscord:name",option.name),
+ new api.ODQuestionData("opendiscord:description",option.description),
+ new api.ODQuestionData("opendiscord:required",option.required),
+
+ new api.ODQuestionData("opendiscord:limits-enabled",option.limits.enabled),
+ new api.ODQuestionData("opendiscord:limits-min",option.limits.min),
+ new api.ODQuestionData("opendiscord:limits-max",option.limits.max),
+ new api.ODQuestionData("opendiscord:choices",option.choices)
+ ])
+}
+
+export const loadFileUploadQuestion = (option:api.ODQuestionsJsonConfig_FileUploadQuestion) => {
+ return new api.ODFileUploadQuestion(option.id,[
+ new api.ODQuestionData("opendiscord:name",option.name),
+ new api.ODQuestionData("opendiscord:description",option.description),
+ new api.ODQuestionData("opendiscord:required",option.required),
+
+ new api.ODQuestionData("opendiscord:limits-enabled",option.limits.enabled),
+ new api.ODQuestionData("opendiscord:limits-min",option.limits.min),
+ new api.ODQuestionData("opendiscord:limits-max",option.limits.max),
+ ])
+}
+
+export const loadTextDisplayQuestion = (option:api.ODQuestionsJsonConfig_TextDisplayQuestion) => {
+ return new api.ODTextDisplayQuestion(option.id,[
+ new api.ODQuestionData("opendiscord:text-contents",option.textContents)
+ ])
}
\ No newline at end of file
diff --git a/src/index.ts b/src/index.ts
index 2c61a46..f6afe08 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -647,7 +647,7 @@ const main = async () => {
//load modal builders
opendiscord.log("Loading modals...","system")
if (opendiscord.sharedFuses.getFuse("modalBuildersLoading")){
- await (await import("./builders/modals.js")).registerAllModals()
+ //Deprecated, moved to "modal components"
}
await opendiscord.events.get("onModalBuilderLoad").emit([opendiscord.builders.modals,opendiscord.builders,opendiscord.actions])
await opendiscord.events.get("afterModalBuildersLoaded").emit([opendiscord.builders.modals,opendiscord.builders,opendiscord.actions])
@@ -671,7 +671,7 @@ const main = async () => {
//load modal components
opendiscord.log("Loading modal components...","system")
if (opendiscord.sharedFuses.getFuse("modalComponentsLoading")){
- //TODO!!
+ await (await import("./components/modals.js")).registerModalComponents()
}
await opendiscord.events.get("onModalComponentLoad").emit([opendiscord.components.modals,opendiscord.components,opendiscord.actions])
await opendiscord.events.get("afterModalComponentsLoaded").emit([opendiscord.components.modals,opendiscord.components,opendiscord.actions])