Skip to content
This repository has been archived by the owner on Nov 20, 2024. It is now read-only.

Commit

Permalink
feat: maintenance messages
Browse files Browse the repository at this point in the history
  • Loading branch information
Firgrep committed Jul 21, 2024
1 parent 9dc6a3b commit e190253
Show file tree
Hide file tree
Showing 9 changed files with 1,030 additions and 10 deletions.
857 changes: 848 additions & 9 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@
"db:push": "npx prisma db push"
},
"dependencies": {
"@emotion/react": "^11.13.0",
"@emotion/styled": "^11.13.0",
"@google-cloud/storage": "^7.11.0",
"@mdx-js/mdx": "^2.3.0",
"@mdxeditor/editor": "^2.19.0",
"@mui/icons-material": "^5.16.4",
"@mui/material": "^5.16.4",
"@next-auth/prisma-adapter": "^1.0.7",
"@prisma/client": "^5.11.0",
"@react-email/components": "0.0.17",
Expand Down
27 changes: 27 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,30 @@ model StripeEvent {
livemode Boolean
pending_webhooks Int
}

// === SECTION 4 ==============================================
// * Miscellaneous internal data
// ============================================================

enum MaintenanceArea {
global
user
}

enum MaintenanceSeverity {
success
info
warning
critical
beta
}

model MaintenanceMessage {
id String @id @default(cuid())
area MaintenanceArea @unique
severity MaintenanceSeverity
published Boolean @default(false)
message String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
2 changes: 2 additions & 0 deletions src/app/(user)/billing/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { CardShell } from "@/components/CardShell";
import { Maintenance } from "@/components/Maintenance";
import { PageWrapper } from "@/components/PageWrapper";
import { getServerAuthSession } from "@/server/auth";
import { dbGetUserPurchasedCourses } from "@/server/controllers/dbController";
Expand All @@ -19,6 +20,7 @@ export default async function Billing() {

return (
<PageWrapper>
<Maintenance area="user" />
<div className="py-10">
<h1 className="text-xl font-bold py-6 text-center">Billing</h1>
{purchasedCourses && purchasedCourses.length > 0 ? (
Expand Down
2 changes: 2 additions & 0 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import FadeIn from "@/components/animations/FadeIn";
import InfoCard from "@/components/InfoCard";
import { PolyRhythmicSpiral } from "@/components/animations/PolyRhythmicSpiral";
import Link from "next/link";
import { Maintenance } from "@/components/Maintenance";

export default async function Home() {
return (
<>
<Hero />
<PageWrapper>
<OpeningDescription />
<Maintenance area="global" />
<MainInfoCard />
<InfoCards />
<Community />
Expand Down
125 changes: 125 additions & 0 deletions src/components/Maintenance.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { CACHE_REVALIDATION_INTERVAL_MAINTENANCE } from "@/config/cacheRevalidationInterval";
import { cache } from "@/server/cache";
import {
dbGetMaintenanceMessageGlobal,
dbGetMaintenanceMessageUser,
} from "@/server/controllers/dbController";
import Heading from "./Heading";
import { $Enums } from "@prisma/client";
import {
AutoFixHighOutlined,
ConstructionOutlined,
EngineeringOutlined,
InfoOutlined,
WarningAmberOutlined,
} from "@mui/icons-material";
import FadeIn from "./animations/FadeIn";

export async function Maintenance({ area }: { area: "global" | "user" }) {
const getMaintenanceMsgGlobal = cache(
async () => {
return await dbGetMaintenanceMessageGlobal();
},
["/maintenance_global"],
{ revalidate: CACHE_REVALIDATION_INTERVAL_MAINTENANCE }
);
const getMaintenanceMsgUser = cache(
async () => {
return await dbGetMaintenanceMessageUser();
},
["/maintenance_user"],
{ revalidate: CACHE_REVALIDATION_INTERVAL_MAINTENANCE }
);

const maintenance =
area === "global"
? await getMaintenanceMsgGlobal()
: await getMaintenanceMsgUser();

if (maintenance) {
function getMaintenanceTitle(severity: $Enums.MaintenanceSeverity) {
switch (severity) {
case "info":
return "News";
case "warning":
return "Maintenance";
case "critical":
return "Important Maintenance";
case "success":
return "New Features";
case "beta":
return "Active Development";
}
}
function getMaintenanceClasses(severity: $Enums.MaintenanceSeverity) {
switch (severity) {
case "info":
return "from-purple-300/90 to-purple-400/90 dark:from-purple-950/90 dark:to-purple-800/90";
case "warning":
return "from-orange-400/90 to-orange-500/90 dark:from-orange-950/90 dark:to-orange-800/90";
case "critical":
return "from-red-400/90 to-red-500/90 dark:from-red-950/90 dark:to-red-800/90";
case "success":
return "from-emerald-300/90 to-emerald-400/90 dark:from-emerald-950/90 dark:to-emerald-800/90";
case "beta":
return "from-rose-300/90 to-rose-400/90 dark:from-rose-950/90 dark:to-rose-800/90";
}
}
function getMaintenanceIcon(severity: $Enums.MaintenanceSeverity) {
switch (severity) {
case "info":
return <InfoOutlined fontSize="large" />;
case "warning":
return <WarningAmberOutlined fontSize="large" />;
case "critical":
return <EngineeringOutlined fontSize="large" />;
case "success":
return <AutoFixHighOutlined fontSize="large" />;
case "beta":
return <ConstructionOutlined fontSize="large" />;
}
}
const title = getMaintenanceTitle(maintenance.severity);
const classes = getMaintenanceClasses(maintenance.severity);

if (area === "user")
return (
<div className="md:px-10 max-w-[900px] mt-10 md:mt-32">
<div
className={`card rounded shadow-xl bg-gradient-to-b ${classes} transition duration-300 md:bg-gradient-to-bl`}
>
<div className="card-body">
<div className="card-title justify-center">
{getMaintenanceIcon(maintenance.severity)}
<Heading as="h3">{title}</Heading>
</div>
<p className="text-slate-900 dark:text-slate-400 pt-4 text-justify">
{maintenance.message}
</p>
</div>
</div>
</div>
);
return (
<FadeIn>
<div className="md:px-10 max-w-[900px] mt-10 md:mt-32">
<div
className={`card rounded shadow-xl bg-gradient-to-b ${classes} transition duration-300 md:bg-gradient-to-bl`}
>
<div className="card-body">
<div className="card-title justify-center">
{getMaintenanceIcon(maintenance.severity)}
<Heading as="h3">{title}</Heading>
</div>
<p className="text-slate-900 dark:text-slate-400 pt-4 text-justify">
{maintenance.message}
</p>
</div>
</div>
</div>
</FadeIn>
);
}

return null;
}
2 changes: 1 addition & 1 deletion src/components/RootNavbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ const UserMenu = ({ sessionData }: { sessionData: Session }) => {
)}
<li className="border-t my-1" />
<li>
<Link href="/billing">Billing</Link>
<Link href="/billing">Account & Billing</Link>
</li>
<li className="border-t my-1" />
<li>
Expand Down
3 changes: 3 additions & 0 deletions src/config/cacheRevalidationInterval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
* Set in seconds
*/
export const CACHE_REVALIDATION_INTERVAL = 60; // 60 * 60 * 24 * 1; // 1 day

export const CACHE_REVALIDATION_INTERVAL_MAINTENANCE =
process.env.NODE_ENV === "development" ? 10 : 60 * 60; // 1 hour
18 changes: 18 additions & 0 deletions src/server/controllers/dbController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1090,3 +1090,21 @@ export async function dbVerifyUserPurchase(userId: string, priceId: string) {
const hasUserPurchased = user.productsPurchased.includes(completePriceId);
return hasUserPurchased;
}

export async function dbGetMaintenanceMessageGlobal() {
return await prisma.maintenanceMessage.findFirst({
where: {
area: "global",
published: true,
},
});
}

export async function dbGetMaintenanceMessageUser() {
return await prisma.maintenanceMessage.findFirst({
where: {
area: "user",
published: true,
},
});
}

0 comments on commit e190253

Please sign in to comment.