mirror of
https://gitea.tendokyu.moe/pinapelz/Mirage.git
synced 2026-09-22 22:38:04 +03:00
reduce amount of modal useStates + add Flower import modals (RB + nostop)
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
interface UserScript {
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
interface FlowerUserscriptModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
mainGameName: string;
|
||||
userPage: string;
|
||||
importPage: string;
|
||||
scripts: UserScript[];
|
||||
}
|
||||
|
||||
interface FlowerUserscriptCardProps {
|
||||
mainGameName: string;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
export const FlowerUserscriptCard = ({ mainGameName, onClick }: FlowerUserscriptCardProps) => {
|
||||
return (
|
||||
<div className="bg-slate-800 rounded-lg border border-slate-700 p-6 hover:border-violet-500 transition-colors">
|
||||
<div className="w-12 h-12 bg-blue-600/20 rounded-lg flex items-center justify-center mb-4">
|
||||
<svg
|
||||
className="w-6 h-6 text-blue-400"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<h4 className="text-white font-semibold mb-2">
|
||||
{mainGameName} Flower Play History (Userscript)
|
||||
</h4>
|
||||
<p className="text-slate-400 text-sm mb-4">
|
||||
Import playdata from cabinets on the Flower network
|
||||
</p>
|
||||
<button
|
||||
onClick={onClick}
|
||||
className="w-full bg-blue-600 hover:bg-blue-700 text-white py-2 px-3 sm:px-4 rounded-md text-sm sm:text-base font-medium transition-colors"
|
||||
>
|
||||
Export Flower Data
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const FlowerUserscriptModal = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
mainGameName,
|
||||
userPage,
|
||||
importPage,
|
||||
scripts,
|
||||
}: FlowerUserscriptModalProps) => {
|
||||
if (!isOpen) return null;
|
||||
|
||||
const handleClose = () => {
|
||||
onClose();
|
||||
};
|
||||
if(mainGameName === undefined){
|
||||
return "Sorry, due to some extreme error the game you're looking for doesn't seem to exist..."
|
||||
}
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 overflow-y-auto">
|
||||
{/* Backdrop */}
|
||||
<div
|
||||
className="fixed inset-0 bg-black/50 backdrop-blur-sm transition-opacity"
|
||||
onClick={handleClose}
|
||||
/>
|
||||
|
||||
{/* Modal */}
|
||||
<div className="flex min-h-full items-center justify-center p-4">
|
||||
<div className="relative bg-slate-900 rounded-lg border border-slate-700 w-full max-w-xl p-6 shadow-xl">
|
||||
{/* Header */}
|
||||
<div className="mb-6">
|
||||
<h3 className="text-xl font-bold text-white mb-2">
|
||||
Import {mainGameName} Flower Play Data
|
||||
</h3>
|
||||
<p className="text-slate-400 text-sm">
|
||||
Follow the instructions below to import your data
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Warning */}
|
||||
<div className="mb-6 rounded-md bg-blue-500/10 border border-blue-500/20 p-3">
|
||||
<p className="text-sm text-blue-400">
|
||||
You will need your ACCESS CODE to register on Flower for the first time! <br/><br/>
|
||||
Do this by tapping your Amusement IC card at any machine on the Flower network and copying
|
||||
down the code displayed on the screen.
|
||||
<br/><br/>
|
||||
This is likely not the same code as the one on the back of your card.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Instructions */}
|
||||
<div className="mb-4 rounded-md bg-slate-800 border border-slate-700 p-4">
|
||||
<h4 className="text-sm font-semibold text-slate-300 mb-2">
|
||||
Instructions:
|
||||
</h4>
|
||||
<ol className="text-sm text-slate-400 space-y-1 list-decimal list-inside">
|
||||
<li>
|
||||
Log into the{" "}
|
||||
<a
|
||||
className="font-bold hover:underline"
|
||||
href={userPage}>
|
||||
{mainGameName} Project Flower page
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
Navigate to the{" "}
|
||||
<a
|
||||
className="font-bold hover:underline"
|
||||
href={importPage}>
|
||||
{mainGameName} Play History Page
|
||||
</a>{" "}
|
||||
</li>
|
||||
<li>
|
||||
Install the relevant userscript (use a browser extension such as{" "}
|
||||
<a
|
||||
className="font-bold hover:underline"
|
||||
href="https://www.tampermonkey.net/">Tampermonkey</a>)
|
||||
</li>
|
||||
{/* Additional Info */}
|
||||
<div className="my-2 rounded-md bg-blue-500/10 border border-blue-500/20 p-3">
|
||||
<p className="text-sm text-blue-400">
|
||||
{scripts.map(userscript => (
|
||||
<a
|
||||
href={userscript.url}
|
||||
className="font-bold underline"
|
||||
>
|
||||
{userscript.name}
|
||||
</a>
|
||||
))}
|
||||
</p>
|
||||
</div>
|
||||
<li>
|
||||
A button will appear on the page that you can click to start the scraping process.
|
||||
</li>
|
||||
<li>
|
||||
Upload the resulting JSON file into Mirage using the
|
||||
Batch-Manual Upload functionality
|
||||
</li>
|
||||
<li>Verify that all data has been imported correctly</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
{/* Actions */}
|
||||
<div className="flex justify-center">
|
||||
<button
|
||||
onClick={handleClose}
|
||||
className="px-6 py-2 bg-violet-600 hover:bg-violet-700 text-white rounded-md font-medium transition-colors"
|
||||
>
|
||||
Got it
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FlowerUserscriptModal;
|
||||
@@ -6,21 +6,22 @@ import type { SupportedGame } from "../types/game";
|
||||
import { uploadScore } from "../utils/scoreUpload";
|
||||
import { NavBar } from "../components/NavBar";
|
||||
import { EamusementUserscriptCard } from "../components/modals/EamusementUserscriptModal";
|
||||
import { FlowerUserscriptCard } from "../components/modals/FlowerUserscriptModal";
|
||||
|
||||
const JsonUploadModal = lazy(() => import("../components/modals/JsonUploadModal"));
|
||||
const EamusementUserscriptModal = lazy(() => import("../components/modals/EamusementUserscriptModal"));
|
||||
const DivaNetModal = lazy(() => import("../components/modals/DivaNetModal"));
|
||||
const MusicDiverModal = lazy(() => import("../components/modals/MusicDiverModal"));
|
||||
const FlowerUserscriptModal = lazy(() => import("../components/modals/FlowerUserscriptModal"));
|
||||
|
||||
type ModalType = 'json' | 'dancerush' | 'dancearound' | 'divanet' | 'musicdiver' | 'nostalgia' | 'reflecbeat';
|
||||
|
||||
const Import = () => {
|
||||
const { user, isLoading, logout } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
const [selectedGame, setSelectedGame] = useState("");
|
||||
const [isJsonModalOpen, setIsJsonModalOpen] = useState(false);
|
||||
const [isDancerushModalOpen, setIsDancerushModalOpen] = useState(false);
|
||||
const [isDanceAroundModalOpen, setIsDanceAroundModalOpen] = useState(false);
|
||||
const [isDivaNetModalOpen, setIsDivaNetModalOpen] = useState(false);
|
||||
const [isMusicDiverModalOpen, setIsMusicDiverModalOpen] = useState(false);
|
||||
const [openModal, setOpenModal] = useState<ModalType | null>(null);
|
||||
|
||||
const [supportedGames, setSupportedGames] = useState<SupportedGame[]>([]);
|
||||
const [gamesLoading, setGamesLoading] = useState(true);
|
||||
const [uploadStatus, setUploadStatus] = useState<{
|
||||
@@ -120,7 +121,7 @@ const Import = () => {
|
||||
Upload your game data from a Mirage compatible JSON file
|
||||
</p>
|
||||
<button
|
||||
onClick={() => setIsJsonModalOpen(true)}
|
||||
onClick={() => setOpenModal('json')}
|
||||
className="w-full bg-violet-600 hover:bg-violet-700 text-white py-2 px-3 sm:px-4 rounded-md text-sm sm:text-base font-medium transition-colors"
|
||||
>
|
||||
Upload JSON
|
||||
@@ -136,7 +137,7 @@ const Import = () => {
|
||||
<JsonUploadCard />
|
||||
<EamusementUserscriptCard
|
||||
mainGameName="DANCERUSH"
|
||||
onClick={() => setIsDancerushModalOpen(true)}
|
||||
onClick={() => setOpenModal('dancerush')}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
@@ -145,8 +146,8 @@ const Import = () => {
|
||||
<>
|
||||
<JsonUploadCard />
|
||||
<EamusementUserscriptCard
|
||||
mainGameName="DANCE aROUND"
|
||||
onClick={() => setIsDanceAroundModalOpen(true)}
|
||||
mainGameName="DANCE aROUND"
|
||||
onClick={() => setOpenModal('dancearound')}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
@@ -158,7 +159,7 @@ const Import = () => {
|
||||
isOpen={false}
|
||||
onClose={() => {}}
|
||||
game={supportedGames.find((g) => g.internalName === selectedGame)}
|
||||
renderAsCard={() => setIsDivaNetModalOpen(true)}
|
||||
renderAsCard={() => setOpenModal('divanet')}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
@@ -170,7 +171,27 @@ const Import = () => {
|
||||
isOpen={false}
|
||||
onClose={() => {}}
|
||||
game={supportedGames.find((g) => g.internalName === selectedGame)}
|
||||
renderAsCard={() => setIsMusicDiverModalOpen(true)}
|
||||
renderAsCard={() => setOpenModal('musicdiver')}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
case "nostalgia":
|
||||
return (
|
||||
<>
|
||||
<JsonUploadCard />
|
||||
<FlowerUserscriptCard
|
||||
mainGameName="NOSTALGIA"
|
||||
onClick={() => setOpenModal('nostalgia')}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
case "reflecbeat":
|
||||
return (
|
||||
<>
|
||||
<JsonUploadCard />
|
||||
<FlowerUserscriptCard
|
||||
mainGameName="REFLEC BEAT"
|
||||
onClick={() => setOpenModal('reflecbeat')}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
@@ -282,10 +303,10 @@ const Import = () => {
|
||||
|
||||
{/* Modals wrapped in Suspense */}
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
{isJsonModalOpen && (
|
||||
{openModal === 'json' && (
|
||||
<JsonUploadModal
|
||||
isOpen={isJsonModalOpen}
|
||||
onClose={() => setIsJsonModalOpen(false)}
|
||||
isOpen={true}
|
||||
onClose={() => setOpenModal(null)}
|
||||
onUpload={handleJsonUpload}
|
||||
game={
|
||||
supportedGames.find((g) => g.internalName === selectedGame)
|
||||
@@ -293,23 +314,23 @@ const Import = () => {
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{isDancerushModalOpen && (
|
||||
{openModal === 'dancerush' && (
|
||||
<EamusementUserscriptModal
|
||||
isOpen={isDancerushModalOpen}
|
||||
onClose={() => setIsDancerushModalOpen(false)}
|
||||
isOpen={true}
|
||||
onClose={() => setOpenModal(null)}
|
||||
mainGameName="DANCERUSH"
|
||||
userPage="https://p.eagate.573.jp/game/dan/1st/top/entrance.html"
|
||||
importPage="https://p.eagate.573.jp/game/dan/1st/top/index.html#play_his"
|
||||
importPage="https://p.eagate.573.jp/payment/p/ex_select_course.html"
|
||||
scripts={[{
|
||||
name: "e-amusement Recently Played Score Export Userscript (Last 20 Played)",
|
||||
url: "https://github.com/pinapelz/Mirage/raw/refs/heads/main/scripts/dancerush/dancerush_play_history.user.js"
|
||||
}]}
|
||||
/>
|
||||
)}
|
||||
{isDanceAroundModalOpen && (
|
||||
{openModal === 'dancearound' && (
|
||||
<EamusementUserscriptModal
|
||||
isOpen={isDanceAroundModalOpen}
|
||||
onClose={() => setIsDanceAroundModalOpen(false)}
|
||||
isOpen={true}
|
||||
onClose={() => setOpenModal(null)}
|
||||
mainGameName="DANCE aROUND"
|
||||
userPage="https://p.eagate.573.jp/game/around/1st/top/index.html"
|
||||
importPage="https://p.eagate.573.jp/game/around/1st/top/index.html#play_hist"
|
||||
@@ -319,26 +340,52 @@ const Import = () => {
|
||||
}]}
|
||||
/>
|
||||
)}
|
||||
{isDivaNetModalOpen && (
|
||||
{openModal === 'divanet' && (
|
||||
<DivaNetModal
|
||||
isOpen={isDivaNetModalOpen}
|
||||
onClose={() => setIsDivaNetModalOpen(false)}
|
||||
isOpen={true}
|
||||
onClose={() => setOpenModal(null)}
|
||||
game={
|
||||
supportedGames.find((g) => g.internalName === selectedGame) ||
|
||||
undefined
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{isMusicDiverModalOpen && (
|
||||
{openModal === 'musicdiver' && (
|
||||
<MusicDiverModal
|
||||
isOpen={isMusicDiverModalOpen}
|
||||
onClose={() => setIsMusicDiverModalOpen(false)}
|
||||
isOpen={true}
|
||||
onClose={() => setOpenModal(null)}
|
||||
game={
|
||||
supportedGames.find((g) => g.internalName === selectedGame) ||
|
||||
undefined
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{openModal === 'nostalgia' && (
|
||||
<FlowerUserscriptModal
|
||||
isOpen={true}
|
||||
onClose={() => setOpenModal(null)}
|
||||
mainGameName="NOSTALGIA"
|
||||
userPage="https://projectflower.eu"
|
||||
importPage="https://projectflower.eu/game/nostalgia/54827307"
|
||||
scripts={[{
|
||||
name: "Flower Play History (Exports only the page you are on)",
|
||||
url: "https://github.com/pinapelz/Mirage/raw/refs/heads/main/scripts/nostalgia/nostalgia_flower_scraper.user.js"
|
||||
}]}
|
||||
/>
|
||||
)}
|
||||
{openModal === 'reflecbeat' && (
|
||||
<FlowerUserscriptModal
|
||||
isOpen={true}
|
||||
onClose={() => setOpenModal(null)}
|
||||
mainGameName="REFLEC BEAT"
|
||||
userPage="https://projectflower.eu"
|
||||
importPage="https://projectflower.eu/game/rb/profile/21363050"
|
||||
scripts={[{
|
||||
name: "Flower Play History (Exports only the page you are on)",
|
||||
url: "https://github.com/pinapelz/Mirage/raw/refs/heads/main/scripts/reflecbeat/reflecbeat_flower_scraper.user.js"
|
||||
}]}
|
||||
/>
|
||||
)}
|
||||
</Suspense>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user