223 lines
8.1 KiB
TypeScript
223 lines
8.1 KiB
TypeScript
"use client";
|
|
|
|
import axios from "axios";
|
|
import { useState } from "react";
|
|
import { Button } from "../ui/button";
|
|
import { useRouter } from "next/navigation";
|
|
import { v4 } from "uuid";
|
|
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command";
|
|
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
|
import { Input } from "../ui/input";
|
|
import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
|
|
import { env } from "process";
|
|
|
|
export interface Connection {
|
|
name: string
|
|
type: string
|
|
clientId: string
|
|
scope: string
|
|
expiresAt: Date
|
|
remover: (name: string) => void
|
|
}
|
|
|
|
const AUTHORIZATION_DATA: { [service: string]: { type: string, endpoint: string, grantType: string, scopes: string[], redirect: string } } = {
|
|
'nightbot': {
|
|
type: 'nightbot',
|
|
endpoint: 'https://api.nightbot.tv/oauth2/authorize',
|
|
grantType: 'token',
|
|
scopes: ['song_requests', 'song_requests_queue', 'song_requests_playlist'],
|
|
redirect: 'https://tomtospeech.com/connection/authorize'
|
|
},
|
|
'twitch': {
|
|
type: 'twitch',
|
|
endpoint: 'https://id.twitch.tv/oauth2/authorize',
|
|
grantType: 'token',
|
|
scopes: [
|
|
'chat:read',
|
|
'bits:read',
|
|
'channel:read:polls',
|
|
'channel:read:predictions',
|
|
'channel:read:subscriptions',
|
|
'channel:read:vips',
|
|
'moderator:read:blocked_terms',
|
|
'chat:read',
|
|
'channel:moderate',
|
|
'channel:read:redemptions',
|
|
'channel:manage:redemptions',
|
|
'channel:manage:predictions',
|
|
'user:read:chat',
|
|
'channel:bot',
|
|
'moderator:read:followers',
|
|
'channel:read:ads',
|
|
'moderator:read:chatters',
|
|
],
|
|
redirect: 'https://tomtospeech.com/connection/authorize'
|
|
},
|
|
// 'twitch tts bot': {
|
|
// type: 'twitch',
|
|
// endpoint: 'https://id.twitch.tv/oauth2/authorize',
|
|
// grantType: 'token',
|
|
// scopes: [
|
|
// 'chat:read',
|
|
// 'bits:read',
|
|
// 'channel:read:polls',
|
|
// 'channel:read:predictions',
|
|
// 'channel:read:subscriptions',
|
|
// 'channel:read:vips',
|
|
// 'moderator:read:blocked_terms',
|
|
// 'chat:read',
|
|
// 'channel:moderate',
|
|
// 'channel:read:redemptions',
|
|
// 'channel:manage:redemptions',
|
|
// 'channel:manage:predictions',
|
|
// 'user:read:chat',
|
|
// 'channel:bot',
|
|
// 'moderator:read:followers',
|
|
// 'channel:read:ads',
|
|
// 'moderator:read:chatters',
|
|
// ],
|
|
// redirect: 'https://tomtospeech.com/connection/authorize'
|
|
// }
|
|
}
|
|
|
|
function AddOrRenew(name: string, type: string | undefined, clientId: string, router: AppRouterInstance) {
|
|
if (type === undefined)
|
|
return
|
|
if (!(type in AUTHORIZATION_DATA))
|
|
return
|
|
|
|
console.log(type)
|
|
const data = AUTHORIZATION_DATA[type]
|
|
const state = v4()
|
|
const clientIdUpdated = type == 'twitch tts bot' ? process.env.NEXT_PUBLIC_TWITCH_TTS_CLIENT_ID : clientId
|
|
axios.post("/api/connection/prepare", {
|
|
name: name,
|
|
type: data.type,
|
|
clientId: clientIdUpdated,
|
|
grantType: data.grantType,
|
|
state: state
|
|
}).then(_ => {
|
|
const url = data.endpoint + '?client_id=' + clientIdUpdated + '&redirect_uri=' + data.redirect + '&response_type=' + data.grantType
|
|
+ '&scope=' + data.scopes.join('%20') + '&state=' + state + '&force_verify=true'
|
|
router.push(url)
|
|
})
|
|
}
|
|
|
|
export const ConnectionElement = ({
|
|
name,
|
|
type,
|
|
clientId,
|
|
expiresAt,
|
|
remover,
|
|
}: Connection) => {
|
|
const router = useRouter()
|
|
const expirationHours = (new Date(expiresAt).getTime() - new Date().getTime()) / 1000 / 60 / 60
|
|
const expirationDays = expirationHours / 24
|
|
|
|
function Delete() {
|
|
axios.delete("/api/connection?name=" + name)
|
|
.then(d => {
|
|
remover(d.data.data.name)
|
|
})
|
|
}
|
|
|
|
return (
|
|
<div
|
|
className="bg-green-300 p-3 border-2 border-green-400 rounded-lg flex text-black m-1">
|
|
<div
|
|
className="justify-between flex-1 font-bold text-xl">
|
|
{name}
|
|
<div className="text-base font-normal">
|
|
{expirationDays > 1 && Math.floor(expirationDays) + " days - " + type}
|
|
{expirationDays <= 1 && Math.floor(expirationHours) + " hours - " + type}
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
className="float-right align-middle flex flex-row items-center">
|
|
<Button
|
|
className="bg-blue-500 mr-3"
|
|
onClick={() => AddOrRenew(name, type, clientId, router)}>
|
|
Renew
|
|
</Button>
|
|
<Button
|
|
className="bg-red-500"
|
|
onClick={Delete}>
|
|
Delete
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export const ConnectionAdderElement = () => {
|
|
const router = useRouter()
|
|
const [name, setName] = useState<string>('')
|
|
const [type, setType] = useState<string | undefined>(undefined)
|
|
const [clientId, setClientId] = useState('')
|
|
const [open, setOpen] = useState(false)
|
|
|
|
return (
|
|
<div
|
|
className="bg-green-300 p-3 border-2 border-green-300 rounded-lg flex m-1">
|
|
<div
|
|
className="justify-between flex-1">
|
|
<Popover
|
|
open={open}
|
|
onOpenChange={setOpen}>
|
|
<PopoverTrigger asChild>
|
|
<Button
|
|
variant="outline"
|
|
role="combobox"
|
|
aria-expanded={open}
|
|
className="w-[120px] justify-between"
|
|
>{!type ? "Select service..." : type}</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent>
|
|
<Command>
|
|
<CommandInput
|
|
placeholder="Filter services..."
|
|
autoFocus={true} />
|
|
<CommandList>
|
|
<CommandEmpty>No action found.</CommandEmpty>
|
|
<CommandGroup>
|
|
{Object.keys(AUTHORIZATION_DATA).map((authType: string) => (
|
|
<CommandItem
|
|
value={authType}
|
|
key={authType}
|
|
onSelect={(value) => {
|
|
setType(authType)
|
|
setOpen(false)
|
|
}}>
|
|
{authType}
|
|
</CommandItem>
|
|
))}
|
|
</CommandGroup>
|
|
</CommandList>
|
|
</Command>
|
|
</PopoverContent>
|
|
</Popover>
|
|
<Input
|
|
className='w-[200px] inline m-1'
|
|
placeholder="Name"
|
|
value={name}
|
|
onChange={e => setName(e.target.value.toLowerCase())} />
|
|
{!!type && type != 'twitch tts bot' &&
|
|
<Input
|
|
className='w-[250px] m-1'
|
|
placeholder="Client Id"
|
|
value={clientId}
|
|
onChange={e => setClientId(e.target.value)} />
|
|
}
|
|
</div>
|
|
<div
|
|
className="float-right flex flex-row items-center">
|
|
<Button
|
|
className="bg-green-500"
|
|
onClick={() => AddOrRenew(name, type, clientId, router)}>
|
|
Add
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |