Skip to content

Commit

Permalink
wip uploadcare storage provider
Browse files Browse the repository at this point in the history
  • Loading branch information
sergeyt committed Sep 26, 2021
1 parent 4a7e656 commit 71a4a42
Show file tree
Hide file tree
Showing 15 changed files with 307 additions and 87 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

# misc
.DS_Store
.idea

# debug
npm-debug.log*
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
"lodash": "4.17.21",
"next": "11.1.2",
"react": "17.0.2",
"react-content-loader": "6.0.3",
"react-dom": "17.0.2",
"react-google-login": "5.2.2",
"react-player": "2.9.0",
"react-youtube": "7.13.1",
"recoil": "0.4.1",
"swr": "1.0.1"
Expand Down
11 changes: 11 additions & 0 deletions src/axios-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { AxiosResponse } from "axios";

function isStatusOK(status: number) {
return status >= 200 && status < 300;
}

export function checkStatusOK(resp: AxiosResponse) {
if (!isStatusOK(resp.status)) {
throw new Error(JSON.stringify(resp.data));
}
}
4 changes: 3 additions & 1 deletion src/components/CourseView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
TabPanels,
TabPanel,
} from "@chakra-ui/react";
import Player from "react-player";
import YouTube from "react-youtube";
import { Course, Lesson } from "types";

