mirror of
https://github.com/hansputera/tiktok-dl.git
synced 2026-04-05 19:51:57 +02:00
feat(apps.web#components): added "swr", and ErrorBoundary component
Signed-off-by: GitHub <noreply@github.com>
This commit is contained in:
committed by
GitHub
parent
fc21150ea5
commit
41dd01d383
40
apps/web/components/ErrorBoundary.tsx
Normal file
40
apps/web/components/ErrorBoundary.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import {Component, ReactNode} from 'react';
|
||||
|
||||
interface Props {
|
||||
children: ReactNode;
|
||||
fallback: ReactNode;
|
||||
}
|
||||
|
||||
interface State {
|
||||
hasError: boolean;
|
||||
error?: Error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class ErrorBoundary
|
||||
*/
|
||||
export class ErrorBoundary extends Component<Props, State> {
|
||||
public state: State = {
|
||||
hasError: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Error} error an error.
|
||||
* @return {State}
|
||||
*/
|
||||
public static getDerivedStateFromError(error: Error): State {
|
||||
return {hasError: true, error};
|
||||
}
|
||||
|
||||
/**
|
||||
* Render error.
|
||||
* @return {JSX.Element}
|
||||
*/
|
||||
public render(): JSX.Element {
|
||||
if (this.state.hasError) {
|
||||
return this.props.fallback as JSX.Element;
|
||||
}
|
||||
|
||||
return this.props.children as JSX.Element;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
import React from 'react';
|
||||
import React, {Suspense} from 'react';
|
||||
import {ErrorBoundary} from './ErrorBoundary';
|
||||
import {TikTokVideoComponent} from './Video';
|
||||
|
||||
// // ERRORS ///
|
||||
/**
|
||||
@@ -13,7 +15,6 @@ class InvalidUrlError extends Error {
|
||||
this.name = 'INVALID_URL';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* FormInput Component.
|
||||
* @return {JSX.Element}
|
||||
@@ -21,6 +22,7 @@ class InvalidUrlError extends Error {
|
||||
export const FormInputComponent = (): JSX.Element => {
|
||||
const [url, setUrl] = React.useState('');
|
||||
const [error, setError] = React.useState<string | Error>();
|
||||
const [submitted, setSubmit] = React.useState<boolean>(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (
|
||||
@@ -49,7 +51,10 @@ export const FormInputComponent = (): JSX.Element => {
|
||||
<form
|
||||
target="#"
|
||||
className="flex flex-col md:flex-row"
|
||||
onSubmit={() => {}}
|
||||
onSubmit={() => {
|
||||
!error && setSubmit(true);
|
||||
return;
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
@@ -63,13 +68,33 @@ export const FormInputComponent = (): JSX.Element => {
|
||||
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
className="p-3 ml-2 bg-sky-400 uppercase text-white"
|
||||
className="p-3 lg:ml-2 md:mt-2 sm:mt-2 bg-sky-400 uppercase text-white"
|
||||
disabled={submitted}
|
||||
>
|
||||
download
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{submitted && (
|
||||
<ErrorBoundary
|
||||
fallback={
|
||||
<h2 className="text-red-500 font-sans font-medium text-base">
|
||||
Couldn't fetch tiktok's video url
|
||||
</h2>
|
||||
}
|
||||
>
|
||||
<Suspense
|
||||
fallback={
|
||||
<h2 className="font-sans font-medium text-base">
|
||||
Loading...
|
||||
</h2>
|
||||
}
|
||||
>
|
||||
<TikTokVideoComponent url={new URL(url)} />
|
||||
</Suspense>
|
||||
</ErrorBoundary>
|
||||
)}
|
||||
</section>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
@@ -1,22 +1,42 @@
|
||||
import React from 'react';
|
||||
import useSWR, {Fetcher} from 'swr';
|
||||
import {ExtractedInfo} from 'tiktok-dl-core';
|
||||
|
||||
type ExtractedInfoWithProvider = ExtractedInfo & {
|
||||
export type ExtractedInfoWithProvider = ExtractedInfo & {
|
||||
provider: string;
|
||||
};
|
||||
|
||||
// fetcher
|
||||
const fetcher: Fetcher<ExtractedInfoWithProvider, string> = (...args) =>
|
||||
fetch(...args).then((res) => res.json());
|
||||
|
||||
/**
|
||||
* Render tiktok video component.
|
||||
* @param {ExtractedInfoWithProvider} data tiktok's api result.
|
||||
* @param {{ url: URL; }} param0 TikTokVideoComponent props.
|
||||
* @return {JSX.Element}
|
||||
*/
|
||||
export const TikTokVideoComponent = (
|
||||
data: ExtractedInfoWithProvider,
|
||||
): JSX.Element => {
|
||||
export const TikTokVideoComponent = ({url}: {url: URL}): JSX.Element => {
|
||||
url.search = ''; // clean params.
|
||||
const {data} = useSWR(
|
||||
[
|
||||
'/api/download',
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify({url: url.href}),
|
||||
},
|
||||
],
|
||||
fetcher,
|
||||
{
|
||||
suspense: true,
|
||||
},
|
||||
);
|
||||
|
||||
console.log(data);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<section className="mt-5">
|
||||
{data.error ? (
|
||||
{data && !data.error ? (
|
||||
<>
|
||||
<h1 className="text-base">Here is your video:</h1>
|
||||
<ul className="flex flex-col md:flex-row flex-grow-0">
|
||||
@@ -29,7 +49,7 @@ export const TikTokVideoComponent = (
|
||||
) : (
|
||||
<>
|
||||
<h1 className="text-base text-red-500 font-medium">
|
||||
Error: {data.error}
|
||||
Error: {data && data.error ? data.error : 'wait'}
|
||||
</h1>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -9,7 +9,7 @@ export default async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
await ratelimitMiddleware(req, res);
|
||||
const providersType = Providers.map((p) => p.resourceName());
|
||||
ow(
|
||||
req.body || req.query,
|
||||
req.method === 'POST' ? JSON.parse(req.body) : req.query,
|
||||
ow.object.partialShape({
|
||||
url: ow.string.url.validate((v) => ({
|
||||
validator:
|
||||
|
||||
Reference in New Issue
Block a user