Skip to content

Commit

Permalink
[+] PopupManager: Adding Provider and the PopupShell, that can be use…
Browse files Browse the repository at this point in the history
…d with Basic, Mulligan and Concede Variants
  • Loading branch information
HugoHMZ committed Dec 19, 2024
1 parent 2b07569 commit 7fb080e
Show file tree
Hide file tree
Showing 8 changed files with 306 additions and 9 deletions.
69 changes: 69 additions & 0 deletions src/app/_components/_sharedcomponents/Popup/Popup.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
export const buttonStyle = {
borderRadius: "15px",
backgroundColor: "#1E2D32",
padding: "1rem 1.5rem",

border: "2px solid transparent",
background:
"linear-gradient(#1E2D32, #1E2D32) padding-box, linear-gradient(to top, #038FC3, #595A5B) border-box",
"&:hover": {
background: "hsl(195, 25%, 16%)",
},
};

export const overlayStyle = {
position: "fixed" as const,
inset: "0",
backgroundColor: "rgba(0, 0, 0, 0.5)",
display: "flex",
justifyContent: "center",
alignItems: "center",
zIndex: 50,
};

export const concedeButtonStyle = {
padding: "1rem 1.5rem",
borderRadius: "15px",
backgroundImage: "linear-gradient(#1E2D32, #1E2D32)",
border: "2px solid transparent",
background:
"linear-gradient(#380707, #380707) padding-box, linear-gradient(to top, #C30101, #7D0807) border-box",
};

export const contentStyle = {
padding: "2rem",
borderRadius: "15px",
width: "90%",
maxWidth: "500px",
height: "260px",
position: "relative" as const,

border: "2px solid transparent",
background:
"linear-gradient(#0F1F27, #030C13) padding-box, linear-gradient(to top, #30434B, #50717D) border-box",
};

export const containerStyle = {
alignItems: "center",
justifyContent: "center",
display: "flex",
flexDirection: "column",
textAlign: "center",
};

export const minimalButtonStyle = {
position: "absolute",
top: "0.5rem",
right: "0.5rem",
color: "white",
};

export const titleStyle = {
color: "white",
fontSize: "1.25rem",
fontWeight: "bold",
};

export const textStyle = {
color: "#C7C7C7",
};
46 changes: 46 additions & 0 deletions src/app/_components/_sharedcomponents/Popup/Popup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"use client";
import { PopupData, PopupType, usePopup } from "@/app/_contexts/Popup.context";
import { Box, IconButton } from "@mui/material";
import React from "react";
import { BiMinus } from "react-icons/bi";
import { contentStyle, minimalButtonStyle, overlayStyle } from "./Popup.styles";
import { ConcedePopup, DefaultPopup, MulliganPopup } from "./Popup.types";
import { ConcededPopupModal } from "./PopupVariant/ConcedePopup";
import { DefaultPopupModal } from "./PopupVariant/DefaultPopup";
import { MulliganPopupModal } from "./PopupVariant/MulliganPopup";

const PopupShell: React.FC = () => {
const { type, data, closePopup } = usePopup();

if (!type || !data) return null; // No popup to display

const renderPopup = (type: PopupType, data: PopupData) => {
switch (type) {
case "default":
return <DefaultPopupModal data={data as DefaultPopup} />;
case "mulligan":
return <MulliganPopupModal data={data as MulliganPopup} />;
case "concede":
return <ConcededPopupModal data={data as ConcedePopup} />;
default:
return null;
}
};

return (
<Box sx={overlayStyle}>
<Box sx={contentStyle}>
<IconButton
sx={minimalButtonStyle}
aria-label="minimize"
onClick={closePopup}
>
<BiMinus />
</IconButton>
{renderPopup(type, data)}
</Box>
</Box>
);
};

export default PopupShell;
19 changes: 19 additions & 0 deletions src/app/_components/_sharedcomponents/Popup/Popup.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export type DefaultPopup = {
type: "default";
title: string;
description: string;
onConfirm: () => void;
onCancel: () => void;
};

export type MulliganPopup = {
type: "mulligan";
onDraw: () => void;
onKeep: () => void;
};

export type ConcedePopup = {
type: "concede";
onConcede: () => void;
onCancel: () => void;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Box, Button, Typography } from "@mui/material";
import {
buttonStyle,
concedeButtonStyle,
containerStyle,
textStyle,
titleStyle,
} from "../Popup.styles";
import { ConcedePopup } from "../Popup.types";

interface ButtonProps {
data: ConcedePopup;
}

