The weeb for the next gen discord boat - Wamellow wamellow.com
bot discord
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor login header

Luna 67ab83d8 45893a8b

+115 -81
+79 -63
components/header.tsx
··· 16 16 17 17 import ImageReduceMotion from "./image-reduce-motion"; 18 18 19 + enum State { 20 + Idle = 0, 21 + Loading = 1, 22 + Failure = 2 23 + } 24 + 19 25 export default function Header(props: React.ComponentProps<"div">) { 20 26 const cookies = useCookies(); 21 27 const devTools = cookies.get("devTools") === "true"; 22 28 const reduceMotions = cookies.get("reduceMotions") === "true"; 23 29 24 30 const [menu, setMenu] = useState(false); 25 - const [loginstate, setLoginstate] = useState<"LOADING" | "ERRORED" | undefined>("LOADING"); 31 + const [state, setState] = useState<State>(State.Loading); 26 32 27 33 const user = userStore((s) => s); 28 34 const router = useRouter(); 29 35 30 36 useEffect(() => { 31 37 32 - authorize({ stateHook: setLoginstate }) 38 + authorize({ setState }) 33 39 .then((_user) => { 34 40 userStore.setState({ 35 41 ...(_user || {}), ··· 44 50 45 51 46 52 const UserButton = ( 47 - <button className={cn("ml-auto flex dark:hover:bg-wamellow hover:bg-wamellow-100 py-2 px-4 rounded-md duration-200 items-center", menu && "dark:bg-wamellow bg-wamellow-100")} onClick={() => setMenu(!menu)}> 53 + <button 54 + className={cn( 55 + "ml-auto flex dark:hover:bg-wamellow hover:bg-wamellow-100 py-2 px-4 rounded-md duration-200 items-center", 56 + menu && "dark:bg-wamellow bg-wamellow-100" 57 + )} 58 + onClick={() => setMenu(!menu)} 59 + > 48 60 49 61 <Skeleton isLoaded={!!user?.id} className="rounded-full mr-2 h-[30px] w-[30px]"> 50 62 <ImageReduceMotion url={`https://cdn.discordapp.com/avatars/${user?.id}/${user?.avatar}`} size={96} alt="your avatar" /> ··· 145 157 </Skeleton> 146 158 <div className="w-full"> 147 159 <div className="dark:text-neutral-200 text-neutral-800 truncate max-w-44 flex items-center gap-2"> 148 - <span className="font-medium text-xl sm:text-base">{user?.globalName || `@${user?.username}`}</span> 160 + <span className="font-medium text-xl sm:text-base"> 161 + {user?.globalName || `@${user?.username}`} 162 + </span> 149 163 {user?.id === "821472922140803112" && 150 164 <Chip color="secondary" size="sm" variant="flat" startContent={<HiBadgeCheck className="h-3.5 w-3.5 mr-1" />}> 151 165 <span className="font-bold">Developer</span> ··· 153 167 } 154 168 </div> 155 169 <div className="text-neutral-500 dark:text-neutral-400 max-w-40 truncate"> 156 - <span className="text-medium sm:text-sm">@{user?.username}</span> 170 + <span className="text-medium sm:text-sm"> 171 + @{user?.username} 172 + </span> 157 173 </div> 158 174 </div> 159 - <Tooltip content="Logout" closeDelay={0} showArrow> 175 + <Tooltip 176 + content="Logout" 177 + closeDelay={0} 178 + showArrow 179 + > 160 180 <button 161 181 className="ml-auto text-red-500 m-4" 162 182 onClick={() => { ··· 171 191 </div> 172 192 173 193 {buttons.map((button, i) => { 174 - if ("type" in button && button.type === "split") { 175 - return <hr key={"headerButton-" + button.type + i} className="my-1 mx-2 dark:border-wamellow border-wamellow-100" />; 176 - } 194 + if ("type" in button && button.type === "split") return ( 195 + <hr key={"headerButton-" + button.type + i} className="my-1 mx-2 dark:border-wamellow border-wamellow-100" /> 196 + ); 177 197 178 - if ("url" in button) { 179 - return ( 180 - <Button 181 - key={"headerButton-" + button.name + button.url} 182 - as={Link} 183 - href={button.url} 184 - className="w-full font-medium !justify-start !text-xl !my-1 sm:!text-medium sm:!my-0 bg-transparent" 185 - onClick={() => setMenu(false)} 186 - startContent={button.icon} 187 - > 188 - {button.name} 189 - </Button> 190 - ); 191 - } 198 + if ("url" in button) return ( 199 + <Button 200 + key={"headerButton-" + button.name + button.url} 201 + as={Link} 202 + href={button.url} 203 + className="w-full font-medium !justify-start !text-xl !my-1 sm:!text-medium sm:!my-0 bg-transparent" 204 + onClick={() => setMenu(false)} 205 + startContent={button.icon} 206 + > 207 + {button.name} 208 + </Button> 209 + ); 192 210 193 - if ("onChange" in button) { 194 - return ( 195 - <div 211 + if ("onChange" in button) return ( 212 + <div 213 + key={"headerButton-" + button.name} 214 + className="flex items-center px-4 pt-2 pb-3" 215 + > 216 + {button.icon} 217 + <span className="ml-[9px] text-xl my-1 sm:text-medium sm:my-0">{button.name}</span> 218 + <Switch 196 219 key={"headerButton-" + button.name} 197 - className="flex items-center px-4 pt-2 pb-3" 198 - > 199 - {button.icon} 200 - <span className="ml-[9px] text-xl my-1 sm:text-medium sm:my-0">{button.name}</span> 201 - <Switch 202 - key={"headerButton-" + button.name} 203 - className="ml-auto" 204 - isSelected={button.value} 205 - onValueChange={button.onChange} 206 - aria-label={button.name} 207 - color="secondary" 208 - size="sm" 209 - /> 210 - </div> 220 + className="ml-auto" 221 + isSelected={button.value} 222 + onValueChange={button.onChange} 223 + aria-label={button.name} 224 + color="secondary" 225 + size="sm" 226 + /> 227 + </div> 211 228 212 - ); 213 - } 229 + ); 214 230 215 231 })} 216 232 </motion.div> 217 233 ); 218 234 219 - return ( 220 - <div {...props}> 235 + return (<div {...props}> 236 + 237 + {state === State.Failure 238 + ? <LoginButton state={state} /> 239 + : UserButton 240 + } 221 241 222 - {loginstate === "ERRORED" 223 - ? <LoginButton loginstate={loginstate} /> 224 - : UserButton 242 + <MotionConfig 243 + transition={reduceMotions ? 244 + { duration: 0 } 245 + : 246 + { type: "spring", bounce: 0.4, duration: menu ? 0.7 : 0.4 } 225 247 } 226 - 227 - <MotionConfig 228 - transition={reduceMotions ? 229 - { duration: 0 } 230 - : 231 - { type: "spring", bounce: 0.4, duration: menu ? 0.7 : 0.4 } 232 - } 233 - > 234 - <AnimatePresence initial={false}> 235 - {user?.id && menu && 248 + > 249 + <AnimatePresence initial={false}> 250 + {user?.id && menu && 236 251 <div className="pr-4 flex text-base font-medium dark:text-neutral-300 text-neutral-700 overflow-x-hidden"> 237 252 <div className="ml-auto"> 238 - <div className="absolute left-0 sm:left-auto px-4 sm:px-0 z-40 w-full">{UserDropdown}</div> 253 + <div className="absolute left-0 sm:left-auto px-4 sm:px-0 z-40 w-full"> 254 + {UserDropdown} 255 + </div> 239 256 </div> 240 257 </div> 241 - } 242 - </AnimatePresence> 243 - </MotionConfig> 258 + } 259 + </AnimatePresence> 260 + </MotionConfig> 244 261 245 - </div> 246 - ); 262 + </div>); 247 263 }
+25 -13
components/login-button.tsx
··· 3 3 import { Button } from "@nextui-org/react"; 4 4 import { Montserrat } from "next/font/google"; 5 5 import Link from "next/link"; 6 - import { FunctionComponent } from "react"; 7 6 import { BsDiscord } from "react-icons/bs"; 8 7 import { HiExclamation } from "react-icons/hi"; 9 8 ··· 11 10 12 11 const montserrat = Montserrat({ subsets: ["latin"] }); 13 12 13 + enum State { 14 + Idle = 0, 15 + Loading = 1, 16 + Failure = 2 17 + } 18 + 14 19 interface Props { 15 - loginstate?: "LOADING" | "ERRORED" | undefined; 20 + state?: State; 16 21 message?: string 17 22 className?: string; 18 - addClassName?: string; 23 + addClassName?: string; // idk why that name 19 24 } 20 25 21 - const LoginButton: FunctionComponent<Props> = ({ loginstate, message, className, addClassName }) => { 22 - if (loginstate === "LOADING") return <></>; 26 + export default function LoginButton({ 27 + state, 28 + message, 29 + className, 30 + addClassName 31 + }: Props) { 32 + if (state === State.Loading) return <></>; 23 33 24 34 function Icon() { 25 - if (!loginstate) return <BsDiscord />; 26 - if (loginstate === "ERRORED") return <HiExclamation className="h-5 w-5" />; 35 + if (!state) return <BsDiscord />; 36 + if (state === State.Failure) return <HiExclamation className="h-5 w-5" />; 27 37 } 28 38 29 39 return ( 30 40 <div className={className || "ml-auto"}> 31 41 <Button 32 42 as={Link} 33 - className={cn("hover:bg-blurple hover:text-white dark:bg-wamellow bg-wamellow-100", loginstate === "ERRORED" && "dark:bg-danger/80 bg-danger/80 text-white", addClassName)} 43 + className={cn( 44 + "hover:bg-blurple hover:text-white dark:bg-wamellow bg-wamellow-100", 45 + state === State.Failure && "dark:bg-danger/80 bg-danger/80 text-white", 46 + addClassName 47 + )} 34 48 href="/login" 35 49 prefetch={false} 36 50 startContent={<Icon />} 37 51 > 38 - {!loginstate ? 39 - <span className={`${montserrat.className} font-semibold`}> 52 + {!state ? 53 + <span className={cn(montserrat.className,"font-semibold")}> 40 54 {message || 41 55 <> 42 56 <span className="hidden md:block">Login with Discord</span> ··· 50 64 </Button> 51 65 </div> 52 66 ); 53 - }; 54 - 55 - export default LoginButton; 67 + }
+11 -5
utils/authorize-user.ts
··· 3 3 import { User } from "@/common/user"; 4 4 import { RouteErrorResponse } from "@/typings"; 5 5 6 + enum State { 7 + Idle = 0, 8 + Loading = 1, 9 + Failure = 2 10 + } 11 + 6 12 export async function authorize({ 7 - stateHook 13 + setState 8 14 }: { 9 - stateHook: React.Dispatch<React.SetStateAction<"LOADING" | "ERRORED" | undefined>>; 15 + setState: React.Dispatch<React.SetStateAction<State>>; 10 16 }) { 11 - stateHook(undefined); 17 + setState(State.Idle); 12 18 13 19 const res = await fetch(`${process.env.NEXT_PUBLIC_API}/sessions`, { 14 20 credentials: "include", ··· 25 31 } 26 32 27 33 if (!res) { 28 - stateHook("ERRORED"); 34 + setState(State.Failure); 29 35 return null; 30 36 } 31 37 32 - stateHook(undefined); 38 + setState(State.Idle); 33 39 return res; 34 40 }