generated from nhcarrigan/template
6bf1ac5e7d
## Summary - Grants the Elysian Discord role to players on login/registration and persists an `inGuild` flag on the Player record - Connects to the Discord Gateway via WebSocket to keep `inGuild` in sync as players join or leave the server - Shows a dismissible "Join our community" modal to players who are not yet in the guild - Hardens `inGuild` exposure through the load endpoint and game context - Moves all non-secret Discord IDs (guild, role, client, redirect URI) out of env vars and into hardcoded constants; removes them from `prod.env` ## Test plan - [ ] Lint, build, and test pipeline passes (100% coverage maintained) - [ ] New player auth grants Elysian role and sets `inGuild: true` - [ ] Existing player auth re-attempts role grant and updates `inGuild` - [ ] Join community modal appears for players not in the guild - [ ] Modal does not reappear within the same browser session after dismissal - [ ] Gateway correctly sets `inGuild: true/false` on member add/remove events ✨ This issue was created with help from Hikari~ 🌸 Reviewed-on: #134 Co-authored-by: Hikari <hikari@nhcarrigan.com> Co-committed-by: Hikari <hikari@nhcarrigan.com>
71 lines
2.0 KiB
TypeScript
71 lines
2.0 KiB
TypeScript
/**
|
|
* @file Modal prompting players to join the NHCarrigan Discord community.
|
|
* @copyright nhcarrigan
|
|
* @license Naomi's Public License
|
|
* @author Naomi Carrigan
|
|
*/
|
|
import { useCallback, useState, type JSX } from "react";
|
|
import { useGame } from "../../context/gameContext.js";
|
|
|
|
const sessionKey = "elysium_join_community_dismissed";
|
|
|
|
/**
|
|
* Renders a modal prompting the player to join the NHCarrigan Discord server.
|
|
* Shown once per session when the player is not already in the guild.
|
|
* @returns The JSX element or null if the player is in the guild or dismissed.
|
|
*/
|
|
const JoinCommunityModal = (): JSX.Element | null => {
|
|
const { inGuild } = useGame();
|
|
const [ dismissed, setDismissed ] = useState(
|
|
() => {
|
|
return sessionStorage.getItem(sessionKey) === "true";
|
|
},
|
|
);
|
|
|
|
const handleDismiss = useCallback((): void => {
|
|
sessionStorage.setItem(sessionKey, "true");
|
|
setDismissed(true);
|
|
}, []);
|
|
|
|
if (inGuild || dismissed) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<div className="modal-overlay">
|
|
<div className="modal">
|
|
<h2>{"Join Our Community!"}</h2>
|
|
<p>
|
|
{"Did you know Elysium has an active Discord community? "}
|
|
{"Join to chat with other players, get updates, and earn "}
|
|
{"the exclusive Elysian role!"}
|
|
</p>
|
|
<p className="modal-note">
|
|
{"You already earn the Elysian role just by playing — "}
|
|
{"joining lets us show it off in the server!"}
|
|
</p>
|
|
<div className="modal-actions">
|
|
<a
|
|
className="modal-close-button"
|
|
href="https://discord.gg/KKe7BaEnQB"
|
|
onClick={handleDismiss}
|
|
rel="noreferrer"
|
|
target="_blank"
|
|
>
|
|
{"Join Discord"}
|
|
</a>
|
|
<button
|
|
className="modal-close-button"
|
|
onClick={handleDismiss}
|
|
type="button"
|
|
>
|
|
{"Maybe later"}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export { JoinCommunityModal };
|