Skip to content

Commit

Permalink
adding app router example for custom page ui
Browse files Browse the repository at this point in the history
  • Loading branch information
jowo-io committed Dec 9, 2023
1 parent 5c092e9 commit 88bf123
Show file tree
Hide file tree
Showing 39 changed files with 4,663 additions and 15 deletions.
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ Create a new API route under `pages/api/lnauth/[...lnauth].ts`
// @/pages/api/lnauth/[...lnauth].ts

import NextAuthLightning, {
LightningAuthSession,
NextAuthLightningConfig,
} from "next-auth-lightning-provider";
import generateQr from "next-auth-lightning-provider/generators/qr";
Expand Down Expand Up @@ -280,7 +279,7 @@ const config: NextAuthLightningConfig = {
*
* @note the path must begin with a leading `/`. For example, `/signin`, not `signin`.
*
* @see https://github.com/jowo-io/next-auth-lightning-provider/tree/main/examples/custom-pages/
* @see https://github.com/jowo-io/next-auth-lightning-provider/tree/main/examples/ui-pages-router/
*
* @default "/api/lnauth/signin"
*/
Expand All @@ -295,7 +294,7 @@ const config: NextAuthLightningConfig = {
*
* @note the path must begin with a leading `/`. For example, `/error`, not `error`.
*
* @see https://github.com/jowo-io/next-auth-lightning-provider/tree/main/examples/custom-pages/
* @see https://github.com/jowo-io/next-auth-lightning-provider/tree/main/examples/ui-pages-router/
*
* @default "/api/auth/error"
*/
Expand Down
11 changes: 6 additions & 5 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ Below is a TODO list for further development of `next-auth-lightning-provider`.

### Alpha

- `Response body object should not be disturbed or locked` in `ui-app-router` example create request
- test deploy all the various example apps
- app router generic
- app router custom pages
- pages router generic
- pages router custom pages
- ar-generic
- ar-custom
- pr-generic
- pr-custom

### Beta

Expand Down Expand Up @@ -43,5 +44,5 @@ Stuff I may or may not get around to:
- 404 page?
- make jest typescript settings the same as project
- add extra tests for difficult code like signin / diagnostics pages, hooks, vanilla js etc.
- look into dicebear console warnings in `custom-pages` example when running when running locally (they don't appear when when installed via npm, so low priority)
- look into dicebear console warnings in `ui-pages-router` example when running when running locally (they don't appear when when installed via npm, so low priority)
- implement CSRF for poll and create endpoints (the rest are either GET requests or made under the `next-auth` hood, e.g. `token` request)
14 changes: 10 additions & 4 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
# Examples

### Custom Auth page

The [examples/custom-pages/](https://github.com/jowo-io/next-auth-lightning-provider/tree/main/examples/custom-pages) example demonstrates how to configure a custom Lightning auth pages.

### App Router

The [examples/app-router/](https://github.com/jowo-io/next-auth-lightning-provider/tree/main/examples/app-router) example demonstrates how to configure `next-auth-lightning-provider` using the Next.js App Router.
Expand Down Expand Up @@ -31,3 +27,13 @@ The [examples/drizzle/](https://github.com/jowo-io/next-auth-lightning-provider/
### Firebase

> COMING SOON
### Customized UI

##### Pages router

The [examples/ui-pages-router/](https://github.com/jowo-io/next-auth-lightning-provider/tree/main/examples/ui-pages-router) example demonstrates how to configure a custom UI for the Lightning auth pages in the pages router.

##### App router

The [examples/ui-app-router/](https://github.com/jowo-io/next-auth-lightning-provider/tree/main/examples/ui-app-router) example demonstrates how to configure a custom UI for the Lightning auth pages in the app router.
1 change: 0 additions & 1 deletion examples/app-router/app/api/lnauth/[...lnauth]/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import NextAuthLightning, {
LightningAuthSession,
NextAuthLightningConfig,
} from "next-auth-lightning-provider";
import generateQr from "next-auth-lightning-provider/generators/qr";
Expand Down
1 change: 0 additions & 1 deletion examples/kv/pages/api/lnauth/[...lnauth].ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import NextAuthLightning, {
LightningAuthSession,
NextAuthLightningConfig,
} from "next-auth-lightning-provider";
import generateQr from "next-auth-lightning-provider/generators/qr";
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
7 changes: 7 additions & 0 deletions examples/ui-app-router/app/api/auth/[...nextauth]/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { AuthOptions } from "next-auth";

import { lightningProvider } from "../../lnauth/[...lnauth]/config";

export const authOptions: AuthOptions = {
providers: [lightningProvider],
};
6 changes: 6 additions & 0 deletions examples/ui-app-router/app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import NextAuth from "next-auth";
import { authOptions } from "./config";

const handler = NextAuth(authOptions);

export { handler as GET, handler as POST };
56 changes: 56 additions & 0 deletions examples/ui-app-router/app/api/lnauth/[...lnauth]/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import NextAuthLightning, {
NextAuthLightningConfig,
} from "next-auth-lightning-provider";
import generateQr from "next-auth-lightning-provider/generators/qr";
import generateName from "next-auth-lightning-provider/generators/name";
import generateAvatar from "next-auth-lightning-provider/generators/avatar";

import { env } from "@/env.mjs";

import storage from "node-persist"; // ⚠️ WARNING using node-persist is not recommended in lambda or edge environments.

await storage.init();

const config: NextAuthLightningConfig = {
// required
siteUrl: env.NEXTAUTH_URL,
secret: env.NEXTAUTH_SECRET,
storage: {
async set({ k1, session }) {
await storage.setItem(`k1:${k1}`, session);
},
async get({ k1 }) {
return await storage.getItem(`k1:${k1}`);
},
async update({ k1, session }) {
const old = await storage.getItem(`k1:${k1}`);
await storage.updateItem(`k1:${k1}`, { ...old, ...session });
},
async delete({ k1 }) {
await storage.removeItem(`k1:${k1}`);
},
},
generateQr,

// optional
generateName,
generateAvatar,

pages: {
signIn: "/signin",
error: "/error",
},
flags: {
diagnostics: true,
logs: true,
},
theme: {
colorScheme: "dark",
},
};

const { provider, handler } = NextAuthLightning(config);

export const lightningProvider = provider;

export { handler };
3 changes: 3 additions & 0 deletions examples/ui-app-router/app/api/lnauth/[...lnauth]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { handler } from "./config";

export { handler as GET, handler as POST };
89 changes: 89 additions & 0 deletions examples/ui-app-router/app/components/LightningAuth.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"use client";

import { useLightningAuth } from "next-auth-lightning-provider/hooks";

export default function LightningAuth({
redirectUri,
state,
}: {
redirectUri: string;
state: string;
}) {
const { lnurl, qr, button } = useLightningAuth({ redirectUri, state });

if (!lnurl) {
return (
<div style={{ textAlign: "center", color: "black" }}>loading...</div>
);
}

return (
<div
style={{
margin: "auto",
maxWidth: 400,
textAlign: "center",
background: "#fff",
color: "#000",
padding: "20px 30px",
borderRadius: 20,
}}
>
<h1
style={{
fontSize: 20,
color: "#000",
marginTop: 0,
marginBottom: 15,
}}
>
Plain JSX
</h1>
<img
width={500}
height={500}
alt="Login with Lightning - QRCode"
style={{
display: "block",
overflow: "hidden",
borderRadius: 5,
width: "100%",
height: "auto",
}}
src={qr}
/>
<pre
style={{
wordBreak: "break-all",
whiteSpace: "pre-wrap",
userSelect: "all",
marginTop: 10,
marginBottom: 10,
}}
>
{lnurl}
</pre>

<a
style={{
alignItems: "center",
backgroundColor: "#f2f2f2",
textDecoration: "none",
border: `2px solid rgba(110, 110, 110, 0.3)`,
borderRadius: 10,
color: "#000",
display: "flex",
fontSize: "1.1rem",
fontWeight: "500",
justifyContent: "center",
minHeight: "30px",
padding: ".75rem 1rem",
position: "relative",
}}
href={button}
>
Open Lightning Wallet
</a>
</div>
);
}
20 changes: 20 additions & 0 deletions examples/ui-app-router/app/components/SignInButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"use client";

import { Session } from "next-auth";
import { signOut, signIn } from "next-auth/react";

export const SignInButton = async ({
session,
}: {
session: Session | null;
}) => {
return (
<div>
{session ? (
<button onClick={() => signOut()}>Sign out</button>
) : (
<button onClick={() => signIn()}>Sign in</button>
)}
</div>
);
};
40 changes: 40 additions & 0 deletions examples/ui-app-router/app/error/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"use client";

import { useSearchParams } from "next/navigation";
import { ErrorCodes } from "next-auth-lightning-provider";

function formatErrorCode(value: any): keyof typeof ErrorCodes {
if (Array.isArray(value)) value = value[0];
if (value && ErrorCodes.hasOwnProperty(value)) {
return value as keyof typeof ErrorCodes;
}
return "Default";
}

export default function Error() {
const searchParams = useSearchParams();
const query = {
message: searchParams?.get("message"),
error: searchParams?.get("error"),
};

const errorCode = formatErrorCode(query.error);

// access an error message from the query parameters
const queryMessage = query.message || ErrorCodes.Default;

// access an error message from the `ErrorCodes` enum
const hardCodedMessage = ErrorCodes[errorCode];

return (
<div style={{ textAlign: "center", color: "red" }}>
<b>Query param message:</b>
<br />
{queryMessage}
<br />
<b>Hard coded message:</b>
<br />
{hardCodedMessage}
</div>
);
}
27 changes: 27 additions & 0 deletions examples/ui-app-router/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ReactNode } from "react";
import { Metadata } from "next";

/**
* Default metadata.
*
* @see https://nextjs.org/docs/app/api-reference/file-conventions/metadata
*/
export const metadata: Metadata = {
title: "Login with Lightning",
};

/**
* The homepage root layout.
*
* @see https://nextjs.org/docs/app/api-reference/file-conventions/layout
*/
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<head />
<body>
<main>{children}</main>
</body>
</html>
);
}
32 changes: 32 additions & 0 deletions examples/ui-app-router/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { getServerSession } from "next-auth";

import { authOptions } from "@/app/api/auth/[...nextauth]/config";
import { SignInButton } from "./components/SignInButton";

const Home = async () => {
const session = await getServerSession(authOptions);

return (
<div>
<h3>Auth session:</h3>

{session?.user?.image && (
<>
<img
width="50px"
height="50px"
src={session.user?.image}
alt={`Avatar of ${session.user?.name}`}
/>
<br />
</>
)}

<pre>{JSON.stringify({ session }, null, 2)}</pre>

<SignInButton session={session} />
</div>
);
};

export default Home;
Loading

0 comments on commit 88bf123

Please sign in to comment.