encapsulates button into context

This commit is contained in:
Benson Wally Tran 2023-11-18 19:53:37 -06:00
parent 2fc30b9603
commit 783e7969db
4 changed files with 84 additions and 32 deletions

View File

@ -1,33 +1,13 @@
'use-client';
import chatOperations from 'operations/chatOperations';
import { useState } from 'react';
import GenerateStoryContextProvider, { IGenerateStoryContext } from './GenerateStoryContext';
export default function GenerateStoryComponent() {
const [loading, setLoading] = useState(false);
const [data, setData] = useState();
const getStory = async () => {
setLoading(true);
const data = await chatOperations.createStoryAsync();
setData(data);
setLoading(false);
};
return (
<GenerateStoryContextProvider>
{({ story }: IGenerateStoryContext) => {
{({ story, loading }: IGenerateStoryContext) => {
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<button
onClick={getStory}
className="mb-10 rounded bg-blue-500 px-4 py-2 font-bold text-white hover:bg-blue-700"
>
Run A New Story
</button>
{loading ? <div className="mb10">Loading...</div> : null}
{JSON.stringify(data)}
</main>
);
}}

View File

@ -1,23 +1,22 @@
'use client';
import { IStory } from 'operations/chatOperations';
import chatOperations, { IStory } from 'operations/chatOperations';
import { PropsWithChildren, createContext, useContext, useMemo, useState } from 'react';
export interface IGenerateStoryContext {
story?: IStory;
setStory: (story: IStory) => void;
images: string[];
setImages: (images: string[]) => void;
loading: boolean;
}
const GenerateStoryContext = createContext<IGenerateStoryContext>({
story: undefined,
setStory: () => {},
images: [],
setImages: () => {}
loading: false
});
function GenerateStoryContextProvider({ children }: { children: PropsWithChildren<any> }) {
const [loading, setLoading] = useState<boolean>(false);
const [story, setStory] = useState<IStory>();
/*
Note(Benson): For now images is an array of urls where each index in the array
@ -27,13 +26,26 @@ function GenerateStoryContextProvider({ children }: { children: PropsWithChildre
const [images, setImages] = useState<string[]>([]);
const value = useMemo<IGenerateStoryContext>(
() => ({ story, setStory, images, setImages }),
[story, setStory, images, setImages]
() => ({ story, images, loading }),
[story, images, loading]
);
return (
<GenerateStoryContext.Provider value={value}>
{typeof children === 'function' ? children(value) : children}
<>
<button
onClick={async () => {
setLoading(true);
const story = await chatOperations.createStoryAsync();
setStory(story);
setLoading(false);
}}
className="mb-10 rounded bg-blue-500 px-4 py-2 font-bold text-white hover:bg-blue-700"
>
Run A New Story
</button>
{typeof children === 'function' ? children(value) : children}
</>
</GenerateStoryContext.Provider>
);
}

View File

@ -0,0 +1,56 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import dependenciesMatch from 'utils/dependenciesMatch';
const usePromiseMemo = <T, E = unknown>(
promise: () => Promise<T>,
nextDeps: unknown[]
): { results?: T; error?: E; loading: boolean; refetch: () => void } => {
const [results, setResults] = useState<T>();
const [error, setError] = useState<E>();
const [hasFinished, setHasFinished] = useState<boolean>(false);
const dependencies = useRef<unknown[]>(nextDeps);
const isMounted = useRef(true);
const checkIfPromiseIsStillValid = useCallback(
(dependenciesAtTimeOfPromise: unknown[]): boolean => {
return (
isMounted.current && dependenciesMatch(dependenciesAtTimeOfPromise, dependencies.current)
);
},
[]
);
const run = useCallback(() => {
setHasFinished(false);
promise()
.then((r) => checkIfPromiseIsStillValid(nextDeps) && setResults(r))
.catch((e) => checkIfPromiseIsStillValid(nextDeps) && setError(e))
.finally(() => checkIfPromiseIsStillValid(nextDeps) && setHasFinished(true));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, nextDeps);
useEffect(() => {
isMounted.current = true;
dependencies.current = nextDeps;
run();
return () => {
isMounted.current = false;
};
// nextDeps is already a dependency of run
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [run]);
return useMemo(
() => ({
results,
error,
loading: !hasFinished,
refetch: run
}),
// eslint-disable-next-line react-hooks/exhaustive-deps
[hasFinished, results]
);
};
export default usePromiseMemo;

View File

@ -40,9 +40,13 @@ async function createStoryAsync(
content: userPrompt
}
];
const data = await post('/api/open-ai/chat', generateRequestPayload(messages));
// const data = await post('/api/revalidate', generateRequestPayload(messages));
return getFunctionCallArguments<IStory>(data);
try {
const data = await post('/api/open-ai/chat', generateRequestPayload(messages));
return getFunctionCallArguments<IStory>(data);
} catch (e) {
console.error(e);
throw e;
}
}
export default { createStoryAsync };