add a manual tester in favor of playground
This commit is contained in:
@@ -39,8 +39,8 @@
|
||||
"build-watch": "pnpm build -- --watch",
|
||||
"test": "vitest --coverage --no-watch",
|
||||
"test-dev": "vitest",
|
||||
"test-manual": "nodemon --exec tsx --ext ts,tsx ./scripts/discordjs-manual-test.tsx",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"playground": "nodemon --exec esmo --ext ts,tsx --inspect=5858 --enable-source-maps ./playground/main.tsx",
|
||||
"release": "bash scripts/release.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -65,9 +65,6 @@
|
||||
"c8": "^7.11.2",
|
||||
"discord.js": "^14.0.3",
|
||||
"dotenv": "^16.0.0",
|
||||
"esbuild": "latest",
|
||||
"esbuild-jest": "^0.5.0",
|
||||
"esmo": "^0.14.1",
|
||||
"lodash-es": "^4.17.21",
|
||||
"nodemon": "^2.0.15",
|
||||
"prettier": "^2.6.2",
|
||||
@@ -75,6 +72,7 @@
|
||||
"react": "^18.0.0",
|
||||
"release-it": "^14.14.2",
|
||||
"tsup": "^5.12.6",
|
||||
"tsx": "^3.8.0",
|
||||
"type-fest": "^2.12.2",
|
||||
"typescript": "^4.6.3",
|
||||
"vite": "^2.9.5",
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
import type { Client, CommandInteraction } from "discord.js"
|
||||
|
||||
type Command = {
|
||||
name: string
|
||||
description: string
|
||||
run: (interaction: CommandInteraction) => unknown
|
||||
}
|
||||
|
||||
export function createCommandHandler(client: Client, commands: Command[]) {
|
||||
client.on("ready", async () => {
|
||||
for (const command of commands) {
|
||||
for (const guild of client.guilds.cache.values()) {
|
||||
await client.application?.commands.create(
|
||||
{
|
||||
name: command.name,
|
||||
description: command.description,
|
||||
},
|
||||
guild.id,
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
client.on("interactionCreate", async (interaction) => {
|
||||
if (!interaction.isChatInputCommand()) return
|
||||
|
||||
const command = commands.find(
|
||||
(command) => command.name === interaction.commandName,
|
||||
)
|
||||
if (command) {
|
||||
try {
|
||||
await command.run(interaction)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import * as React from "react"
|
||||
import { Button, Embed, EmbedField, EmbedTitle } from "../library/main"
|
||||
|
||||
export function Counter(props: { onDeactivate: () => void }) {
|
||||
const [count, setCount] = React.useState(0)
|
||||
const [embedVisible, setEmbedVisible] = React.useState(false)
|
||||
|
||||
return (
|
||||
<>
|
||||
this button was clicked {count} times
|
||||
{embedVisible && (
|
||||
<Embed>
|
||||
<EmbedTitle>the counter</EmbedTitle>
|
||||
{count > 0 && (
|
||||
<EmbedField name="is it even?">
|
||||
{count % 2 === 0 ? "yes" : "no"}
|
||||
</EmbedField>
|
||||
)}
|
||||
</Embed>
|
||||
)}
|
||||
{embedVisible && (
|
||||
<Button label="hide embed" onClick={() => setEmbedVisible(false)} />
|
||||
)}
|
||||
<Button
|
||||
style="primary"
|
||||
emoji="<:plus_one:778531744860602388>"
|
||||
label="clicc"
|
||||
onClick={() => setCount(count + 1)}
|
||||
/>
|
||||
{!embedVisible && (
|
||||
<Button label="show embed" onClick={() => setEmbedVisible(true)} />
|
||||
)}
|
||||
<Button style="danger" label="deactivate" onClick={props.onDeactivate} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import React, { useState } from "react"
|
||||
import { Button, Option, Select } from "../library/main"
|
||||
|
||||
export function FruitSelect({
|
||||
onConfirm,
|
||||
}: {
|
||||
onConfirm: (choice: string) => void
|
||||
}) {
|
||||
const [value, setValue] = useState<string>()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Select
|
||||
placeholder="choose a fruit"
|
||||
value={value}
|
||||
onChangeValue={setValue}
|
||||
>
|
||||
<Option value="🍎" />
|
||||
<Option value="🍌" />
|
||||
<Option value="🍒" />
|
||||
</Select>
|
||||
<Button
|
||||
label="confirm"
|
||||
disabled={value == undefined}
|
||||
onClick={() => {
|
||||
if (value) onConfirm(value)
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
import { Client, IntentsBitField } from "discord.js"
|
||||
import "dotenv/config"
|
||||
import React from "react"
|
||||
import { Button, ReacordDiscordJs, useInstance } from "../library/main"
|
||||
import { createCommandHandler } from "./command-handler"
|
||||
import { Counter } from "./counter"
|
||||
import { FruitSelect } from "./fruit-select"
|
||||
|
||||
const client = new Client({
|
||||
intents: IntentsBitField.Flags.Guilds,
|
||||
})
|
||||
|
||||
const reacord = new ReacordDiscordJs(client)
|
||||
|
||||
client.on("ready", () => {
|
||||
console.info("ready 💖")
|
||||
|
||||
// const now = new Date()
|
||||
|
||||
// function UptimeCounter() {
|
||||
// const [uptime, setUptime] = React.useState(0)
|
||||
|
||||
// React.useEffect(() => {
|
||||
// const interval = setInterval(() => {
|
||||
// setUptime(Date.now() - now.getTime())
|
||||
// }, 5000)
|
||||
// return () => clearInterval(interval)
|
||||
// }, [])
|
||||
|
||||
// return (
|
||||
// <Embed>this bot has been running for {prettyMilliseconds(uptime)}</Embed>
|
||||
// )
|
||||
// }
|
||||
|
||||
// reacord.send("671787605624487941", <UptimeCounter />)
|
||||
})
|
||||
|
||||
createCommandHandler(client, [
|
||||
{
|
||||
name: "button",
|
||||
description: "it's a button",
|
||||
run: (interaction) => {
|
||||
reacord.reply(
|
||||
interaction,
|
||||
<Button label="clic" onClick={() => console.info("was clic")} />,
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "counter",
|
||||
description: "shows a counter button",
|
||||
run: (interaction) => {
|
||||
const reply = reacord.reply(interaction)
|
||||
reply.render(<Counter onDeactivate={() => reply.destroy()} />)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "select",
|
||||
description: "shows a select",
|
||||
run: (interaction) => {
|
||||
const instance = reacord.reply(
|
||||
interaction,
|
||||
<FruitSelect
|
||||
onConfirm={(value) => {
|
||||
instance.render(`you chose ${value}`)
|
||||
instance.deactivate()
|
||||
}}
|
||||
/>,
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ephemeral-button",
|
||||
description: "button which shows ephemeral messages",
|
||||
run: (interaction) => {
|
||||
reacord.reply(
|
||||
interaction,
|
||||
<>
|
||||
<Button
|
||||
label="public clic"
|
||||
onClick={(event) =>
|
||||
reacord.reply(
|
||||
interaction,
|
||||
`${event.guild?.member.displayName} clic`,
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
label="clic"
|
||||
onClick={(event) => event.ephemeralReply("you clic")}
|
||||
/>
|
||||
</>,
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "delete-this",
|
||||
description: "delete this",
|
||||
run: (interaction) => {
|
||||
function DeleteThis() {
|
||||
const instance = useInstance()
|
||||
return <Button label="delete this" onClick={() => instance.destroy()} />
|
||||
}
|
||||
reacord.reply(interaction, <DeleteThis />)
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
await client.login(process.env.TEST_BOT_TOKEN)
|
||||
134
packages/reacord/scripts/discordjs-manual-test.tsx
Normal file
134
packages/reacord/scripts/discordjs-manual-test.tsx
Normal file
@@ -0,0 +1,134 @@
|
||||
import type { TextChannel } from "discord.js"
|
||||
import { ChannelType, Client, IntentsBitField } from "discord.js"
|
||||
import "dotenv/config"
|
||||
import { kebabCase } from "lodash-es"
|
||||
import * as React from "react"
|
||||
import { useState } from "react"
|
||||
import {
|
||||
Button,
|
||||
Option,
|
||||
ReacordDiscordJs,
|
||||
Select,
|
||||
useInstance,
|
||||
} from "../library/main"
|
||||
|
||||
const client = new Client({ intents: IntentsBitField.Flags.Guilds })
|
||||
const reacord = new ReacordDiscordJs(client)
|
||||
|
||||
await client.login(process.env.TEST_BOT_TOKEN)
|
||||
|
||||
const guild = await client.guilds.fetch(process.env.TEST_GUILD_ID!)
|
||||
|
||||
const category = await guild.channels.fetch(process.env.TEST_CATEGORY_ID!)
|
||||
if (category?.type !== ChannelType.GuildCategory) {
|
||||
throw new Error(
|
||||
`channel ${process.env.TEST_CATEGORY_ID} is not a guild category. received ${category?.type}`,
|
||||
)
|
||||
}
|
||||
|
||||
for (const [, channel] of category.children.cache) {
|
||||
await channel.delete()
|
||||
}
|
||||
|
||||
let prefix = 0
|
||||
const createTest = async (
|
||||
name: string,
|
||||
block: (channel: TextChannel) => void | Promise<unknown>,
|
||||
) => {
|
||||
prefix += 1
|
||||
const channel = await category.children.create({
|
||||
type: ChannelType.GuildText,
|
||||
name: `${String(prefix).padStart(3, "0")}-${kebabCase(name)}`,
|
||||
})
|
||||
await block(channel)
|
||||
}
|
||||
|
||||
await createTest("basic", (channel) => {
|
||||
reacord.send(channel.id, "Hello, world!")
|
||||
})
|
||||
|
||||
await createTest("counter", (channel) => {
|
||||
const Counter = () => {
|
||||
const [count, setCount] = React.useState(0)
|
||||
return (
|
||||
<>
|
||||
count: {count}
|
||||
<Button
|
||||
style="primary"
|
||||
emoji="➕"
|
||||
onClick={() => setCount(count + 1)}
|
||||
/>
|
||||
<Button
|
||||
style="primary"
|
||||
emoji="➖"
|
||||
onClick={() => setCount(count - 1)}
|
||||
/>
|
||||
<Button label="reset" onClick={() => setCount(0)} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
reacord.send(channel.id, <Counter />)
|
||||
})
|
||||
|
||||
await createTest("select", (channel) => {
|
||||
function FruitSelect({ onConfirm }: { onConfirm: (choice: string) => void }) {
|
||||
const [value, setValue] = useState<string>()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Select
|
||||
placeholder="choose a fruit"
|
||||
value={value}
|
||||
onChangeValue={setValue}
|
||||
>
|
||||
<Option value="🍎" />
|
||||
<Option value="🍌" />
|
||||
<Option value="🍒" />
|
||||
</Select>
|
||||
<Button
|
||||
label="confirm"
|
||||
disabled={value == undefined}
|
||||
onClick={() => {
|
||||
if (value) onConfirm(value)
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const instance = reacord.send(
|
||||
channel.id,
|
||||
<FruitSelect
|
||||
onConfirm={(value) => {
|
||||
instance.render(`you chose ${value}`)
|
||||
instance.deactivate()
|
||||
}}
|
||||
/>,
|
||||
)
|
||||
})
|
||||
|
||||
await createTest("ephemeral button", (channel) => {
|
||||
reacord.send(
|
||||
channel.id,
|
||||
<>
|
||||
<Button
|
||||
label="public clic"
|
||||
onClick={(event) =>
|
||||
event.reply(`${event.guild?.member.displayName} clic`)
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
label="clic"
|
||||
onClick={(event) => event.ephemeralReply("you clic")}
|
||||
/>
|
||||
</>,
|
||||
)
|
||||
})
|
||||
|
||||
await createTest("delete this", (channel) => {
|
||||
function DeleteThis() {
|
||||
const instance = useInstance()
|
||||
return <Button label="delete this" onClick={() => instance.destroy()} />
|
||||
}
|
||||
reacord.send(channel.id, <DeleteThis />)
|
||||
})
|
||||
Reference in New Issue
Block a user