Skip to content

Commit f9bf28e

Browse files
committed
Toasts
1 parent 9c44a41 commit f9bf28e

File tree

4 files changed

+81
-31
lines changed

4 files changed

+81
-31
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"react-dom": "17.0.2",
1717
"react-markdown": "^7.1.1",
1818
"react-modal": "^3.14.4",
19+
"react-toastify": "^8.1.0",
1920
"sharp": "^0.29.3"
2021
},
2122
"devDependencies": {

pages/_app.tsx

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
import type { AppProps } from "next/app"
22
import Head from "next/head"
33
import { useEffect } from "react"
4+
import { ToastContainer } from "react-toastify"
5+
import "react-toastify/dist/ReactToastify.css"
46
import "tailwindcss/tailwind.css"
57
import Footer from "../components/Footer"
68
import NavBar from "../components/NavBar"
7-
import * as gtag from "../utils/gtag"
89
import "../public/global.css"
9-
import ReactModal from "react-modal"
10+
import * as gtag from "../utils/gtag"
11+
12+
const contextClass = {
13+
success: "bg-green-600 dark:bg-green-900",
14+
error: "bg-red-600 dark:bg-red-900",
15+
info: "bg-gray-600 dark:bg-gray-900",
16+
warning: "bg-orange-400 dark:bg-orange-800",
17+
default: "bg-indigo-600 dark:bg-indigo-900",
18+
dark: "bg-white-600 dark:bg-white-900",
19+
}
1020

1121
export default function MyApp({ Component, pageProps, router }: AppProps) {
1222
useEffect(() => {
@@ -27,10 +37,17 @@ export default function MyApp({ Component, pageProps, router }: AppProps) {
2737
</Head>
2838

2939
<div className="w-full">
30-
<NavBar location={router.asPath}/>
40+
<NavBar location={router.asPath} />
3141
<div className="p-4 flex flex-col w-full flex-1 px-1 lg:px-20 items-center justify-center">
32-
<Component {...pageProps} location={router.asPath}/>
42+
<Component {...pageProps} location={router.asPath} />
3343
</div>
44+
<ToastContainer
45+
toastClassName={({ type = "default" } = {}) => contextClass[type || "default"] +
46+
" relative flex p-1 min-h-10 rounded-md justify-between overflow-hidden cursor-pointer"
47+
}
48+
position="bottom-center"
49+
theme={"colored"}
50+
/>
3451
</div>
3552
<Footer />
3653
</div>

pages/tools/reminders.tsx

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { serialize } from "cookie"
22
import { GetServerSideProps } from "next"
33
import Head from "next/head"
4-
import { useRouter } from "next/router"
54
import { Component, useEffect, useState } from "react"
65
import ReactModal from "react-modal"
6+
import { toast } from "react-toastify"
77
import Main from "../../components/Main"
88
import { config } from "../../utils/config"
99
import { parseUser } from "../../utils/parse-user"
@@ -86,10 +86,7 @@ export default class Reminders extends Component<Props, { reminders: Reminder[],
8686
})}
8787
/>)}
8888
<div className="flex flex-wrap gap-2">
89-
<span className="bg-blue-600 text-slate-50 w-fit px-3 py-1 text-center rounded-lg mt-2 cursor-pointer" onClick={() => fetch("/api/sendmessage", {
90-
headers: { "Content-Type": "application/json" },
91-
method: "POST"
92-
})}>Send test message</span>
89+
<span className="bg-blue-600 text-slate-50 w-fit px-3 py-1 text-center rounded-lg mt-2 cursor-pointer" onClick={() => sendTest()}>Send test message</span>
9390
<span className="bg-green-600 text-slate-50 w-fit px-3 py-1 text-center rounded-lg mt-2 cursor-pointer" onClick={() => this.setState({ createReminderOpen: true })}>Create reminder</span>
9491
<CreateReminder
9592
isOpen={this.state.createReminderOpen}
@@ -101,14 +98,21 @@ export default class Reminders extends Component<Props, { reminders: Reminder[],
10198
)
10299
}
103100
}
101+
async function sendTest() {
102+
const res = await fetch("/api/sendmessage", {
103+
headers: { "Content-Type": "application/json" },
104+
method: "POST"
105+
})
106+
if (res.status == 200)
107+
toast.success("Successfully send test message")
108+
else toast.error("An error occurred while sending a test message: " + await res.text())
109+
}
104110

