-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding tailwind, next-auth and basic admin pages.
- Loading branch information
1 parent
2f392ea
commit ef83b07
Showing
28 changed files
with
3,799 additions
and
345 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import Link from "next/link" | ||
|
||
import { Button } from "@/components/ui/button" | ||
import { | ||
Card, | ||
CardContent, | ||
CardDescription, | ||
CardFooter, | ||
CardHeader, | ||
CardTitle, | ||
} from "@/components/ui/card" | ||
import { Checkbox } from "@/components/ui/checkbox" | ||
import { Input } from "@/components/ui/input" | ||
|
||
export default 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 max-w-6xl gap-2"> | ||
<h1 className="text-3xl font-semibold">Settings</h1> | ||
</div> | ||
<div className="mx-auto grid w-full max-w-6xl items-start gap-6 md:grid-cols-[180px_1fr] lg:grid-cols-[250px_1fr]"> | ||
<nav | ||
className="grid gap-4 text-sm text-muted-foreground" x-chunk="dashboard-04-chunk-0" | ||
> | ||
<Link href="#" className="font-semibold text-primary"> | ||
General | ||
</Link> | ||
<Link href="#">Security</Link> | ||
<Link href="#">Integrations</Link> | ||
<Link href="#">Support</Link> | ||
<Link href="#">Organizations</Link> | ||
<Link href="#">Advanced</Link> | ||
</nav> | ||
<div className="grid gap-6"> | ||
<Card x-chunk="dashboard-04-chunk-1"> | ||
<CardHeader> | ||
<CardTitle>Store Name</CardTitle> | ||
<CardDescription> | ||
Used to identify your store in the marketplace. | ||
</CardDescription> | ||
</CardHeader> | ||
<CardContent> | ||
<form> | ||
<Input placeholder="Store Name" /> | ||
</form> | ||
</CardContent> | ||
<CardFooter className="border-t px-6 py-4"> | ||
<Button>Save</Button> | ||
</CardFooter> | ||
</Card> | ||
<Card x-chunk="dashboard-04-chunk-2"> | ||
<CardHeader> | ||
<CardTitle>Plugins Directory</CardTitle> | ||
<CardDescription> | ||
The directory within your project, in which your plugins are | ||
located. | ||
</CardDescription> | ||
</CardHeader> | ||
<CardContent> | ||
<form className="flex flex-col gap-4"> | ||
<Input | ||
placeholder="Project Name" | ||
defaultValue="/content/plugins" | ||
/> | ||
<div className="flex items-center space-x-2"> | ||
<Checkbox id="include" defaultChecked /> | ||
<label | ||
htmlFor="include" | ||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" | ||
> | ||
Allow administrators to change the directory. | ||
</label> | ||
</div> | ||
</form> | ||
</CardContent> | ||
<CardFooter className="border-t px-6 py-4"> | ||
<Button>Save</Button> | ||
</CardFooter> | ||
</Card> | ||
</div> | ||
</div> | ||
</main> | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
|
||
import Image from "next/image" | ||
import Link from "next/link" | ||
|
||
import { Button } from "@/components/ui/button" | ||
import { Input } from "@/components/ui/input" | ||
import { Label } from "@/components/ui/label" | ||
|
||
export default function Dashboard() { | ||
return ( | ||
<div className="w-full lg:grid lg:min-h-[600px] lg:grid-cols-2 xl:min-h-[800px]"> | ||
<div className="flex items-center justify-center py-12"> | ||
<div className="mx-auto grid w-[350px] gap-6"> | ||
<div className="grid gap-2 text-center"> | ||
<h1 className="text-3xl font-bold">Login</h1> | ||
<p className="text-balance text-muted-foreground"> | ||
Enter your email below to login to your account | ||
</p> | ||
</div> | ||
<div className="grid gap-4"> | ||
<div className="grid gap-2"> | ||
<Label htmlFor="email">Email</Label> | ||
<Input | ||
id="email" | ||
type="email" | ||
placeholder="m@example.com" | ||
required | ||
/> | ||
</div> | ||
<div className="grid gap-2"> | ||
<div className="flex items-center"> | ||
<Label htmlFor="password">Password</Label> | ||
<Link | ||
href="/forgot-password" | ||
className="ml-auto inline-block text-sm underline" | ||
> | ||
Forgot your password? | ||
</Link> | ||
</div> | ||
<Input id="password" type="password" required /> | ||
</div> | ||
<Button type="submit" className="w-full"> | ||
Login | ||
</Button> | ||
<Button variant="outline" className="w-full"> | ||
Login with Google | ||
</Button> | ||
</div> | ||
<div className="mt-4 text-center text-sm"> | ||
Don't have an account?{" "} | ||
<Link href="#" className="underline"> | ||
Sign up | ||
</Link> | ||
</div> | ||
</div> | ||
</div> | ||
<div className="hidden bg-muted lg:block"> | ||
<Image | ||
src="/placeholder.svg" | ||
alt="Image" | ||
width="1920" | ||
height="1080" | ||
className="h-full w-full object-cover dark:brightness-[0.2] dark:grayscale" | ||
/> | ||
</div> | ||
</div> | ||
) | ||
} |
114 changes: 114 additions & 0 deletions
114
frontend/starters/development/app/api/auth/[...nextauth]/route.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import NextAuth from "next-auth" | ||
import CredentialsProvider from "next-auth/providers/credentials" | ||
import jwt_decode from "jwt-decode" | ||
|
||
const handler = NextAuth({ | ||
providers: [ | ||
CredentialsProvider({ | ||
name: "Drupal", | ||
credentials: { | ||
username: { label: "Username", type: "text", placeholder: "Username" }, | ||
password: { label: "Password", type: "password" }, | ||
}, | ||
async authorize(credentials) { | ||
const formData = new URLSearchParams() | ||
formData.append("grant_type", "password") | ||
formData.append("client_id", process.env.NEXT_PUBLIC_DRUPAL_CLIENT_ID) | ||
formData.append("client_secret", process.env.NEXT_PUBLIC_DRUPAL_CLIENT_SECRET) | ||
formData.append("username", credentials.username) | ||
formData.append("password", credentials.password) | ||
|
||
// Get access token from Drupal. | ||
const response = await fetch( | ||
`${process.env.NEXT_PUBLIC_DRUPAL_HOST}/oauth/token`, | ||
{ | ||
method: "POST", | ||
body: formData, | ||
headers: { | ||
"Content-Type": "application/x-www-form-urlencoded", | ||
}, | ||
} | ||
) | ||
|
||
if (!response.ok) { | ||
return null | ||
} | ||
|
||
return await response.json() | ||
}, | ||
}), | ||
], | ||
callbacks: { | ||
async jwt({ token, user, account }) { | ||
if (account && user) { | ||
token.accessToken = user.access_token | ||
token.accessTokenExpires = | ||
Date.now() + (user.expires_in as number) * 1000 | ||
token.refreshToken = user.refresh_token | ||
} | ||
|
||
// If token has not expired, return it, | ||
if (Date.now() < token.accessTokenExpires) { | ||
return token | ||
} | ||
|
||
// Otherwise, refresh the token. | ||
return refreshAccessToken(token) | ||
}, | ||
async session({ session, token }) { | ||
if (token?.accessToken) { | ||
session.accessToken = token.accessToken | ||
const decoded = jwt_decode<{ email: string; username: string }>( | ||
token.accessToken as string | ||
) | ||
session.user.email = decoded.email | ||
session.user.name = decoded.username | ||
session.error = token.error | ||
} | ||
return session | ||
} | ||
}, | ||
}) | ||
|
||
// Helper to obtain a new access_token from a refresh token. | ||
async function refreshAccessToken(token) { | ||
try { | ||
const formData = new URLSearchParams() | ||
|
||
formData.append("grant_type", "refresh_token") | ||
formData.append("client_id", process.env.NEXT_PUBLIC_DRUPAL_CLIENT_ID) | ||
formData.append("client_secret", process.env.NEXT_PUBLIC_DRUPAL_CLIENT_SECRET) | ||
formData.append("refresh_token", token.refreshToken) | ||
|
||
const response = await fetch( | ||
`${process.env.NEXT_PUBLIC_DRUPAL_HOST}/oauth/token`, | ||
{ | ||
method: "POST", | ||
body: formData, | ||
headers: { | ||
"Content-Type": "application/x-www-form-urlencoded", | ||
}, | ||
} | ||
) | ||
|
||
const data = await response.json() | ||
|
||
if (!response.ok) { | ||
throw new Error() | ||
} | ||
|
||
return { | ||
...token, | ||
accessToken: data.access_token, | ||
accessTokenExpires: Date.now() + data.expires_in * 1000, | ||
refreshToken: data.refresh_token ?? token.refreshToken, | ||
} | ||
} catch (error) { | ||
return { | ||
...token, | ||
error: "RefreshAccessTokenError", | ||
} | ||
} | ||
} | ||
|
||
export { handler as GET, handler as POST } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.