Expand All @@ -33,8 +34,9 @@ const CourseView: React.FC<Props> = ({ data }) => {
<HStack>
<Box h="380px">
{lesson?.youtubeVideoId ? (
<YouTube videoId={lesson?.youtubeVideoId} />
<YouTube videoId={lesson.youtubeVideoId} />
) : null}
{lesson?.videoUrl ? <Player url={lesson.videoUrl} /> : null}
</Box>
{/* lesson list */}
<Box h="380px" overflow="auto">
Expand Down
33 changes: 33 additions & 0 deletions src/components/Loader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from "react";
import ContentLoader from "react-content-loader";

const Default = (props) => (
<ContentLoader
speed={2}
width={800}
height={100}
viewBox="0 0 800 100"
backgroundColor="#f3f3f3"
foregroundColor="#ecebeb"
{...props}
>
<rect x="0" y="0" rx="3" ry="3" width="67" height="11" />
<rect x="76" y="0" rx="3" ry="3" width="140" height="11" />
<rect x="127" y="48" rx="3" ry="3" width="53" height="11" />
<rect x="187" y="48" rx="3" ry="3" width="72" height="11" />
<rect x="18" y="48" rx="3" ry="3" width="100" height="11" />
<rect x="0" y="71" rx="3" ry="3" width="37" height="11" />
<rect x="18" y="23" rx="3" ry="3" width="140" height="11" />
<rect x="166" y="23" rx="3" ry="3" width="173" height="11" />
</ContentLoader>
);

type Props = {
[prop: string]: any;
};

const Loader: React.FC<Props> = ({ ...props }) => {
return <Default {...props} />;
};

export default Loader;
34 changes: 34 additions & 0 deletions src/components/UploadcareFileGroups.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import _ from "lodash";
import Link from "next/link";
import useSWR from "swr";
import { Box } from "@chakra-ui/react";
import { getFileGroups } from "uploadcare-api";
import ErrorView from "./ErrorView";
import Loader from "./Loader";

const UploadcareFileGroups = ({ apiConfig }) => {
const { data, error } = useSWR("/uc/file-groups", () =>
getFileGroups(apiConfig)
);
return (
<>
<ErrorView error={error} />
{!error && !data && <Loader />}
{!error && data && _.isEmpty(data) ? (
<Box m={3}>You don't have file groups yet.</Box>
) : null}
{_.map(data?.results, (item, k) => {
const id = item.id.replace("~1", "");
return (
<Box key={k}>
<Link href={`/course/uploadcare/${id}`}>
{item.title || id}
</Link>
</Box>
);
})}
</>
);
};

export default UploadcareFileGroups;
47 changes: 47 additions & 0 deletions src/components/YouTubePlaylists.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import _ from "lodash";
import Link from "next/link";
import { Box } from "@chakra-ui/react";
import useSWR from "swr";
import { getPlaylists } from "youtube-api";
import { useAccessToken } from "components/GoogleAuth";
import ErrorView from "./ErrorView";
import Loader from "./Loader";

const YouTubePlaylists = () => {
const accessToken = useAccessToken();
const { data, error } = useSWR(
`/playlists?token=${accessToken}`,
async () => {
if (!accessToken) {
return [];
}
const resp = await getPlaylists({
accessToken,
});
return resp.items.map((t) => ({
id: t.id,
title: t.snippet.title,
description: t.snippet.description,
}));
}
);
return (
<>
<ErrorView error={error} />
{!error && !data && <Loader />}
{!error && data && _.isEmpty(data) ? (
<Box m={3}>
No data. Please login into your google account to view your video
courses
</Box>
) : null}
{_.map(data, (item, k) => (
<Box key={k}>
<Link href={`/course/youtube/${item.id}`}>{item.title}</Link>
</Box>
))}
</>
);
};

export default YouTubePlaylists;
44 changes: 0 additions & 44 deletions src/pages/course/[pid].tsx

This file was deleted.

51 changes: 51 additions & 0 deletions src/pages/course/uploadcare/[id].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import _ from "lodash";
import { useRouter } from "next/router";
import CourseView from "components/CourseView";
import ErrorView from "components/ErrorView";
import Page from "components/Layout";
import useSWR from "swr";
import { getFileGroup } from "uploadcare-api";
import { Course } from "types";

export async function getStaticPaths() {
return {
paths: ["/course/uploadcare/1"],
fallback: true,
};
}

export async function getStaticProps() {
return {
props: {
uploadcare: {
publicKey: process.env.UC_PUBLIC_KEY,
secretKey: process.env.UC_SECRET_KEY,
},
},
};
}

export default function CoursePage({ uploadcare }) {
const router = useRouter();
const { id } = router.query;
const { data, error } = useSWR(`/uploadcare/file-group/${id}`, async () => {
const grp = await getFileGroup(String(id), uploadcare);
return {
title: grp.title || grp.id,
description: grp.description || "",
lessons: _.map(grp.items, (t) => ({
title: t.snippet.title,
description: t.snippet.description,
duration: 5,
youtubeVideoId: t.contentDetails.videoId,
})),
} as Course;
});

return (
<Page>
<ErrorView error={error} />
{data ? <CourseView data={data} /> : null}
</Page>
);
}
47 changes: 47 additions & 0 deletions src/pages/course/youtube/[pid].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import _ from "lodash";
import { useRouter } from "next/router";
import CourseView from "components/CourseView";
import { useAccessToken } from "components/GoogleAuth";
import ErrorView from "components/ErrorView";
import Page from "components/Layout";
import useSWR from "swr";
import { getPlaylistItems, getPlaylists } from "youtube-api";
import { Course } from "types";

export default function CoursePage() {
const router = useRouter();
const { pid } = router.query;
const accessToken = useAccessToken();
const { data, error } = useSWR(
`/youtube/course?token=${accessToken}`,
async () => {
if (!accessToken) {
throw new Error("no access token");
}
// TODO get playlist by id
const list = await getPlaylists({ accessToken });
const playlist = _.find(list.items, (t) => t.id === pid);
const resp = await getPlaylistItems({
playlistId: String(pid),
accessToken,
});
return {
title: playlist?.snippet?.title || "",
description: playlist?.snippet?.description || "",
lessons: resp.items.map((t) => ({
title: t.snippet.title,
description: t.snippet.description,
duration: 5,
youtubeVideoId: t.contentDetails.videoId,
})),
} as Course;
}
);

return (
<Page>
<ErrorView error={error} />
{data ? <CourseView data={data} /> : null}
</Page>
);
}
56 changes: 16 additions & 40 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import _ from "lodash";
import Link from "next/link";
import {
Box,
Stack,
Expand All @@ -9,59 +8,36 @@ import {
TabPanels,
TabPanel,
} from "@chakra-ui/react";
import ErrorView from "components/ErrorView";
import { useAccessToken } from "components/GoogleAuth";
import Page from "components/Layout";
import useSWR from "swr";
import { getPlaylists } from "youtube-api";
import YouTubePlaylists from "components/YouTubePlaylists";
import UCFileGroups from "components/UploadcareFileGroups";

export default function Home() {
const accessToken = useAccessToken();
const { data, error } = useSWR(
`/playlists?token=${accessToken}`,
async () => {
if (!accessToken) {
return [];
}
const resp = await getPlaylists({
accessToken,
});
return resp.items.map((t) => ({
id: t.id,
title: t.snippet.title,
description: t.snippet.description,
}));
}
);
export async function getStaticProps() {
return {
props: {
uploadcare: {
publicKey: process.env.UC_PUBLIC_KEY,
secretKey: process.env.UC_SECRET_KEY,
},
},
};
}

export default function Home({ uploadcare }) {
return (
<Page>
<Stack>
<ErrorView error={error} />
<Tabs>
<Tabs isLazy>
<TabList>
<Tab>YouTube</Tab>
<Tab>UploadCare</Tab>
</TabList>
<TabPanels>
<TabPanel>
{_.isEmpty(data) ? (
<Box m={3}>
No data. Please login into your google account to view your
video courses
</Box>
) : null}
{_.map(data, (item) => (
<Box>
<Link href={`/course/${item.id}`}>{item.title}</Link>
</Box>
))}
<YouTubePlaylists />
</TabPanel>
<TabPanel>
<Box m={3}>
No data. Please login into your uploadcare account to view your
video courses
</Box>
<UCFileGroups apiConfig={uploadcare} />
</TabPanel>
</TabPanels>
</Tabs>
Expand Down
Loading

1 comment on commit 71a4a42

@vercel
Copy link

@vercel vercel bot commented on 71a4a42 Sep 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.