Skip to content

Commit

Permalink
ProtectedPageWrapper and updates
Browse files Browse the repository at this point in the history
  • Loading branch information
juliancwirko committed Dec 17, 2022
1 parent 75878ac commit 72141ab
Show file tree
Hide file tree
Showing 6 changed files with 657 additions and 640 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
### [4.1.0](https://github.com/xdevguild/nextjs-dapp-template/releases/tag/v4.1.0) (2022-12-17)
- added `ProtectedPageWrapper` component - client side only 'gate keeper', check README.md for more info
- fix for the `useApiCall` hook
- npm dependencies updates

### [4.0.0](https://github.com/xdevguild/nextjs-dapp-template/releases/tag/v4.0.0) (2022-12-04)
- changes in how the API proxy work
- renamed env variables
Expand Down
24 changes: 22 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,21 +221,41 @@ const { loginMethod, expires, loginToken, signature } = useLoginInfo();

#### useApiCall()

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
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" }`

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

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

### ProtectedPageWrapper

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.

```jsx
import { ProtectedPageWrapper } from './components/tools/ProtectedPageWrapper';

const Profile = () => {
return (
<ProtectedPageWrapper>
<Text>The content for logged-in only!</Text>
<Text>For example the profile page or any other that should be accessible only for logged-in users</Text>
</ProtectedPageWrapper>
);
};

export default Profile;
```

### Working with the API

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.
Expand Down
43 changes: 43 additions & 0 deletions components/tools/ProtectedPageWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useEffect, PropsWithChildren, FC } from 'react';
import { Spinner, Stack } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import { useLogin } from '../../hooks/auth/useLogin';

interface ProtectedPageWrapper {
redirectPath?: string;
}

export const ProtectedPageWrapper: FC<
PropsWithChildren<ProtectedPageWrapper>
> = ({ children, redirectPath = '/' }) => {
const router = useRouter();
const { isLoggedIn, isLoggingIn } = useLogin();

useEffect(() => {
if (!isLoggingIn && !isLoggedIn) {
router.push(redirectPath);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isLoggedIn, isLoggingIn]);

if (isLoggingIn) {
return (
<Stack
width="100vw"
height="100vh"
flex={1}
direction="row"
alignItems="center"
justifyContent="center"
>
<Spinner size="xl" />
</Stack>
);
}

if (!isLoggingIn && !isLoggedIn) {
return null;
}

return <>{children}</>;
};
22 changes: 15 additions & 7 deletions hooks/core/useApiCall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,32 @@ interface ApiCallData {
payload?: Record<string, unknown>;
options?: Record<string, unknown>;
autoInit?: boolean;
baseEndpoint?: string;
}

interface FetcherArgs {
url: string;
type?: string;
payload: Record<string, unknown> | undefined;
type?: string;
baseEndpoint?: string;
}

export async function fetcher({ url, type, payload }: FetcherArgs) {
export async function fetcher({
url,
type,
payload,
baseEndpoint,
}: FetcherArgs) {
if (type === 'post') {
return await apiCall.post(url, payload || {});
return await apiCall.post(url, payload || {}, { baseEndpoint });
}
if (type === 'put') {
return await apiCall.put(url, payload || {});
return await apiCall.put(url, payload || {}, { baseEndpoint });
}
if (type === 'delete') {
return await apiCall.delete(url);
return await apiCall.delete(url, { baseEndpoint });
}
return await apiCall.get(url);
return await apiCall.get(url, { baseEndpoint });
}

export function useApiCall<T>({
Expand All @@ -35,9 +42,10 @@ export function useApiCall<T>({
payload,
options,
autoInit = true,
baseEndpoint,
}: ApiCallData) {
const { data, error, mutate, isValidating, isLoading } = useSWR(
autoInit ? { url, payload, type } : null,
autoInit ? { url, payload, type, baseEndpoint } : null,
fetcher,
{
revalidateIfStale: true,
Expand Down
Loading

0 comments on commit 72141ab

Please sign in to comment.