Skip to content

Commit

Permalink
Merge pull request #93 from powerstackdev/next-puck-drupal
Browse files Browse the repository at this point in the history
Cleaning up the create page logic, tweaking caching, and cleaning up …
  • Loading branch information
xaviemirmon committed Apr 24, 2024
2 parents 7c411a6 + 9f3f86d commit fd2da3c
Show file tree
Hide file tree
Showing 17 changed files with 435 additions and 189 deletions.
12 changes: 12 additions & 0 deletions frontend/packages/utils/src/Utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,15 @@ export const capitalize = (text) =>
text.charAt(0).toUpperCase() + text.slice(1).toLowerCase()

export const isBrowser = () => typeof window !== "undefined"

export const formatDate = (dateString) => {
const date = new Date(dateString)
return date.toLocaleString("en-US", {
year: "numeric", // 2021, 2022, ...
month: "long", // January, February, ...
day: "numeric", // 1, 2, 3, ...
hour: "numeric", // 12 AM, 1 PM, ...
minute: "numeric", // 00, 01, 02, ...
second: "numeric", // 00, 01, 02, ...
})
}
4 changes: 2 additions & 2 deletions frontend/starters/development/app/[...slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export default async function NodePage({
searchParams,
}: NodePageProps) {
const isDraftMode = draftMode().isEnabled

const path = `/${slug.join("/")}`
let node
try {
node = await getNode(slug)
Expand All @@ -126,7 +126,7 @@ export default async function NodePage({

return (
<>
{node.type === "node--page" && <BasicPage node={node} path={slug} />}
{node.type === "node--page" && <BasicPage node={node} path={path} />}
{node.type === "node--article" && <Article node={node} />}
</>
)
Expand Down
187 changes: 106 additions & 81 deletions frontend/starters/development/app/admin/content/page.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import Link from "next/link"

import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { MoreHorizontal } from "lucide-react"
import { Card, CardContent, CardFooter } from "@/components/ui/card"
import { MoreHorizontal, ArrowUpRight } from "lucide-react"

import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuDeleteItem,
DropdownMenuLabel,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
Expand All @@ -30,10 +24,17 @@ import {

import { drupal } from "@/lib/drupal"
import type { DrupalNode, JsonApiParams } from "next-drupal"
import { unstable_noStore as noStore } from "next/cache"
import { formatDate } from "@powerstack/utils"
import { toast } from "sonner"

async function getNodes(type: string) {
export const dynamic = "force-dynamic"

const params: JsonApiParams = {}
async function getNodes(type: string) {
noStore()
const params: JsonApiParams = {
sort: "-changed",
}
if (type === "node--article") {
params.include = "field_image,uid"
}
Expand All @@ -47,110 +48,134 @@ async function getNodes(type: string) {
})

if (!resource) {
throw new Error(
`Failed to fetch resource:`,
{
cause: "DrupalError",
}
)
throw new Error(`Failed to fetch resource:`, {
cause: "DrupalError",
})
}

return resource
}

type NodePageParams = {
slug: string[]
}
type NodePageProps = {
params: NodePageParams
searchParams: { [key: string]: string | string[] | undefined }
}

export async function generateMetadata() {

return {
title: `Admin: Content`,
}
}
slug: string[]
}
type NodePageProps = {
params: NodePageParams
searchParams: { [key: string]: string | string[] | undefined }
}

export async function ContentList() {
let nodes
async function fetchNodes() {
try {
nodes = await getNodes('node--page')
const fetchedNodes = await getNodes("node--page")
return fetchedNodes
} catch (e) {
// If we fail to fetch the node, don't return any metadata.
return {}
return e
}
const tableRows = nodes.map(node => (
<TableRow>
<TableCell className="font-medium">
{node.title}
</TableCell>
<TableCell>
{node.status ? <Badge variant="outline">Pubished</Badge> : <Badge variant="outline">Unpublished</Badge> }
</TableCell>
<TableCell className="hidden md:table-cell">{node.created}</TableCell>
<TableCell className="hidden md:table-cell">
{node.changed}
</TableCell>
<TableCell>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button aria-haspopup="true" size="icon" variant="ghost">
<MoreHorizontal className="h-4 w-4" />
<span className="sr-only">Toggle menu</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuItem><Link href={node?.path?.alias ? node?.path?.alias : `/node/${node.drupal_internal__nid}`}>View</Link></DropdownMenuItem>
<DropdownMenuItem><Link href={node?.path?.alias ? `${node?.path?.alias}/edit` : `/node/${node.drupal_internal__nid}/edit`}>Edit</Link></DropdownMenuItem>
<DropdownMenuItem>Delete</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</TableCell>
</TableRow>
))
}
const nodes = await fetchNodes()

const tableRows = nodes.map((node) => (
<TableRow>
<TableCell className="font-medium">
<Link
href={
node?.path?.alias
? `${node?.path?.alias}`
: `/node/${node.drupal_internal__nid}`
}
>
{node.title}
</Link>
</TableCell>
<TableCell>
{node.status ? (
<Badge variant="outline">Published</Badge>
) : (
<Badge variant="outline">Unpublished</Badge>
)}
</TableCell>
<TableCell>{formatDate(node.created)}</TableCell>
<TableCell>{formatDate(node.changed)}</TableCell>
<TableCell>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button aria-haspopup="true" size="icon" variant="ghost">
<MoreHorizontal className="h-4 w-4" />
<span className="sr-only">Toggle menu</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<Link
href={
node?.path?.alias
? node?.path?.alias
: `/node/${node.drupal_internal__nid}`
}
>
<DropdownMenuItem>View</DropdownMenuItem>
</Link>
<Link
href={
node?.path?.alias
? `${node?.path?.alias}/edit`
: `/node/${node.drupal_internal__nid}/edit`
}
>
<DropdownMenuItem>Edit</DropdownMenuItem>
</Link>
<DropdownMenuDeleteItem node={node}>Delete</DropdownMenuDeleteItem>
</DropdownMenuContent>
</DropdownMenu>
</TableCell>
</TableRow>
))
return (
<Card>
<CardContent>
<>
<CardContent className="min-h-36">
<Table>
<TableHeader>
<TableRow>
<TableHead>Title</TableHead>
<TableHead>Status</TableHead>
<TableHead className="hidden md:table-cell">Created</TableHead>
<TableHead className="hidden md:table-cell">
Updated
</TableHead>
<TableHead>
Actions
</TableHead>
<TableHead>Created</TableHead>
<TableHead>Updated</TableHead>
<TableHead>Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{tableRows}
</TableBody>
<TableBody>{tableRows}</TableBody>
</Table>
</CardContent>
<CardFooter>
<div className="text-xs text-muted-foreground">
Showing <strong>{nodes.length}</strong> pages
Showing <strong>{nodes.length}</strong> pages. If you need more robust
content filtering visit{" "}
<Link
href={`${process.env.NEXT_PUBLIC_DRUPAL_HOST}/admin/content`}
target="_blank"
className="text-muted-foreground transition-colors hover:text-foreground underline"
>
here
<ArrowUpRight className="w-3 h-3 inline" />
</Link>
.
</div>
</CardFooter>
</Card>
</>
)
}


export default function Dashboard() {
export default async function Dashboard() {
return (
<div className="flex min-h-screen w-full flex-col">
<main className="flex min-h-[calc(100vh_-_theme(spacing.16))] flex-1 flex-col gap-4 bg-muted/40 p-4 md:gap-8 md:p-10">
<div className="mx-auto grid w-full">
<h1 className="text-3xl font-semibold">Content</h1>
</div>
<ContentList />
<Card>
<ContentList />
</Card>
</main>
</div>
)
Expand Down
2 changes: 1 addition & 1 deletion frontend/starters/development/app/api/revalidate/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ async function handler(request: NextRequest) {
const secret = searchParams.get("secret")

// Validate secret.
if (secret !== process.env.DRUPAL_REVALIDATE_SECRET) {
if (secret !== process.env.NEXT_REVALIDATE_SECRET) {
return new Response("Invalid secret.", { status: 401 })
}

Expand Down

0 comments on commit fd2da3c

Please sign in to comment.