feat: migrate accounts from development to production

This commit is contained in:
dvelo 2025-01-29 21:03:20 -06:00
parent e51a2ecd16
commit 532ead4bdf
7 changed files with 181 additions and 157 deletions

@ -47,6 +47,16 @@ export default function Settings() {
setLinked(user?.publicMetadata.player != undefined); setLinked(user?.publicMetadata.player != undefined);
}, [user, isSignedIn]); }, [user, isSignedIn]);
const forceUnlink = async () => {
if (!linked) await toast.promise(unlinkMCAccount(), {
success: "Unlinked account!",
loading: "Unlinking...",
error: "Error while unlinking account.",
});
else
await toast.warning("Please use the normal unlink option before using the force unlink one.")
};
return ( return (
<main className="p-4"> <main className="p-4">
<strong className="text-3xl">Linking</strong> <strong className="text-3xl">Linking</strong>
@ -112,7 +122,15 @@ export default function Settings() {
</div> </div>
<small className="mt-0"> <small className="mt-0">
All of your customizations stay the same, and can be changed if another All of your customizations stay the same, and can be changed if another
account links your Minecraft account. account links your Minecraft account.{" "}
<div
className="cursor-pointer text-blue-600"
onClick={forceUnlink}
onKeyDown={forceUnlink}
onKeyUp={forceUnlink}
>
Still linked in-game? Force unlink your account.
</div>
</small> </small>
</main> </main>
); );

@ -37,13 +37,13 @@ import { ThemeProvider } from "@/components/ThemeProvider";
import { ClerkThemeProvider } from "@/components/clerk/ClerkThemeProvider"; import { ClerkThemeProvider } from "@/components/clerk/ClerkThemeProvider";
import NewDomainDialog from "@/components/misc/NewDomainDialog"; import NewDomainDialog from "@/components/misc/NewDomainDialog";
import ThemedToaster from "@/components/misc/ThemedToaster"; import ThemedToaster from "@/components/misc/ThemedToaster";
import UnofficalDialog from "@/components/misc/UnofficalDialog";
import { TooltipProvider } from "@/components/ui/tooltip"; import { TooltipProvider } from "@/components/ui/tooltip";
import type { Metadata, Viewport } from "next"; import type { Metadata, Viewport } from "next";
import { Inter as interFont } from "next/font/google"; import { Inter as interFont } from "next/font/google";
import LayoutPart from "@/components/feat/LayoutPart"; import LayoutPart from "@/components/feat/LayoutPart";
import AllBanners from "@/components/feat/AllBanners"; import AllBanners from "@/components/feat/AllBanners";
import Footer from "@/components/misc/Footer"; import Footer from "@/components/misc/Footer";
import { SwitchEnvPopup } from "@/components/misc/SwitchEnvPopup";
export const extraMetadata = { export const extraMetadata = {
twitter: { twitter: {
@ -84,7 +84,7 @@ export default async function RootLayout({
<SpeedInsights /> <SpeedInsights />
<Analytics /> <Analytics />
<NewDomainDialog /> <NewDomainDialog />
<UnofficalDialog /> <SwitchEnvPopup />
<Footer /> <Footer />
</TooltipProvider> </TooltipProvider>
</ThemeProvider> </ThemeProvider>

@ -35,8 +35,9 @@ import {
PopoverTrigger, PopoverTrigger,
} from "@/components/ui/popover"; } from "@/components/ui/popover";
import { Button } from "../ui/button"; import { Button } from "../ui/button";
import { AtSign, LogIn } from "lucide-react"; import { AtSign, LogIn, Ship } from "lucide-react";
import { useClerk } from "@clerk/nextjs"; import { useClerk } from "@clerk/nextjs";
import { useRouter } from "@/lib/useRouter";
export default function SignInPopoverButton({ export default function SignInPopoverButton({
className, className,
@ -67,11 +68,14 @@ export default function SignInPopoverButton({
export function SignInPopover() { export function SignInPopover() {
const clerk = useClerk(); const clerk = useClerk();
const router = useRouter();
return ( return (
<div className=" grid w-[200px]"> <div className=" grid w-[200px]">
<strong className="text-center">Login</strong> <strong className="text-center">Login</strong>
<small className="text-center pb-6"> <small className="text-center pb-2">
Customize your own servers and favorite other servers. Secured by Clerk Customize your own servers and favorite other servers. Secured by Clerk
<br className="py-2"/>
If you created your account before Jan. 29, 2025, use the legacy migration button.
</small> </small>
<br /> <br />
<Button variant={"ghost"} onClick={() => clerk.openSignIn()}> <Button variant={"ghost"} onClick={() => clerk.openSignIn()}>
@ -82,6 +86,9 @@ export function SignInPopover() {
<AtSign size={18} className="mr-2" /> <AtSign size={18} className="mr-2" />
Sign-up Sign-up
</Button> </Button>
<Button variant="ghost" onClick={() => router.push(process.env.NEXT_PUBLIC_CLERK_SWITCH_DOMAIN as string)}>
<Ship size={18} className="mr-2"/>Legacy Migration
</Button>
</div> </div>
); );
} }

@ -41,8 +41,8 @@ export default function A({
}) { }) {
return ( return (
<NextLink <NextLink
href={pageFind(children || "")} href={pageFind(children || "") || "#"}
className="no-underline transition duration-300 hover:underline " className="transition duration-300 underline"
title={children} title={children}
> >
{(children || "").startsWith("Docs:") && ( {(children || "").startsWith("Docs:") && (
@ -68,7 +68,7 @@ export function ALegacy({
}) { }) {
return ( return (
<NextLink <NextLink
href={pageFind(href || "")} href={pageFind(href || "") || "#"}
className="no-underline transition duration-300 hover:underline " className="no-underline transition duration-300 hover:underline "
title={href} title={href}
> >
@ -95,6 +95,7 @@ export const pageFind = (text: string) => {
if (text === "Special:AccountOptions") return "/account/settings/options"; if (text === "Special:AccountOptions") return "/account/settings/options";
if (text.startsWith("Server:") && text.endsWith("/Customization")) if (text.startsWith("Server:") && text.endsWith("/Customization"))
return "/server/" + text.substring(7, text.length - 14) + "/customization"; return "/server/" + text.substring(7, text.length - 14) + "/customization";
if (text === "Special:ClerkConvertionPage") return process.env.NEXT_PUBLIC_CLERK_SWITCH_DOMAIN;
if (text.startsWith("Server:")) return "/server/" + text.substring(7); if (text.startsWith("Server:")) return "/server/" + text.substring(7);
if (text.startsWith("Wiki:")) if (text.startsWith("Wiki:"))
return "https://minehut.wiki.gg/wiki/" + text.substring(5); return "https://minehut.wiki.gg/wiki/" + text.substring(5);

@ -0,0 +1,58 @@
"use client";
import { useEffect, useState } from "react";
import {
Dialog,
DialogContent,
DialogTitle,
DialogTrigger,
} from "../ui/dialog";
import { OctagonAlert } from "lucide-react";
import A from "./Link";
import { Button } from "../ui/button";
import { useRouter } from "@/lib/useRouter";
export function SwitchEnvPopup() {
const [open, setOpen] = useState(false);
const router = useRouter();
useEffect(() => {
if (localStorage.getItem("mhsf--switch-env-alert") !== "true") {
setOpen(true);
}
}, [])
const setDialogTrigger = (v: boolean) => {
setOpen(v)
if (!v) {
localStorage.setItem("mhsf--switch-env-alert", "true")
}
}
return (
<Dialog open={open} onOpenChange={setDialogTrigger}>
<DialogContent>
<OctagonAlert className="text-orange-300" />
<DialogTitle className="text-3xl">
Wait! Did you have an old account?
</DialogTitle>
<p className="inline">
<strong>If you had an account before Jan. 28th, 2025</strong>, you
have a legacy account that <i>needs to be converted.</i>
</p>
<p className="inline">
Legacy accounts can be converted by going to{" "}
<A alt="this page">Special:ClerkConvertionPage</A> and logging in with
your old account & creating a new account. Your old account settings &
content will automatically be transferred to your new account.{" "}
</p>
<div className="flex items-center">
<Button onClick={() => { router.push(process.env.NEXT_PUBLIC_CLERK_SWITCH_DOMAIN || "#") }}>Convert account</Button>{" "}
<DialogTrigger>
<Button className="ml-2" variant="outline">Close</Button>
</DialogTrigger>
</div>
</DialogContent>
</Dialog>
);
}

@ -1,77 +0,0 @@
/*
* MHSF, Minehut Server List
* All external content is rather licensed under the ECA Agreement
* located here: https://list.mlnehut.com/docs/legal/external-content-agreement
*
* All code under MHSF is licensed under the MIT License
* by open source contributors
*
* Copyright (c) 2024 dvelo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
"use client";
import { useEffect, useState } from "react";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "../ui/dialog";
export default function UnofficalDialog() {
const [isOpen, setOpen] = useState(false);
useEffect(() => {
const dialog = localStorage.getItem("unoffical-dialog-open");
if (dialog == null) {
setOpen(true);
}
}, []);
const onChangeVal = (state: boolean) => {
if (state == false) {
setOpen(false);
localStorage.setItem("unoffical-dialog-open", "true");
} else setOpen(state);
};
return (
<Dialog open={isOpen} onOpenChange={onChangeVal}>
<DialogContent>
<DialogHeader>
<DialogTitle>Welcome to the Minehut Server List (MHSF)</DialogTitle>
</DialogHeader>
<DialogDescription>
MHSF is a Minehut server-list using the Minehut API to serve you
servers with filters, sorts and other helpful information when picking
a server to play.{" "}
<span className="font-bold">
Keep in mind that MHSF is not endorsed by Minehut or GamerSafer in
any way, as MHSF is a open-source unofficial project.
</span>
</DialogDescription>
</DialogContent>
</Dialog>
);
}

@ -67,8 +67,25 @@ const FeatureList = ({
); );
}; };
export const version = "1.7.0"; export const version = "1.7.5";
export const changelog: { name: string; id: string; changelog: ReactNode }[] = [ export const changelog: { name: string; id: string; changelog: ReactNode }[] = [
{
id: "tj4ijg09aern9eargjjuauerr",
name: "v1.7.5",
changelog: (
<FeatureList
github="https://github.com/DeveloLongScript/MHSF/releases/tag/1.7.5"
features={[
"Migrated accounts from development to production"
]}
title={
<strong className="flex items-center">
Version 1.7.5 (January 29th 2025)
</strong>
}
/>
),
},
{ {
id: "38ufajf8efajwj3njdaisef", id: "38ufajf8efajwj3njdaisef",
name: "v1.7", name: "v1.7",