mirror of
https://github.com/status-im/js-waku-examples.git
synced 2025-03-02 15:40:57 +00:00
add create and edit pages, create Waku provider
This commit is contained in:
parent
1abf528f75
commit
63f222d3cc
51
examples/flush-notes/src/app/WakuProvider.tsx
Normal file
51
examples/flush-notes/src/app/WakuProvider.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { waku, Waku, WakuEvents } from "@/services/waku";
|
||||
|
||||
type WakuContextProps = {
|
||||
status: string;
|
||||
};
|
||||
|
||||
const WakuContext = React.createContext<WakuContextProps>({
|
||||
status: "",
|
||||
});
|
||||
|
||||
type WakuProviderProps = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export const useWaku = () => {
|
||||
const { status } = React.useContext(WakuContext);
|
||||
|
||||
return { status };
|
||||
};
|
||||
|
||||
export const WakuProvider = (props: WakuProviderProps) => {
|
||||
const wakuRef = React.useRef<Waku>();
|
||||
const [status, setStatus] = React.useState<string>("");
|
||||
|
||||
React.useEffect(() => {
|
||||
if (wakuRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const statusListener = (event: CustomEvent) => {
|
||||
setStatus(event.detail);
|
||||
};
|
||||
waku.addEventListener(WakuEvents.Status, statusListener);
|
||||
|
||||
waku.init().then(() => {
|
||||
wakuRef.current = waku;
|
||||
});
|
||||
return () => {
|
||||
waku.removeEventListener(WakuEvents.Status, statusListener);
|
||||
};
|
||||
}, [wakuRef, setStatus]);
|
||||
|
||||
return (
|
||||
<WakuContext.Provider value={{ status }}>
|
||||
{props.children}
|
||||
</WakuContext.Provider>
|
||||
);
|
||||
};
|
12
examples/flush-notes/src/app/create/page.tsx
Normal file
12
examples/flush-notes/src/app/create/page.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import { useWaku } from "@/app/WakuProvider";
|
||||
|
||||
export default function Create() {
|
||||
const { status } = useWaku();
|
||||
return (
|
||||
<div>
|
||||
<p>{status}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
48
examples/flush-notes/src/app/edit/page.tsx
Normal file
48
examples/flush-notes/src/app/edit/page.tsx
Normal file
@ -0,0 +1,48 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import Markdown from "react-markdown";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useNoteHash } from "@/hooks/useNoteHash";
|
||||
|
||||
const t = `
|
||||
### Problem
|
||||
Cannot read data returned from REST API in browser if request is done with CORS violation.
|
||||
|
||||
# Impact
|
||||
Prevents browsers from querying REST API.
|
||||
|
||||
### To reproduce
|
||||
0. Run nwaku REST API
|
||||
1. Copy https://github.com/waku-org/waku-frontend/tree/weboko/follow-up
|
||||
5. Wait for 10 seconds and see in console following error:
|
||||
|
||||
It happens even though the request succeds.
|
||||
|
||||
|
||||
### Expected behavior
|
||||
Error should not happen.
|
||||
|
||||
### Additional context
|
||||
What happens is that browser implements Fetch API in the manner that when request is made to resource with CORS violation then even if it would succeed - client won't be able to read response data.
|
||||
Spec of the Fetch API - https://fetch.spec.whatwg.org/#concept-filtered-response-opaque
|
||||
|
||||
|
||||
### The fix
|
||||
Considering we expect REST API to be run only on localhost we should add following HTTP header to allow web apps run on different port to be able to talk to the API.
|
||||
`;
|
||||
|
||||
const View = () => {
|
||||
const router = useRouter();
|
||||
const noteHash = useNoteHash();
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!noteHash) {
|
||||
router.replace("/404");
|
||||
}
|
||||
}, [noteHash]);
|
||||
|
||||
return <Markdown>{t}</Markdown>;
|
||||
};
|
||||
|
||||
export default View;
|
@ -1,14 +1,12 @@
|
||||
import type { Metadata } from "next";
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { Inter } from "next/font/google";
|
||||
import { WakuProvider } from "@/app/WakuProvider";
|
||||
import "./globals.css";
|
||||
|
||||
const inter = Inter({ subsets: ["latin"] });
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Flush notes",
|
||||
description: "An app to share notes",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
@ -16,7 +14,9 @@ export default function RootLayout({
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={inter.className}>{children}</body>
|
||||
<body className={inter.className}>
|
||||
<WakuProvider>{children}</WakuProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
@ -1,32 +1,22 @@
|
||||
import Markdown from "react-markdown";
|
||||
"use client";
|
||||
|
||||
const t = `
|
||||
### Problem
|
||||
Cannot read data returned from REST API in browser if request is done with CORS violation.
|
||||
|
||||
# Impact
|
||||
Prevents browsers from querying REST API.
|
||||
|
||||
### To reproduce
|
||||
0. Run nwaku REST API
|
||||
1. Copy https://github.com/waku-org/waku-frontend/tree/weboko/follow-up
|
||||
5. Wait for 10 seconds and see in console following error:
|
||||
|
||||
It happens even though the request succeds.
|
||||
|
||||
|
||||
### Expected behavior
|
||||
Error should not happen.
|
||||
|
||||
### Additional context
|
||||
What happens is that browser implements Fetch API in the manner that when request is made to resource with CORS violation then even if it would succeed - client won't be able to read response data.
|
||||
Spec of the Fetch API - https://fetch.spec.whatwg.org/#concept-filtered-response-opaque
|
||||
|
||||
|
||||
### The fix
|
||||
Considering we expect REST API to be run only on localhost we should add following HTTP header to allow web apps run on different port to be able to talk to the API.
|
||||
`;
|
||||
import { useWaku } from "@/app/WakuProvider";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
export default function Home() {
|
||||
return <Markdown>{t}</Markdown>;
|
||||
const { status } = useWaku();
|
||||
const router = useRouter();
|
||||
return (
|
||||
<div>
|
||||
<p>{status}</p>
|
||||
<button
|
||||
onClick={() => {
|
||||
router.push("/create");
|
||||
}}
|
||||
>
|
||||
Create new
|
||||
</button>
|
||||
<button>Edit existing</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
import React from "react";
|
||||
import Markdown from "react-markdown";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useViewHash } from "@/hooks/useViewHash";
|
||||
import { useNoteHash } from "@/hooks/useNoteHash";
|
||||
|
||||
const t = `
|
||||
### Problem
|
||||
@ -34,7 +34,7 @@ Considering we expect REST API to be run only on localhost we should add followi
|
||||
|
||||
const View = () => {
|
||||
const router = useRouter();
|
||||
const noteHash = useViewHash();
|
||||
const noteHash = useNoteHash();
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!noteHash) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
export const useViewHash = (): undefined | string => {
|
||||
export const useNoteHash = (): undefined | string => {
|
||||
const pathname = usePathname();
|
||||
const segments = pathname.split("/");
|
||||
const viewIndex = segments.indexOf("view");
|
@ -1,18 +1,59 @@
|
||||
import { LightNode, createLightNode } from "@waku/sdk";
|
||||
"use client";
|
||||
|
||||
type WakuOptions = {
|
||||
node: LightNode;
|
||||
};
|
||||
import { LightNode, createLightNode, waitForRemotePeer } from "@waku/sdk";
|
||||
|
||||
type EventListener = (event: CustomEvent) => void;
|
||||
|
||||
export enum WakuEvents {
|
||||
Status = "status",
|
||||
}
|
||||
|
||||
export class Waku {
|
||||
private node: undefined | LightNode;
|
||||
|
||||
private constructor(options: WakuOptions) {
|
||||
this.node = options.node;
|
||||
private emitter = new EventTarget();
|
||||
private initialized: boolean = false;
|
||||
private initializing: boolean = false;
|
||||
|
||||
constructor() {}
|
||||
|
||||
public async init(): Promise<void> {
|
||||
if (this.initialized || this.initializing) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.initializing = true;
|
||||
console.log("Waku");
|
||||
try {
|
||||
this.emitStatusEvent("Initializing...");
|
||||
const node = await createLightNode({ defaultBootstrap: true });
|
||||
await node.start();
|
||||
this.emitStatusEvent("Waiting for peers...");
|
||||
await waitForRemotePeer(node);
|
||||
this.node = node;
|
||||
this.initialized = true;
|
||||
this.emitStatusEvent("Connected");
|
||||
} catch (error) {
|
||||
console.error("Failed to initialize Waku node:", error);
|
||||
this.emitStatusEvent("Failed to initialize(see logs)");
|
||||
}
|
||||
this.initializing = false;
|
||||
}
|
||||
|
||||
public static async init(): Promise<Waku> {
|
||||
const node = await createLightNode({ defaultBootstrap: true });
|
||||
return new Waku({ node });
|
||||
public addEventListener(event: WakuEvents, fn: EventListener) {
|
||||
return this.emitter.addEventListener(event, fn as any);
|
||||
}
|
||||
|
||||
public removeEventListener(event: WakuEvents, fn: EventListener) {
|
||||
return this.emitter.removeEventListener(event, fn as any);
|
||||
}
|
||||
|
||||
private emitStatusEvent(payload: string) {
|
||||
console.log(payload);
|
||||
this.emitter.dispatchEvent(
|
||||
new CustomEvent(WakuEvents.Status, { detail: payload })
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const waku = new Waku();
|
||||
|
Loading…
x
Reference in New Issue
Block a user