Skip to content

Commit 72141ab

Browse files
committed
ProtectedPageWrapper and updates
1 parent 75878ac commit 72141ab

File tree

6 files changed

+657
-640
lines changed

6 files changed

+657
-640
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
### [4.1.0](https://github.com/xdevguild/nextjs-dapp-template/releases/tag/v4.1.0) (2022-12-17)
2+
- added `ProtectedPageWrapper` component - client side only 'gate keeper', check README.md for more info
3+
- fix for the `useApiCall` hook
4+
- npm dependencies updates
5+
16
### [4.0.0](https://github.com/xdevguild/nextjs-dapp-template/releases/tag/v4.0.0) (2022-12-04)
27
- changes in how the API proxy work
38
- renamed env variables

README.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,21 +221,41 @@ const { loginMethod, expires, loginToken, signature } = useLoginInfo();
221221

222222
#### useApiCall()
223223

224-
The hook provides a convenient way of doing custom API calls unrelated to transactions or smart contract queries. By default, it will use MultiversX API endpoint. But it can be any type of API, not only MultiversX API. In that case, you would need to pass the `{ baseEndpoint: "https://some-api.com" }` in options
224+
The hook provides a convenient way of doing custom API calls unrelated to transactions or smart contract queries. By default, it will use MultiversX API endpoint. But it can be any type of API, not only MultiversX API. In that case, you would need to pass the `{ baseEndpoint: "https://some-api.com" }`
225225

226226
```jsx
227227
const { data, isLoading, isValidating, fetch, error } = useApiCall<Token[]>({
228-
url: `/accounts/<some_erd_address_here>/tokens`, // can be any API endpoint without the host, because it is already handled internally
228+
url: `/accounts/<some_erd_address_here>/tokens`, // can be any API path without the host, because the host is already handled internally
229229
autoInit: true, // similar to useScQuery
230230
type: 'get', // can be get, post, delete, put
231231
payload: {},
232232
options: {}
233+
baseEndpoint: undefined, // any custom API endpoint, by default MultiversX API
233234
});
234235
```
235236

236237
You can pass the response type. Returned object is the same as in `useScQuery`
237238
The hook uses `swr` and native `fetch` under the hood.
238239

240+
### ProtectedPageWrapper
241+
242+
The component wraps your page contents and will display them only for logged-in users. Otherwise, it will redirect to a defined path. Remember that this is only a client-side check. So don't rely on it with the data that should be private and secured.
243+
244+
```jsx
245+
import { ProtectedPageWrapper } from './components/tools/ProtectedPageWrapper';
246+
247+
const Profile = () => {
248+
return (
249+
<ProtectedPageWrapper>
250+
<Text>The content for logged-in only!</Text>
251+
<Text>For example the profile page or any other that should be accessible only for logged-in users</Text>
252+
</ProtectedPageWrapper>
253+
);
254+
};
255+
256+
export default Profile;
257+
```
258+
239259
### Working with the API
240260

241261
The API endpoint is proxied on the backend side. The only public API endpoint is `/api/multiversx`. This is useful when you don't want to show the API endpoint because, for example, you use the paid ones. Also, there is an option to block the `/api/multiversx` endpoint to be used only within the Dapp, even previewing it in the browser won't be possible.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { useEffect, PropsWithChildren, FC } from 'react';
2+
import { Spinner, Stack } from '@chakra-ui/react';
3+
import { useRouter } from 'next/router';
4+
import { useLogin } from '../../hooks/auth/useLogin';
5+
6+
interface ProtectedPageWrapper {
7+
redirectPath?: string;
8+
}
9+
10+
export const ProtectedPageWrapper: FC<
11+
PropsWithChildren<ProtectedPageWrapper>
12+
> = ({ children, redirectPath = '/' }) => {
13+
const router = useRouter();
14+
const { isLoggedIn, isLoggingIn } = useLogin();
15+
16+
useEffect(() => {
17+
if (!isLoggingIn && !isLoggedIn) {
18+
router.push(redirectPath);
19+
}
20+
// eslint-disable-next-line react-hooks/exhaustive-deps
21+
}, [isLoggedIn, isLoggingIn]);
22+
23+
if (isLoggingIn) {
24+
return (
25+
<Stack
26+
width="100vw"
27+
height="100vh"
28+
flex={1}
29+
direction="row"
30+
alignItems="center"
31+
justifyContent="center"
32+
>
33+
<Spinner size="xl" />
34+
</Stack>
35+
);
36+
}
37+
38+
if (!isLoggingIn && !isLoggedIn) {
39+
return null;
40+
}
41+
42+
return <>{children}</>;
43+
};

hooks/core/useApiCall.tsx

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,32 @@ interface ApiCallData {
88
payload?: Record<string, unknown>;
99
options?: Record<string, unknown>;
1010
autoInit?: boolean;
11+
baseEndpoint?: string;
1112
}
1213

1314
interface FetcherArgs {
1415
url: string;
15-
type?: string;
1616
payload: Record<string, unknown> | undefined;
17+
type?: string;
18+
baseEndpoint?: string;
1719
}
1820

19-
export async function fetcher({ url, type, payload }: FetcherArgs) {
21+
export async function fetcher({
22+
url,
23+
type,
24+
payload,
25+
baseEndpoint,
26+
}: FetcherArgs) {
2027
if (type === 'post') {
21-
return await apiCall.post(url, payload || {});
28+
return await apiCall.post(url, payload || {}, { baseEndpoint });
2229
}
2330
if (type === 'put') {
24-
return await apiCall.put(url, payload || {});
31+
return await apiCall.put(url, payload || {}, { baseEndpoint });
2532
}
2633
if (type === 'delete') {
27-
return await apiCall.delete(url);
34+
return await apiCall.delete(url, { baseEndpoint });
2835
}
29-
return await apiCall.get(url);
36+
return await apiCall.get(url, { baseEndpoint });
3037
}
3138

3239
export function useApiCall<T>({
@@ -35,9 +42,10 @@ export function useApiCall<T>({
3542
payload,
3643
options,
3744
autoInit = true,
45+
baseEndpoint,
3846
}: ApiCallData) {
3947
const { data, error, mutate, isValidating, isLoading } = useSWR(
40-
autoInit ? { url, payload, type } : null,
48+
autoInit ? { url, payload, type, baseEndpoint } : null,
4149
fetcher,
4250
{
4351
revalidateIfStale: true,

0 commit comments

Comments
 (0)