remove top right buttons, move stars button to top right, add delete account button, use mock data in step 1, change some descriptions
This commit is contained in:
@@ -60,3 +60,6 @@ See [docs/CONTRIBUTING.md](https://github.com/avgupta456/github-trends/blob/main
|
||||
## Acknowledgements
|
||||
|
||||
Much inspiration was taken from [GitHub Readme Stats](https://github.com/anuraghazra/github-readme-stats). If you haven't already, check it out and give it a star!
|
||||
|
||||
## Other
|
||||
We use your GitHub API access token to make requests on your behalf. All of our code is open-source and visible on our GitHub repository.
|
||||
@@ -44,12 +44,8 @@ export function setIsAuthenticated(newIsAuthenticated) {
|
||||
|
||||
const defaultAdapter = getAdapter(axios.defaults.adapter);
|
||||
|
||||
// mock responses to unauthenticated "anuraghazra" requests
|
||||
// mock responses to "anuraghazra" requests
|
||||
axios.defaults.adapter = async (config) => {
|
||||
if (isAuthenticated) {
|
||||
return defaultAdapter(config);
|
||||
}
|
||||
|
||||
const params = config.data ? JSON.parse(config.data) : {};
|
||||
|
||||
if (
|
||||
|
||||
@@ -9,12 +9,9 @@ import {
|
||||
|
||||
import Header from './Header';
|
||||
import LandingScreen from '../Landing';
|
||||
import { SignUpScreen } from '../Auth';
|
||||
import HomeScreen from '../Home';
|
||||
import SettingsScreen from '../Settings';
|
||||
import { NoMatchScreen } from '../Misc';
|
||||
import { getUserMetadata } from '../../api';
|
||||
import Footer from './Footer';
|
||||
import {
|
||||
useIsAuthenticated,
|
||||
useUserKey,
|
||||
@@ -48,16 +45,11 @@ function App() {
|
||||
<Header mode="trends" />
|
||||
<section className="bg-white text-gray-700 flex-grow">
|
||||
<Routes>
|
||||
{!isAuthenticated && (
|
||||
<Route path="/signup" element={<SignUpScreen />} />
|
||||
)}
|
||||
<Route path="/user/*" element={<HomeScreen />} />
|
||||
<Route path="/settings" element={<SettingsScreen />} />
|
||||
<Route exact path="/" element={<LandingScreen />} />
|
||||
<Route path="*" element={<NoMatchScreen />} />
|
||||
</Routes>
|
||||
</section>
|
||||
<Footer />
|
||||
</Router>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import React from 'react';
|
||||
import { FaGithub as GithubIcon } from 'react-icons/fa';
|
||||
|
||||
function Footer() {
|
||||
return (
|
||||
<footer className="body-font">
|
||||
<div className="bg-gray-100 border-t border-gray-300">
|
||||
<div className="container mx-auto py-4 px-5 flex justify-center">
|
||||
<a
|
||||
href="https://www.github.com/avgupta456/github-trends"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="rounded-sm shadow bg-gray-700 hover:bg-gray-800 text-gray-50 px-3 py-2 flex items-center"
|
||||
>
|
||||
Star on
|
||||
<GithubIcon className="ml-1.5 w-5 h-5" />
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
|
||||
export default Footer;
|
||||
@@ -5,13 +5,13 @@ import PropTypes from 'prop-types';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { GiHamburgerMenu as HamburgerIcon } from 'react-icons/gi';
|
||||
import { MdSettings as SettingsIcon } from 'react-icons/md';
|
||||
|
||||
import { logout as _logout } from '../../redux/actions/userActions';
|
||||
import { useIsAuthenticated } from '../../redux/selectors/userSelectors';
|
||||
import appIcon from '../../assets/appLogo64.png';
|
||||
import { classnames } from '../../utils';
|
||||
import { GITHUB_PUBLIC_AUTH_URL } from '../../constants';
|
||||
import { FaGithub as GithubIcon } from 'react-icons/fa';
|
||||
|
||||
const propTypes = {
|
||||
to: PropTypes.string.isRequired,
|
||||
@@ -80,35 +80,21 @@ const Header = ({ mode }) => {
|
||||
<span className="ml-2 text-xl">GitHub Trends</span>
|
||||
)}
|
||||
</Link>
|
||||
{/* Auth Pages: Sign Up, Log In, Log Out */}
|
||||
{/* Star on GitHub */}
|
||||
<div className="hidden md:flex ml-auto items-center text-base justify-center">
|
||||
{isAuthenticated ? (
|
||||
<>
|
||||
{mode === 'trends' && (
|
||||
<Link to="/settings" className="mr-3 px-1 py-1">
|
||||
<SettingsIcon className="h-6 w-6 text-gray-700" />
|
||||
</Link>
|
||||
)}
|
||||
<StandardLink to="/" onClick={logout}>
|
||||
Sign Out
|
||||
</StandardLink>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<a
|
||||
className="px-4 py-1 mr-3 rounded-sm bg-gray-200 hover:bg-gray-300 text-gray-700"
|
||||
href={GITHUB_PUBLIC_AUTH_URL}
|
||||
>
|
||||
Login
|
||||
</a>
|
||||
<Link
|
||||
to="/signup"
|
||||
className="px-4 py-1 mr-3 rounded-sm bg-blue-500 hover:bg-blue-700 hover:text-gray-300"
|
||||
>
|
||||
Sign Up
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
<a
|
||||
href="https://www.github.com/avgupta456/github-trends"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="rounded-sm shadow bg-gray-700 hover:bg-gray-800 text-gray-50 px-3 py-2 flex items-center"
|
||||
>
|
||||
Star on
|
||||
<GithubIcon className="ml-1.5 w-5 h-5" />
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
{/* Hamburger Menu */}
|
||||
<div className="md:hidden flex ml-auto items-center">
|
||||
|
||||
@@ -280,12 +280,13 @@ const HomeScreen = () => {
|
||||
<p>
|
||||
{privateAccess ? (
|
||||
<>
|
||||
You have granted access to both{' '}
|
||||
<b>public and private</b> repositories.
|
||||
You granted GitHub Trends access to both your{' '}
|
||||
<b>public and private</b> contributions.
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
You have granted access to <b>public</b> repositories.
|
||||
You granted GitHub Trends access to your <b>public</b>{' '}
|
||||
contributions.
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useDispatch } from 'react-redux';
|
||||
import { Button, Image } from '../../../components';
|
||||
import { classnames } from '../../../utils';
|
||||
import {
|
||||
CLIENT_ID,
|
||||
GITHUB_PRIVATE_AUTH_URL,
|
||||
GITHUB_PUBLIC_AUTH_URL,
|
||||
HOST,
|
||||
@@ -16,10 +17,13 @@ import { logout as _logout } from '../../../redux/actions/userActions';
|
||||
import {
|
||||
useIsAuthenticated,
|
||||
usePrivateAccess,
|
||||
useUserId,
|
||||
useUserKey,
|
||||
} from '../../../redux/selectors/userSelectors';
|
||||
import { deleteAccount } from '../../../api';
|
||||
|
||||
const LoginStage = ({ setCurrItem }) => {
|
||||
const userId = useUserId();
|
||||
const userKey = useUserKey();
|
||||
const privateAccess = usePrivateAccess();
|
||||
const isAuthenticated = useIsAuthenticated();
|
||||
@@ -28,6 +32,13 @@ const LoginStage = ({ setCurrItem }) => {
|
||||
const logout = () => {
|
||||
dispatch(_logout());
|
||||
};
|
||||
const deleteAccountHandler = async (myUserId, myUserKey) => {
|
||||
const success = await deleteAccount(myUserId, myUserKey);
|
||||
if (success) {
|
||||
logout();
|
||||
window.location = `https://github.com/settings/connections/applications/${CLIENT_ID}`;
|
||||
}
|
||||
};
|
||||
|
||||
// Card data
|
||||
const cards = [
|
||||
@@ -81,7 +92,7 @@ const LoginStage = ({ setCurrItem }) => {
|
||||
</a>
|
||||
<p className="text-sm text-gray-600 flex-1">
|
||||
Switch to public access if you prefer not to share private
|
||||
repository data.
|
||||
contributions.
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
@@ -95,8 +106,8 @@ const LoginStage = ({ setCurrItem }) => {
|
||||
</Button>
|
||||
</a>
|
||||
<p className="text-sm text-gray-600 flex-1">
|
||||
Upgrade to include contributions from your private
|
||||
repositories for more complete stats.
|
||||
Upgrade to include contributions in private repositories
|
||||
for more complete and accurate stats.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
@@ -111,7 +122,21 @@ const LoginStage = ({ setCurrItem }) => {
|
||||
<span className="xl:text-lg">Log Out</span>
|
||||
</Button>
|
||||
<p className="text-sm text-gray-600 flex-1">
|
||||
Log out from your GitHub account.
|
||||
Log out from GitHub Trends.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Delete Account Button */}
|
||||
<div className="mt-6 flex items-center gap-4">
|
||||
<Button
|
||||
className="h-12 flex justify-center items-center w-[320px] text-black border border-black bg-white hover:bg-gray-100"
|
||||
onClick={deleteAccountHandler(userId, userKey)}
|
||||
>
|
||||
<span className="xl:text-lg">Delete Account</span>
|
||||
</Button>
|
||||
<p className="text-sm text-gray-600 flex-1">
|
||||
This will delete your GitHub Trends account and then redirect
|
||||
you to a GitHub screen where you can revoke your access token.
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
@@ -128,7 +153,8 @@ const LoginStage = ({ setCurrItem }) => {
|
||||
</Button>
|
||||
</a>
|
||||
<p className="text-sm text-gray-600 flex-1">
|
||||
Generate stats based on your public repositories.
|
||||
Generate stats based on your contributions in public
|
||||
repositories.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -142,7 +168,7 @@ const LoginStage = ({ setCurrItem }) => {
|
||||
</Button>
|
||||
</a>
|
||||
<p className="text-sm text-gray-600 flex-1">
|
||||
Includes contributions in your private repositories for more
|
||||
Includes contributions from private repositories for more
|
||||
complete and accurate stats.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -1,264 +0,0 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { Button } from '../../components';
|
||||
import { logout as _logout } from '../../redux/actions/userActions';
|
||||
import {
|
||||
useUserId,
|
||||
useUserKey,
|
||||
useIsAuthenticated,
|
||||
usePrivateAccess,
|
||||
} from '../../redux/selectors/userSelectors';
|
||||
import { deleteAccount } from '../../api';
|
||||
import { classnames } from '../../utils';
|
||||
import { CLIENT_ID, GITHUB_PRIVATE_AUTH_URL, HOST } from '../../constants';
|
||||
|
||||
const SectionButton = ({ name, implemented, isSelected, setSelected }) => {
|
||||
return (
|
||||
<div
|
||||
className={classnames(
|
||||
'w-full py-3 px-3 hover:bg-gray-100 text-gray-700 text-lg cursor-pointer',
|
||||
isSelected &&
|
||||
'pl-2 bg-gray-100 cursor-default border-l-4 border-blue-500',
|
||||
!implemented && 'opacity-50 cursor-not-allowed',
|
||||
)}
|
||||
onClick={() => setSelected('accountTier')}
|
||||
>
|
||||
{name}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
SectionButton.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
implemented: PropTypes.bool,
|
||||
isSelected: PropTypes.bool.isRequired,
|
||||
setSelected: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
SectionButton.defaultProps = {
|
||||
implemented: true,
|
||||
};
|
||||
|
||||
function useOutsideAlerter(ref, action) {
|
||||
useEffect(() => {
|
||||
/**
|
||||
* Alert if clicked on outside of element
|
||||
*/
|
||||
function handleClickOutside(event) {
|
||||
if (ref.current && !ref.current.contains(event.target)) {
|
||||
action();
|
||||
}
|
||||
}
|
||||
|
||||
// Bind the event listener
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
return () => {
|
||||
// Unbind the event listener on clean up
|
||||
document.removeEventListener('mousedown', handleClickOutside);
|
||||
};
|
||||
}, [ref]);
|
||||
}
|
||||
|
||||
const SettingsScreen = () => {
|
||||
const [selected, setSelected] = useState('accountTier');
|
||||
const [deleteModal, setDeleteModal] = useState(false);
|
||||
|
||||
const openDeleteModal = () => {
|
||||
setDeleteModal(true);
|
||||
};
|
||||
|
||||
const closeDeleteModal = () => {
|
||||
setDeleteModal(false);
|
||||
};
|
||||
|
||||
const wrapperRef = useRef(null);
|
||||
useOutsideAlerter(wrapperRef, closeDeleteModal);
|
||||
|
||||
const userId = useUserId();
|
||||
const userKey = useUserKey();
|
||||
const isAuthenticated = useIsAuthenticated();
|
||||
const privateAccess = usePrivateAccess();
|
||||
const accountTier = privateAccess ? 'Private Workflow' : 'Public Workflow';
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const logout = () => dispatch(_logout());
|
||||
|
||||
console.log(isAuthenticated, userId, userKey, privateAccess, accountTier);
|
||||
|
||||
if (!isAuthenticated) {
|
||||
return (
|
||||
<div className="h-full py-8 flex justify-center items-center">
|
||||
<div className="text-center">
|
||||
<h1 className="text-3xl font-bold">
|
||||
Please sign in to access this page
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-full w-full">
|
||||
<div className={classnames('h-full flex', deleteModal && 'opacity-25')}>
|
||||
<div className="h-full w-1/3 md:w-80 p-4 flex flex-col border-r">
|
||||
<p className="p-2 text-gray-700 text-lg font-bold">
|
||||
Account Settings
|
||||
</p>
|
||||
<hr />
|
||||
<SectionButton
|
||||
name="Account Tier"
|
||||
isSelected={selected === 'accountTier'}
|
||||
setSelected={() => setSelected('accountTier')}
|
||||
/>
|
||||
<SectionButton
|
||||
name="Personalization"
|
||||
implemented={false}
|
||||
isSelected={selected === 'personalization'}
|
||||
setSelected={() => setSelected('personalization')}
|
||||
/>
|
||||
<SectionButton
|
||||
name="Delete Account"
|
||||
isSelected={selected === 'deleteAccount'}
|
||||
setSelected={() => setSelected('deleteAccount')}
|
||||
/>
|
||||
</div>
|
||||
<div className="h-full w-full">
|
||||
<div className="container mx-auto p-8">
|
||||
{selected === 'accountTier' && (
|
||||
<div>
|
||||
<p className="mb-1 text-2xl text-gray-700">Account Tier</p>
|
||||
<hr />
|
||||
<br />
|
||||
<p className="flex text-lg">
|
||||
Current Tier:
|
||||
<strong className="ml-1">{accountTier}</strong>
|
||||
</p>
|
||||
<br />
|
||||
{privateAccess ? (
|
||||
<p>
|
||||
You have given GitHub Trends (read and write) access to all
|
||||
public and private code contributions. We use your GitHub
|
||||
API access token to make requests on your behalf. All of our
|
||||
code is open-source and visible on our
|
||||
<a
|
||||
className="ml-1 text-blue-500 underline"
|
||||
href="https://github.com/avgupta456/github-trends"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
GitHub repository
|
||||
</a>
|
||||
</p>
|
||||
) : (
|
||||
<p>
|
||||
You have given GitHub Trends read access to your public
|
||||
repositories. Upgrading to the Private Workflow will allow
|
||||
us to better represent your code contributions. We use your
|
||||
GitHub API access token to make requests on your behalf. All
|
||||
of our code is open-source and visible on our
|
||||
<a
|
||||
className="ml-1 text-blue-500 underline"
|
||||
href="https://github.com/avgupta456/github-trends"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
GitHub repository
|
||||
</a>
|
||||
</p>
|
||||
)}
|
||||
<br />
|
||||
{privateAccess ? (
|
||||
<a href={`https://${HOST}/api/downgrade?user_key=${userKey}`}>
|
||||
<Button className="bg-blue-500 text-white rounded-sm">
|
||||
Downgrade to Public Access
|
||||
</Button>
|
||||
</a>
|
||||
) : (
|
||||
<a href={GITHUB_PRIVATE_AUTH_URL}>
|
||||
<Button className="bg-blue-500 text-white rounded-sm">
|
||||
Upgrade to Private Access
|
||||
</Button>
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{selected === 'personalization' && (
|
||||
<div>
|
||||
<p className="mb-1 text-2xl text-gray-700">Personalization</p>
|
||||
<hr />
|
||||
<br />
|
||||
<p>Coming soon!</p>
|
||||
</div>
|
||||
)}
|
||||
{selected === 'deleteAccount' && (
|
||||
<div>
|
||||
<p className="mb-1 text-2xl text-gray-700">Delete Account</p>
|
||||
<hr />
|
||||
<br />
|
||||
<p>
|
||||
Deleting your account is permanent and cannot be undone. If
|
||||
you are sure you want to delete your account, click the button
|
||||
below to remove your statistics from GitHub Trends. This will
|
||||
redirect you to a GitHub screen where you can revoke your
|
||||
access token.
|
||||
</p>
|
||||
<br />
|
||||
<Button
|
||||
className="bg-gray-200 rounded-sm text-red-600 border-2"
|
||||
onClick={openDeleteModal}
|
||||
>
|
||||
Permanently Delete Account
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{deleteModal && (
|
||||
<div>
|
||||
<div className="fixed left-0 top-0 w-full h-full">
|
||||
<div className="w-full h-full flex justify-center items-center">
|
||||
<div
|
||||
className="w-96 p-4 bg-white rounded-sm border-2 border-gray-200"
|
||||
ref={wrapperRef}
|
||||
>
|
||||
<p className="mb-1 text-2xl text-gray-700">Delete Account</p>
|
||||
<hr />
|
||||
<br />
|
||||
<p>
|
||||
Are you sure you want to continue? This action cannot be
|
||||
undone.
|
||||
</p>
|
||||
<br />
|
||||
<div className="flex flex-wrap">
|
||||
<Button
|
||||
className="bg-blue-500 text-white rounded-sm"
|
||||
onClick={() => setDeleteModal(false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
className="bg-gray-200 ml-auto rounded-sm text-red-600 border-2"
|
||||
onClick={async () => {
|
||||
const success = await deleteAccount(userId, userKey);
|
||||
if (success) {
|
||||
logout();
|
||||
window.location = `https://github.com/settings/connections/applications/${CLIENT_ID}`;
|
||||
}
|
||||
}}
|
||||
>
|
||||
Delete Account
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsScreen;
|
||||
@@ -1,3 +0,0 @@
|
||||
import SettingsScreen from './Settings';
|
||||
|
||||
export default SettingsScreen;
|
||||
Reference in New Issue
Block a user