export const ConcededPopupModal = ({ data }: ButtonProps) => {
return (
<Box sx={containerStyle}>
<Typography sx={titleStyle}>Would you like to concede?</Typography>
<Typography sx={textStyle}>
Concede will end the game and declare you as the loser.
</Typography>
<Box sx={{ display: "flex", gap: "1rem", marginTop: "2rem" }}>
<Button
onClick={data.onConcede}
sx={concedeButtonStyle}
variant="contained"
>
Concede
</Button>
<Button onClick={data.onCancel} sx={buttonStyle}>
Continue playing
</Button>
</Box>
</Box>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Box, Button, Typography } from "@mui/material";
import {
buttonStyle,
containerStyle,
textStyle,
titleStyle,
} from "../Popup.styles";
import { DefaultPopup } from "../Popup.types";

interface ButtonProps {
data: DefaultPopup;
}

export const DefaultPopupModal = ({ data }: ButtonProps) => {
return (
<Box sx={containerStyle}>
<Typography sx={titleStyle}>{data.title}</Typography>
<Typography sx={textStyle}>{data.description}</Typography>
<Box sx={{ display: "flex", gap: "1rem", marginTop: "2rem" }}>
<Button onClick={data.onConfirm} sx={buttonStyle} variant="contained">
Yes
</Button>
<Button onClick={data.onCancel} sx={buttonStyle}>
No
</Button>
</Box>
</Box>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Box, Button, Typography } from "@mui/material";
import {
buttonStyle,
containerStyle,
textStyle,
titleStyle,
} from "../Popup.styles";
import { MulliganPopup } from "../Popup.types";

interface ButtonProps {
data: MulliganPopup;
}

export const MulliganPopupModal = ({ data }: ButtonProps) => {
return (
<Box sx={containerStyle}>
<Typography sx={titleStyle}>Would you like to mulligan?</Typography>
<Typography sx={textStyle}>
Mulligan will replace your initial 6 cards with another 6 new\nones.
This action can only be done one time!
</Typography>
<Box sx={{ display: "flex", gap: "1rem", marginTop: "2rem" }}>
<Button onClick={data.onDraw} sx={buttonStyle} variant="contained">
Draw another six
</Button>
<Button onClick={data.onKeep} sx={buttonStyle}>
Keep this hand
</Button>
</Box>
</Box>
);
};
59 changes: 59 additions & 0 deletions src/app/_contexts/Popup.context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"use client";
import React, { createContext, useContext, useState } from "react";
import {
ConcedePopup,
DefaultPopup,
MulliganPopup,
} from "../_components/_sharedcomponents/Popup/Popup.types";

// TODO: SelectCardsPopup | LeaderAbilityPopup | DrawPopup | SelectCardsWithAspectPopup
export type PopupData = DefaultPopup | MulliganPopup | ConcedePopup;

export type PopupType = PopupData["type"];

export type PopupDataMap = {
default: Omit<DefaultPopup, "type">;
mulligan: Omit<MulliganPopup, "type">;
concede: Omit<ConcedePopup, "type">;
};

interface PopupContextProps {
type?: PopupType;
data?: PopupData;
openPopup: <T extends PopupType>(type: T, data: PopupDataMap[T]) => void;
closePopup: () => void;
}

const PopupContext = createContext<PopupContextProps | undefined>(undefined);

export const PopupProvider: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
const [type, setType] = useState<PopupType | undefined>(undefined);
const [data, setData] = useState<PopupData | undefined>(undefined);

const openPopup = <T extends PopupType>(type: T, data: PopupDataMap[T]) => {
setType(type);
setData({ type, ...data } as PopupData);
};

const closePopup = () => {
console.log("Closing popup");
setType(undefined);
setData(undefined);
};

return (
<PopupContext.Provider value={{ type, data, openPopup, closePopup }}>
{children}
</PopupContext.Provider>
);
};

export const usePopup = () => {
const context = useContext(PopupContext);
if (!context) {
throw new Error("usePopup must be used within a PopupProvider");
}
return context;
};
25 changes: 16 additions & 9 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@
// layout.tsx
import type { Metadata } from "next";
import React from 'react';
import ClientLayout from './ClientLayout';
import { Barlow } from "next/font/google";
import React from "react";
import { PopupProvider } from "./_contexts/Popup.context";
import "./_utils/s3Utils";
import ClientLayout from "./ClientLayout";

const barlow = Barlow({
subsets: ["latin"],
weight: ["400", "600", "800"],
variable: "--font-barlow",
subsets: ["latin"],
weight: ["400", "600", "800"],
variable: "--font-barlow",
});

export const metadata: Metadata = {
title: "Karabast",
title: "Karabast",
};

export default function RootLayout({ children }: { children: React.ReactNode }) {
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en" className={barlow.variable}>
<body>
<ClientLayout>{children}</ClientLayout>
<PopupProvider>
<ClientLayout>{children}</ClientLayout>
</PopupProvider>
</body>
</html>
);
}
}

0 comments on commit 7fb080e

Please sign in to comment.