Skip to content

Commit d803911

Browse files
committed
Attempting to use a modal for event create command
1 parent 1ba58bd commit d803911

6 files changed

Lines changed: 161 additions & 84 deletions

File tree

client/src/main/kotlin/org/dreamexposure/discal/client/commands/global/EventCommand.kt

Lines changed: 7 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class EventCommand(
3535
override fun shouldDefer(event: ChatInputInteractionEvent): Boolean {
3636
// check if this is the recur command, if so, check if modal will get sent
3737
return when (event.options[0].name) {
38+
"create" -> false
3839
"recur" -> {
3940
val shouldRecur = event.options[0].getOption("recur")
4041
.flatMap(ApplicationCommandInteractionOption::getValue)
@@ -76,24 +77,6 @@ class EventCommand(
7677
}
7778

7879
private suspend fun create(event: ChatInputInteractionEvent, settings: GuildSettings) {
79-
val name = event.options[0].getOption("name")
80-
.flatMap(ApplicationCommandInteractionOption::getValue)
81-
.map(ApplicationCommandInteractionOptionValue::asString)
82-
.orElse("")
83-
val description = event.options[0].getOption("description")
84-
.flatMap(ApplicationCommandInteractionOption::getValue)
85-
.map(ApplicationCommandInteractionOptionValue::asString)
86-
.orElse("")
87-
val location = event.options[0].getOption("location")
88-
.flatMap(ApplicationCommandInteractionOption::getValue)
89-
.map(ApplicationCommandInteractionOptionValue::asString)
90-
.orElse("")
91-
val calendarNumber = event.options[0].getOption("calendar")
92-
.flatMap(ApplicationCommandInteractionOption::getValue)
93-
.map(ApplicationCommandInteractionOptionValue::asLong)
94-
.map(Long::toInt)
95-
.orElse(1)
96-
9780
// Validate permissions
9881
val hasControlRole = permissionService.hasControlRole(settings.guildId, event.interaction.user.id)
9982
if (!hasControlRole) {
@@ -114,42 +97,12 @@ class EventCommand(
11497
return
11598
}
11699

117-
// Make sure calendar exists
118-
val calendar = calendarService.getCalendar(settings.guildId, calendarNumber)
119-
if (calendar == null) {
120-
event.createFollowup(getCommonMsg("error.notFound.calendar", settings.locale))
121-
.withEphemeral(ephemeral)
122-
.awaitSingle()
123-
return
124-
}
125-
126-
val newWizard = EventWizardState(
127-
guildId = settings.guildId,
128-
userId = event.interaction.user.id,
129-
editing = false,
130-
entity = Event.PartialEvent(
131-
id = null,
132-
guildId = settings.guildId,
133-
calendarNumber = calendarNumber,
134-
name = name,
135-
description = description,
136-
location = location,
137-
color = EventColor.NONE,
138-
start = null,
139-
end = null,
140-
recur = false,
141-
recurrence = null,
142-
image = null,
143-
timezone = calendar.timezone,
144-
)
145-
)
146-
calendarService.putEventWizard(newWizard)
147-
148-
event.createFollowup(getMessage("create.success", settings))
149-
.withEphemeral(ephemeral)
150-
.withEmbeds(embedService.eventWizardEmbed(newWizard, settings))
151-
.withComponents(*componentService.getWizardComponents(newWizard, settings))
152-
.awaitSingle()
100+
// Pop modal
101+
event.presentModal()
102+
.withCustomId("event-wizard.create-event")
103+
.withTitle(getCommonMsg("modal.event.create.title", settings.locale))
104+
.withComponents(*componentService.getEventCreateModalComponents(settings, calendarService.getAllCalendars(settings.guildId)))
105+
.awaitSingleOrNull()
153106
}
154107

155108
private suspend fun name(event: ChatInputInteractionEvent, settings: GuildSettings) {
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package org.dreamexposure.discal.client.interaction
2+
3+
import discord4j.core.event.domain.interaction.ModalSubmitInteractionEvent
4+
import discord4j.core.`object`.component.StringSelectMenu
5+
import discord4j.core.`object`.component.TextInput
6+
import kotlinx.coroutines.reactor.awaitSingle
7+
import org.dreamexposure.discal.core.business.CalendarService
8+
import org.dreamexposure.discal.core.business.ComponentService
9+
import org.dreamexposure.discal.core.business.EmbedService
10+
import org.dreamexposure.discal.core.business.PermissionService
11+
import org.dreamexposure.discal.core.enums.event.EventColor
12+
import org.dreamexposure.discal.core.`object`.new.Event
13+
import org.dreamexposure.discal.core.`object`.new.EventWizardState
14+
import org.dreamexposure.discal.core.`object`.new.GuildSettings
15+
import org.dreamexposure.discal.core.utils.getCommonMsg
16+
import org.springframework.stereotype.Component
17+
18+
@Component
19+
class EventCreateModal(
20+
private val permissionService: PermissionService,
21+
private val calendarService: CalendarService,
22+
private val embedService: EmbedService,
23+
private val componentService: ComponentService,
24+
): InteractionHandler<ModalSubmitInteractionEvent> {
25+
override val ids = arrayOf("event-wizard.create-event")
26+
override val ephemeral = true
27+
28+
override suspend fun handle(event: ModalSubmitInteractionEvent, settings: GuildSettings) {
29+
val textInputs = event.getComponents(TextInput::class.java)
30+
val selectInputs = event.getComponents(StringSelectMenu::class.java)
31+
32+
val name = textInputs.first { it.customId == "event.create.name" }
33+
.value
34+
.orElse("")
35+
val description = textInputs.first { it.customId == "event.create.description" }
36+
.value
37+
.orElse("")
38+
val location = textInputs.first { it.customId == "event.create.location" }
39+
.value
40+
.orElse("")
41+
val calendarNumber = selectInputs.first { it.customId == "event.create.calendar" }
42+
.values
43+
.get()
44+
.first()
45+
.toInt()
46+
47+
48+
// Validate permissions
49+
val hasControlRole = permissionService.hasControlRole(settings.guildId, event.interaction.user.id)
50+
if (!hasControlRole) {
51+
event.createFollowup(getCommonMsg("error.perms.privileged", settings.locale))
52+
.withEphemeral(ephemeral)
53+
.awaitSingle()
54+
return
55+
}
56+
57+
// Check if wizard already started
58+
val existingWizard = calendarService.getEventWizard(settings.guildId, event.interaction.user.id)
59+
if (existingWizard != null) {
60+
event.createFollowup(getCommonMsg("error.event.wizard.started", settings.locale))
61+
.withEphemeral(ephemeral)
62+
.withEmbeds(embedService.eventWizardEmbed(existingWizard, settings))
63+
.withComponents(*componentService.getWizardComponents(existingWizard, settings))
64+
.awaitSingle()
65+
return
66+
}
67+
68+
// Make sure calendar exists
69+
val calendar = calendarService.getCalendar(settings.guildId, calendarNumber)
70+
if (calendar == null) {
71+
event.createFollowup(getCommonMsg("error.notFound.calendar", settings.locale))
72+
.withEphemeral(ephemeral)
73+
.awaitSingle()
74+
return
75+
}
76+
77+
val newWizard = EventWizardState(
78+
guildId = settings.guildId,
79+
userId = event.interaction.user.id,
80+
editing = false,
81+
entity = Event.PartialEvent(
82+
id = null,
83+
guildId = settings.guildId,
84+
calendarNumber = calendarNumber,
85+
name = name,
86+
description = description,
87+
location = location,
88+
color = EventColor.NONE,
89+
start = null,
90+
end = null,
91+
recur = false,
92+
recurrence = null,
93+
image = null,
94+
timezone = calendar.timezone,
95+
)
96+
)
97+
calendarService.putEventWizard(newWizard)
98+
99+
event.createFollowup(getCommonMsg("modal.event.create.success", settings.locale))
100+
.withEphemeral(ephemeral)
101+
.withEmbeds(embedService.eventWizardEmbed(newWizard, settings))
102+
.withComponents(*componentService.getWizardComponents(newWizard, settings))
103+
.awaitSingle()
104+
}
105+
}

core/src/main/kotlin/org/dreamexposure/discal/core/business/ComponentService.kt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package org.dreamexposure.discal.core.business
33
import discord4j.common.util.Snowflake
44
import discord4j.core.`object`.component.*
55
import discord4j.core.`object`.emoji.Emoji
6+
import org.dreamexposure.discal.core.extensions.autocompleteSafe
7+
import org.dreamexposure.discal.core.extensions.toMarkdown
68
import org.dreamexposure.discal.core.`object`.new.*
79
import org.dreamexposure.discal.core.utils.getCommonMsg
810
import org.springframework.stereotype.Component
@@ -69,6 +71,37 @@ class ComponentService {
6971
return arrayOf(ActionRow.of(confirmButton, cancelButton))
7072
}
7173

74+
fun getEventCreateModalComponents(settings: GuildSettings, calendars: List<Calendar>): Array<LayoutComponent> {
75+
val nameInput = TextInput.small("event.create.name")
76+
.placeholder(getCommonMsg("modal.event.create.name.placeholder", settings.locale))
77+
.required(false)
78+
79+
val descriptionInput = TextInput.paragraph("event.create.description")
80+
.placeholder(getCommonMsg("modal.event.create.description.placeholder", settings.locale))
81+
.required(false)
82+
83+
val locationInput = TextInput.small("event.create.location")
84+
.placeholder(getCommonMsg("modal.event.create.location.placeholder", settings.locale))
85+
.required(false)
86+
87+
// Generate calendar options
88+
val calendarOptions = calendars.subList(0, 25.coerceAtMost(calendars.size)).map {
89+
SelectMenu.Option.of("[${it.metadata.number}] ${it.name.toMarkdown().autocompleteSafe(6)}", it.metadata.number.toString())
90+
.withDefault(it.metadata.number == 1)
91+
}
92+
val calendarSelect = SelectMenu.of("event.create.calendar", calendarOptions)
93+
.withPlaceholder(getCommonMsg("modal.event.create.calendar.placeholder", settings.locale))
94+
.required(true)
95+
96+
97+
return arrayOf(
98+
Label.of(getCommonMsg("modal.event.create.name.label", settings.locale), nameInput),
99+
Label.of(getCommonMsg("modal.event.create.description.label", settings.locale), descriptionInput),
100+
Label.of(getCommonMsg("modal.event.create.location.label", settings.locale), locationInput),
101+
Label.of(getCommonMsg("modal.event.create.calendar.label", settings.locale), calendarSelect),
102+
)
103+
}
104+
72105
fun getEventRecurrenceWeeklyModalComponents(settings: GuildSettings, event: Event.PartialEvent): Array<LayoutComponent> {
73106
// Determine pre-selected days
74107
val selectedDays = emptyList<DayOfWeek>().toMutableList()

core/src/main/resources/commands/global/event.json

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,7 @@
66
"name": "create",
77
"type": 1,
88
"description": "Starts the event creation wizard",
9-
"required": false,
10-
"options": [
11-
{
12-
"name": "name",
13-
"type": 3,
14-
"description": "The name of the new event",
15-
"required": false
16-
},
17-
{
18-
"name": "description",
19-
"type": 3,
20-
"description": "The description of the new event",
21-
"required": false
22-
},
23-
{
24-
"name": "location",
25-
"type": 3,
26-
"description": "The location of the new event",
27-
"required": false
28-
},
29-
{
30-
"name": "calendar",
31-
"type": 4,
32-
"description": "The calendar to create the event in (defaults to 1)",
33-
"autocomplete":true,
34-
"required": false,
35-
"min_value": 1
36-
}
37-
]
9+
"required": false
3810
},
3911
{
4012
"name": "name",

core/src/main/resources/i18n/command/event/event.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
create.success=event wizard started! Please supply required information and then confirm the creation of your new \
1+
create.success=Event wizard started! Please supply required information and then confirm the creation of your new \
22
event with `/event confirm`
33

44
name.success=Successfully set the name of the event.

core/src/main/resources/i18n/common.properties

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ error.format.snowflake.message=Invalid Message ID provided. To get an ID see: \
3434

3535
error.event.ended=That event has already ended!
3636
error.event.wizard.notStarted=The event wizard has not been started yet.
37+
error.event.wizard.started=Event wizard has already been started.
3738

3839
error.calendar.max=The max amount of calendars have already been created. Consider supporting at \
3940
https://patreon.com/Novafox to unlock a greater limit.
@@ -48,6 +49,19 @@ dropdown.rsvp.option.not-going.label=Not going
4849
dropdown.rsvp.option.undecided.label=Undecided
4950
dropdown.rsvp.response.unexpected-option=The selected option was not recognized, please try again
5051

52+
# Event create menus
53+
modal.event.create.title=Create Event
54+
modal.event.create.name.label=Name
55+
modal.event.create.name.placeholder=The name of your event...
56+
modal.event.create.description.label=Description
57+
modal.event.create.description.placeholder=A longer form description of your event...
58+
modal.event.create.location.label=Location
59+
modal.event.create.location.placeholder=Where your event is taking place...
60+
modal.event.create.calendar.label=Calendar
61+
modal.event.create.calendar.placeholder=The calendar to schedule your event on
62+
modal.event.create.success=Event wizard started! Please supply required information and then confirm the creation of your new \
63+
event with `/event confirm`
64+
5165
# Event Recurrence menus
5266
select.event.recurrence.days.label=Days of Week
5367
select.event.recurrence.month.label=Monthly Recurrence Options

0 commit comments

Comments
 (0)