Redux-based YouTube clone project using Firebase and YouTube APIs. You can sign in with Google (provided by Firebase Authentication) and enjoy the synchronized Youtube service here (provided by Youtube API)!
- Used Redux and Redux-thunk to efficiently manage asynchronous states. π Read More in my blog
- Folder structure
redux
βββ actions
β βββ auth.action.js
β βββ channel.action.js
β βββ comment.action.js
β βββ video.action.js
βββ reducers
β βββ auth.reducer.js
β βββ channel.reducer.js
β βββ comment.reducer.js
β βββ video.reducer.js
βββ store.js
- Production Period : 2022.03.06 - 2022.03.29
You are able to start the app by typing the following commands in the command line:
git clone https://github.com/devjoylee/utube.git
npm install
npm start
- OAuth Service
- Implemented Google sign-in using Firebase's Authentication provider π Read More in my blog
- Get
access token
from the provider and save it in sessionStorage to authenticate an user
- Code Preview
// pages/loginPage.js
export const LoginPage = () => {
const dispatch = useDispatch();
const navigate = useNavigate();
const accessToken = useSelector((state) => state.auth.accessToken);
// when the login button is clicked, activate login action
const handleLogin = () => {
dispatch(login());
};
// redirect to main page when logged in successfully
useEffect(() => {
if (accessToken) {
navigate('/');
}
}, [accessToken, navigate]);
return <div className='login_page'>// ...</div>;
};
// redux/actions/auth.action.js
// Add google authentication provider
export const login = () => async (dispatch) => {
try {
dispatch({ type: LOGIN_REQUEST });
const provider = new firebase.auth.GoogleAuthProvider();
provider.addScope('https://www.googleapis.com/auth/youtube.force-ssl');
const res = await auth.signInWithPopup(provider);
const accessToken = res.credential.accessToken;
const profile = {
name: res.additionalUserInfo.profile.name,
photoURL: res.additionalUserInfo.profile.picture,
};
sessionStorage.setItem('youtube-token', accessToken);
sessionStorage.setItem('youtube-user', JSON.stringify(profile));
dispatch({ type: LOGIN_SUCCESS, payload: accessToken });
dispatch({ type: LOAD_PROFILE, payload: profile });
} catch (error) {
console.log(error.message);
dispatch({ type: LOGIN_FAIL, payload: error.message });
}
};
- VIDEOs : If you click each video, it will link to the view page of the video.
- CATEGORY : If you click a category at the top of the main page, it will return new video list about the category keyword.
- SEARCH BAR : If you search any keyword through the search bar, it will link to to the search results page.
- Implemented infinite scrolling using
react-infinite-scroll-component
library. - When loading videos, utilized the
Skeleton UI
to improve the user experience.
- Code Preview
// components/Main/Video/VideoList.js
export const VideoList = ({ loadVideos }) => {
const dispatch = useDispatch();
// get video list using redux
useEffect(() => {
dispatch(getPopularVideos());
}, [dispatch]);
const { videos, activeCategory, loading } = useSelector((state) => state.mainVideo);
const fetchData = async () => {
await loadVideos(activeCategory);
};
return (
<div className='video-container'>
{/* Custom Infinite Scroll */}
<InfiniteScroll
dataLength={videos.length}
next={fetchData}
hasMore={true}
className='video-list'
>
{loading || !videos.length
? // when loading videos, show the skeleton UI
[...Array(20)].map((_, i) => <SkeletonVideo key={i} />)
: videos.map((video, i) => <Video key={i} video={video} />)}
</InfiniteScroll>
</div>
);
};
- You can play the video here and see all details such as channel, description, comments, likes, etc
- It has a related video list on the right side of the page.
- When loading a video, utilized the
Skeleton UI
to improve the user experience. - You can actually leave comments at the comment section. It will directly leave comments on the video you are watching by synchronizing with your Google account.
- Code Preview
// components/Watch/Comment/CommentList.js
export const CommentList = ({ videoId, video }) => {
const [text, setText] = useState('');
const dispatch = useDispatch();
const commentList = useSelector((state) => state.commentList.comments);
const commentCount = video?.statistics?.commentCount;
const handleChange = (e) => setText(e.target.value);
const handleComment = (e) => {
e.preventDefault();
if (text.length === 0) return;
// POST comment
dispatch(addComment(videoId, text));
// GET comment
setTimeout(() => dispatch(getCommentsById(videoId)), 2500);
setText('');
};
useEffect(() => {
dispatch(getCommentsById(videoId));
}, [videoId, dispatch]);
return <div className='comments'>// ...</div>;
};
- It will display a list of videos about the keyword you searched from the search bar.
- Implemented infinite scrolling using
react-infinite-scroll-component
library. - When loading list, utilized the
Skeleton UI
to improve the user experience.
- It will show a list of channels you are subscribed by synchronizing with your Google account.
- Implemented infinite scrolling using
react-infinite-scroll-component
library. - When loading list, utilized the
Skeleton UI
to improve the user experience.
The commit message is written with the GITMOJI icons in order to make commit messages more intuitive.
Gitmoji | Meaning |
---|---|
π | Init or begin a project. |
π | Move or rename resources |
β¨ | Introduce new features |
π | Add the UI and style files |
β»οΈ | Refactor code |
π | Add or update documentation |
β | Add a dependency |
π | Fix a bug |
π | Deploy stuff |
REFERENCE : Gitmoji (http://gitmoji.dev/)