105111
function CreateReminder({ isOpen, requestClose, addReminder }: { isOpen: boolean, requestClose: () => void, addReminder: (r: Reminder) => void }) {
106112
const [name, setName] = useState("")
107113
const [duration, setDuration] = useState("")
108114
const [target, setTarget] = useState(formatTime(new Date()))
109115

110-
const [error, setError] = useState("")
111-
112116
useEffect(() => {
113117
setTarget(formatTime(new Date(Date.now() + parseDuration(duration))))
114118

@@ -125,32 +129,26 @@ function CreateReminder({ isOpen, requestClose, addReminder }: { isOpen: boolean
125129
}, [duration])
126130

127131
async function createReminder(name: string, duration: string) {
128-
if (name.length > 128) return setError("Name too long")
129-
if (name.length == 0) return setError("No name given")
130-
if (duration.length == 0) return setError("No duration given")
131-
if (parseDuration(duration) < 120000) return setError("Duration is too short (at least 2 minutes)")
132+
if (name.length > 128) return toast.error("Name too long")
133+
if (name.length == 0) return toast.error("No name given")
134+
if (duration.length == 0) return toast.error("No duration given")
135+
if (parseDuration(duration) < 120000) return toast.error("Duration is too short (at least 2 minutes)")
132136

133137
const res = await send("/api/reminders/create", { name, duration })
134138

135139
if ((res.status >= 200 && res.status < 300)) {
136140
requestClose()
137141
addReminder(await res.json())
138142

143+
toast.success("Created reminder!")
144+
139145
setName("")
140146
setDuration("")
141147
} else {
142-
return setError("An error occurred... Try again later")
148+
return toast.error("An error occurred... Try again later")
143149
}
144150
}
145151
return <ReactModal style={modalStyle} isOpen={isOpen} onRequestClose={requestClose} ariaHideApp={false}>
146-
<ReactModal style={erorrModalStyle} isOpen={error.length > 0} onRequestClose={() => setError("")} ariaHideApp={false}>
147-
<div className="flex flex-1 justify-center items-center h-full" onKeyDown={() => setError("")}>
148-
<div className="font-semibold text-xl">
149-
{error}
150-
</div>
151-
</div>
152-
</ReactModal>
153-
154152
<h4 className="text-lg font-semibold">Create a reminder</h4>
155153
<div className="flex flex-col">
156154
<form onSubmit={(e) => {
@@ -161,15 +159,31 @@ function CreateReminder({ isOpen, requestClose, addReminder }: { isOpen: boolean
161159
<TextInput value={name} set={setName} placeholder="Enter a name" maxLength={128} label="Name:" />
162160
<TextInput value={duration} set={setDuration} placeholder="Enter a duration (ex. 10 hours 2 resin 5s)" maxLength={128} label="Duration:" />
163161
<div>Will trigger {parseDuration(duration) > 0 && <>in <span className="text-slate-100">{timeLeft(formatDuration(parseDuration(duration)), true)}</span></>} on <span className="text-slate-100">{target}</span></div>
164-
<button className="bg-green-600 disabled:bg-slate-900 text-slate-50 disabled:text-slate-400 w-fit px-3 py-1 text-center rounded-lg mt-2 cursor-pointer" formAction="submit" disabled={duration.length == 0 || name.length == 0 || parseDuration(duration) < 120000}>Create reminder</button>
162+
<button
163+
className="bg-green-600 disabled:bg-slate-900 text-slate-50 disabled:text-slate-400 w-fit px-3 py-1 text-center rounded-lg mt-2 cursor-pointer"
164+
formAction="submit"
165+
disabled={duration.length == 0 || name.length == 0 || parseDuration(duration) < 120000}
166+
>
167+
Create reminder
168+
</button>
165169
</form>
166170
</div>
167171
<br />
168172

169173
<h4 className="text-lg font-semibold">Presets</h4>
170174
<div className="flex flex-wrap gap-2">
171-
<span className="bg-green-600 text-slate-50 w-fit px-3 py-1 text-center rounded-lg mt-2 cursor-pointer" onClick={() => createReminder("Parametric", "6d22h")}>Parametric (6d22h)</span>
172-
<span className="bg-green-600 text-slate-50 w-fit px-3 py-1 text-center rounded-lg mt-2 cursor-pointer" onClick={() => createReminder("Ores", "72h")}>Ores (72h)</span>
175+
<span
176+
className="bg-green-600 text-slate-50 w-fit px-3 py-1 text-center rounded-lg mt-2 cursor-pointer"
177+
onClick={() => createReminder("Parametric", "6d22h")}
178+
>
179+
Parametric (6d22h)
180+
</span>
181+
<span
182+
className="bg-green-600 text-slate-50 w-fit px-3 py-1 text-center rounded-lg mt-2 cursor-pointer"
183+
onClick={() => createReminder("Ores", "72h")}
184+
>
185+
Ores (72h)
186+
</span>
173187
</div>
174188
</ReactModal>
175189
}
@@ -188,7 +202,7 @@ function TextInput({ value, set, maxLength, placeholder, label }: { value: strin
188202
}
189203

190204
function formatTime(date: Date) {
191-
return date.toLocaleString(undefined, { day: "numeric", year: "numeric", month: "short", hour: "2-digit", minute: "2-digit", second:"2-digit" })
205+
return date.toLocaleString(undefined, { day: "numeric", year: "numeric", month: "short", hour: "2-digit", minute: "2-digit", second: "2-digit" })
192206
}
193207

194208
function formatDuration(duration: number) {
@@ -211,13 +225,13 @@ function ReminderCard({ r, onDelete }: { r: Reminder, onDelete: () => void }) {
211225

212226
function DiscordAvatar({ user }: { user: DiscordUser }) {
213227
// eslint-disable-next-line @next/next/no-img-element
214-
return <img
215-
src={user.avatar ? `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.webp?size=16` : "https://discord.com/assets/1f0bfc0865d324c2587920a7d80c609b.png"}
228+
return user.avatar ? <img
229+
src={`https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.webp?size=16`}
216230
alt="Discord avatar"
217231
width={16}
218232
height={16}
219233
className="rounded-xl p-0 m-0 inline-block"
220-
/>
234+
/> : <></>
221235
}
222236

223237
export const getServerSideProps: GetServerSideProps<Props> = async function (ctx) {

pnpm-lock.yaml

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)