Skip to content

Commit

Permalink
feat(share homebrew): Updated homebrew sharing functions
Browse files Browse the repository at this point in the history
  • Loading branch information
scottbenton committed Apr 26, 2024
1 parent 75d297d commit ef149a1
Show file tree
Hide file tree
Showing 36 changed files with 512 additions and 381 deletions.
4 changes: 2 additions & 2 deletions firestore.rules
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ service cloud.firestore {
match /collections/{homebrewId} {
allow read: if true;
allow create: if request.auth.uid != null;
allow write: if request.auth.uid in resource.data.editors && !request.resource.data.diff(resource.data).affectedKeys().hasAny(["creator", "editors"]);

allow update: if (request.auth.uid in resource.data.editors && !request.resource.data.diff(resource.data).affectedKeys().hasAny(["creator", "editors"])) || (request.auth.uid != null && request.resource.data.diff(resource.data).affectedKeys().hasOnly(["viewers"]));
allow delete: if (request.auth.uid == resource.data.creator);
}

match /stats/{statId} {
Expand Down
19 changes: 19 additions & 0 deletions functions/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,22 @@ export const addCurrentUserAsHomebrewCampaignEditor = onCall<

return true;
});

export const removeCurrentUserAsHomebrewCampaignEditor = onCall<
{ homebrewCollectionId: string },
Promise<boolean>
>(async (request) => {
const homebrewCollectionId = request.data.homebrewCollectionId;
const uid = request.auth?.uid;

if (!uid) {
logger.warn("User was not authenticated");
return false;
}

await getFirestore()
.doc(`/homebrew/homebrew/collections/${homebrewCollectionId}`)
.update({ editors: FieldValue.arrayRemove(uid) });

return true;
});
4 changes: 4 additions & 0 deletions src/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ const router = createBrowserRouter(
path={homebrewPaths[HOMEBREW_ROUTES.EDITOR]}
lazy={() => import("pages/Homebrew/HomebrewEditorPage")}
/>
<Route
path={homebrewPaths[HOMEBREW_ROUTES.EDITOR_JOIN]}
lazy={() => import("pages/Homebrew/HomebrewEditorInvitationPage")}
/>
</Route>
</Route>
{/* Unauthenticated Pages */}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import { functions } from "config/firebase.config";
import { httpsCallable } from "firebase/functions";

export function getHomebrewCollectionFromInviteUrl(): Promise<string | null> {
export function getHomebrewCollectionFromInviteUrl(
inviteKey: string
): Promise<string | null> {
return new Promise((resolve, reject) => {
const inviteKey = location.pathname.substring(
location.pathname.lastIndexOf("/") + 1
);

const getHomebrewId = httpsCallable(
functions,
"getHomebrewIdFromInviteKey"
);

getHomebrewId({ inviteKey })
.then((homebrewId) => {
return homebrewId.data;
resolve(homebrewId.data as string | null);
})
.catch((e) => {
console.error(e);
Expand Down
22 changes: 22 additions & 0 deletions src/api-calls/homebrew/editorFunction/removeSelfAsEditor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { functions } from "config/firebase.config";
import { httpsCallable } from "firebase/functions";

export function removeSelfAsEditor(
homebrewCollectionId: string
): Promise<boolean> {
return new Promise((resolve, reject) => {
const removeEditor = httpsCallable(
functions,
"removeCurrentUserAsHomebrewCampaignEditor"
);

removeEditor({ homebrewCollectionId })
.then((wasSuccessful) => {
resolve(wasSuccessful.data as boolean);
})
.catch((e) => {
console.error(e);
reject(e);
});
});
}
7 changes: 5 additions & 2 deletions src/api-calls/homebrew/listenToHomebrewCollections.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { onSnapshot, query, where } from "firebase/firestore";
import { onSnapshot, or, query, where } from "firebase/firestore";
import { HomebrewCollectionDocument } from "types/homebrew/HomebrewCollection.type";
import { getHomebrewCollection } from "./_getRef";

Expand All @@ -14,7 +14,10 @@ export function listenToHomebrewCollections(
) {
const homebrewQuery = query(
getHomebrewCollection(),
where("editors", "array-contains", uid)
or(
where("editors", "array-contains", uid),
where("viewers", "array-contains", uid)
)
);
return onSnapshot(
homebrewQuery,
Expand Down
4 changes: 2 additions & 2 deletions src/api-calls/homebrew/updateHomebrewExpansion.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { updateDoc } from "firebase/firestore";
import { PartialWithFieldValue, updateDoc } from "firebase/firestore";
import { getHomebrewCollectionDoc } from "./_getRef";
import { ExpansionDocument } from "types/homebrew/HomebrewCollection.type";
import { createApiFunction } from "api-calls/createApiFunction";

export const updateHomebrewExpansion = createApiFunction<
{ id: string; expansion: Partial<ExpansionDocument> },
{ id: string; expansion: PartialWithFieldValue<ExpansionDocument> },
void
>((params) => {
const { id, expansion } = params;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,18 @@ export function ExpansionSelector(props: ExpansionSelectorProps) {
const officialExpansions = useGameSystemValue(defaultExpansions);

const homebrewExpansionMap = useStore((store) => store.homebrew.collections);
const sortedExpansionIds = useStore(
(store) => store.homebrew.sortedHomebrewCollectionIds
);

const expansionIds = Object.keys(homebrewExpansionMap)
.filter(
(expansionId) =>
homebrewExpansionMap[expansionId]?.base?.rulesetId === baseRuleset
)
.sort((k1, k2) =>
homebrewExpansionMap[k1]?.base?.title?.localeCompare(
homebrewExpansionMap[k2]?.base?.title
)
);
const expansionIds = sortedExpansionIds.filter(
(expansionId) =>
homebrewExpansionMap[expansionId]?.base?.rulesetId === baseRuleset
);

const notFoundExpansionIds = Object.keys(enabledExpansionMap).filter(
(key) => !expansionIds.includes(key)
);

return (
<Box>
Expand Down Expand Up @@ -88,6 +89,23 @@ export function ExpansionSelector(props: ExpansionSelectorProps) {
}
/>
))}
{notFoundExpansionIds.map((expansionId) => (
<FormControlLabel
key={expansionId}
control={
<Switch
checked={enabledExpansionMap[expansionId] ?? false}
onChange={(evt, checked) =>
toggleEnableExpansion(expansionId, checked)
}
/>
}
label={
homebrewExpansionMap[expansionId].base?.title ??
"Deleted Homebrew Expansion"
}
/>
))}
</FormGroup>
) : (
<EmptyState leftAlign message={"No homebrew expansions found"} />
Expand Down
13 changes: 9 additions & 4 deletions src/components/shared/Layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import { BottomNav } from "./nav/BottomNav";
import { NavRail } from "./nav/NavRail";
import { TopNav } from "./nav/TopNav";
import { LayoutPathListener } from "./LayoutPathListener";
import { useNewCrewLinkTheme } from "hooks/featureFlags/useNewCrewLinkTheme";
import { StarforgedStarBackground } from "./StarforgedStarBackground";
import { useGameSystem } from "hooks/useGameSystem";
import { GAME_SYSTEMS } from "types/GameSystems.type";
import { useNewSunderedIslesTheme } from "hooks/featureFlags/useNewSunderedIslesTheme";

export function Layout() {
useSyncFeatureFlags();
Expand All @@ -25,7 +27,10 @@ export function Layout() {
(store) => store.auth.closeUserNameDialog
);

const showNewCrewLinkTheme = useNewCrewLinkTheme();
const { gameSystem } = useGameSystem();
const showNewSunderedIslesTheme = useNewSunderedIslesTheme();
const showStarforgedTheming =
gameSystem === GAME_SYSTEMS.STARFORGED && !showNewSunderedIslesTheme;

if (state === AUTH_STATE.LOADING) {
return <LinearProgress color={"primary"} />;
Expand All @@ -37,12 +42,12 @@ export function Layout() {
display={"flex"}
flexDirection={"column"}
sx={(theme) => ({
backgroundColor: showNewCrewLinkTheme
backgroundColor: showStarforgedTheming
? undefined
: theme.palette.background.default,
})}
>
{showNewCrewLinkTheme && <StarforgedStarBackground />}
{showStarforgedTheming && <StarforgedStarBackground />}
<Box
display={"flex"}
flexDirection={{ xs: "column", sm: "row" }}
Expand Down
13 changes: 6 additions & 7 deletions src/components/shared/Layout/PageHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Box, Container, Stack, Typography, useTheme } from "@mui/material";
import { getPublicAssetPath } from "functions/getPublicAssetPath";
import { useNewCrewLinkTheme } from "hooks/featureFlags/useNewCrewLinkTheme";
import { useNewSunderedIslesTheme } from "hooks/featureFlags/useNewSunderedIslesTheme";
import { useGameSystemValue } from "hooks/useGameSystemValue";
import React, { PropsWithChildren } from "react";
Expand All @@ -20,7 +19,6 @@ export function PageHeader(props: PageHeaderProps) {
const isEmpty = !label && !subLabel && !actions && !children;

const isLightTheme = useTheme().palette.mode === "light";
const showNewStarforgedTheme = useNewCrewLinkTheme();
const showNewSunderedIslesTheme = useNewSunderedIslesTheme();

const isIronsworn = useGameSystemValue({
Expand All @@ -43,7 +41,7 @@ export function PageHeader(props: PageHeaderProps) {
mb: isEmpty ? -8 : -4,
// width: "100vw",
backgroundColor:
isLightTheme && !showNewStarforgedTheme
isLightTheme && (isIronsworn || showNewSunderedIslesTheme)
? theme.palette.darkGrey.main
: undefined,
position: "relative",
Expand Down Expand Up @@ -109,12 +107,13 @@ export function PageHeader(props: PageHeaderProps) {
<Box
sx={(theme) => ({
backgroundImage:
isLightTheme && !showNewStarforgedTheme
isLightTheme && (isIronsworn || showNewSunderedIslesTheme)
? `url("${borderUrl}")`
: undefined,
backgroundColor: showNewSunderedIslesTheme
? "darkGrey.main"
: undefined,
backgroundColor:
showNewSunderedIslesTheme && theme.palette.mode === "light"
? "darkGrey.main"
: undefined,
height: theme.spacing(showNewSunderedIslesTheme ? 2 : 8),
backgroundRepeat: "repeat-x",
backgroundSize: "contain",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import { FlyoutMenuList } from "./FlyoutMenuList";

export function HomebrewMenu() {
const homebrewCollections = useStore((store) => store.homebrew.collections);
const sortedHomebrewCollections = useStore(
(store) => store.homebrew.sortedHomebrewCollectionIds
);
return (
<FlyoutMenuList
label={"Homebrew"}
itemIds={Object.keys(homebrewCollections)}
itemIds={sortedHomebrewCollections}
renderListItem={(collectionId) => (
<ListItem key={collectionId} disablePadding>
<ListItemButton
Expand Down
5 changes: 0 additions & 5 deletions src/hooks/featureFlags/activeFeatureFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ export const activeFeatureFlags: {
testId: "custom-content-page",
label: "Add new homebrew content management page",
},
{
testId: "new-crew-link-theme",
label: "Show potential new theme for Starforged Crew Link",
gameSystems: [GAME_SYSTEMS.STARFORGED],
},
{
testId: "new-sundered-isles-theme",
label: "Show potential theme for Sundered Isles Crew Link",
Expand Down
11 changes: 0 additions & 11 deletions src/hooks/featureFlags/useNewCrewLinkTheme.ts

This file was deleted.

35 changes: 20 additions & 15 deletions src/pages/Campaign/CampaignGMScreenPage/CampaignGMScreenPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,21 +65,26 @@ export function CampaignGMScreenPage() {

if (!campaign || !campaignId) {
return (
<EmptyState
title={"Campaign not Found"}
message={"Please try again from the campaign selection page"}
showImage
callToAction={
<Button
LinkComponent={LinkComponent}
href={constructCampaignPath(CAMPAIGN_ROUTES.SELECT)}
variant={"contained"}
size={"large"}
>
Select a Campaign
</Button>
}
/>
<>
<PageHeader />
<PageContent isPaper>
<EmptyState
title={"Campaign not Found"}
message={"Please try again from the campaign selection page"}
showImage
callToAction={
<Button
LinkComponent={LinkComponent}
href={constructCampaignPath(CAMPAIGN_ROUTES.SELECT)}
variant={"contained"}
size={"large"}
>
Select a Campaign
</Button>
}
/>
</PageContent>
</>
);
}
if (!uid || !campaign.gmIds?.includes(uid)) {
Expand Down
39 changes: 22 additions & 17 deletions src/pages/Campaign/CampaignSheetPage/CampaignSheetPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useSearchParams } from "react-router-dom";
import { CampaignSheetHeader } from "./components/CampaignSheetHeader";
import { CharacterSection } from "./components/CharacterSection";
import { WorldSection } from "./components/WorldSection";
import { PageContent } from "components/shared/Layout";
import { PageContent, PageHeader } from "components/shared/Layout";
import { BreakContainer } from "components/shared/BreakContainer";
import { TracksSection } from "./components/TracksSection";
import { StyledTabs, StyledTab } from "components/shared/StyledTabs";
Expand Down Expand Up @@ -68,21 +68,26 @@ export function CampaignSheetPage() {

if (!campaignId || !campaign) {
return (
<EmptyState
title={"Campaign not Found"}
message={"Please try again from the campaign selection page"}
showImage
callToAction={
<Button
LinkComponent={LinkComponent}
href={constructCampaignPath(CAMPAIGN_ROUTES.SELECT)}
variant={"contained"}
size={"large"}
>
Select a Campaign
</Button>
}
/>
<>
<PageHeader />
<PageContent isPaper>
<EmptyState
title={"Campaign not Found"}
message={"Please try again from the campaign selection page"}
showImage
callToAction={
<Button
LinkComponent={LinkComponent}
href={constructCampaignPath(CAMPAIGN_ROUTES.SELECT)}
variant={"contained"}
size={"large"}
>
Select a Campaign
</Button>
}
/>
</PageContent>
</>
);
}

Expand All @@ -98,7 +103,7 @@ export function CampaignSheetPage() {
<StyledTabs
value={selectedTab}
onChange={(evt, value) => handleTabChange(value)}
indicatorColor='primary'
indicatorColor="primary"
centered
variant={"standard"}
sx={(theme) => ({
Expand Down
Loading

0 comments on commit ef149a1

Please sign in to comment.