Skip to content

Commit e47eca0

Browse files
committed
feat: firstVisit popup
Signed-off-by: Karthik Ayangar <[email protected]>
1 parent bd5531f commit e47eca0

File tree

40 files changed

+958
-556
lines changed

40 files changed

+958
-556
lines changed

src/app/api/githubData.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ export interface OrgRank {
2121
contributors: Contributors;
2222
}
2323

24-
export interface ProjectStats{
25-
contributors: Contributors
24+
export interface ProjectStats {
25+
contributors: Contributors;
2626
}
2727

2828
// Contributors==project issues commits pull
@@ -71,7 +71,7 @@ export const getProjectGithubData = async (
7171
orgName: string,
7272
projectName: string,
7373
monthly: boolean
74-
) : Promise<AxiosResponse<ProjectStats>>=> {
74+
): Promise<AxiosResponse<ProjectStats>> => {
7575
const url =
7676
BACKEND_URL +
7777
'/api/protected/github/' +

src/app/api/organization.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ export const changeOrgMembersStatus = async (
124124
orgName: string,
125125
orgMemberStatus: { [key: string]: string }
126126
) => {
127-
const url = BACKEND_URL + '/api/protected/org/changeMembersStatus/'+orgName;
127+
const url = BACKEND_URL + '/api/protected/org/changeMembersStatus/' + orgName;
128128
const respnse = await axios.put(
129129
url,
130130
{

src/app/api/project.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export interface GetProject {
1111
id: number;
1212
name: string;
1313
description: string;
14-
link: string
14+
link: string;
1515
}
1616

1717
export interface Member {

src/app/components/buttonBar/index.tsx

+24-15
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,36 @@ import TimeRangeSwitch from 'app/components/timeRangeSwitch';
44
import './index.scss';
55
import { GetProject } from 'app/api/project';
66
import { useNavigate } from 'react-router-dom';
7-
interface Props{
8-
weekly: boolean,
9-
setWeekly: (week:boolean)=>void
10-
project: GetProject | null
11-
workspaceName: string | undefined
12-
7+
interface Props {
8+
weekly: boolean;
9+
setWeekly: (week: boolean) => void;
10+
project: GetProject | null;
11+
workspaceName: string | undefined;
1312
}
14-
const ButtonBar:React.FC<Props> = ({weekly, setWeekly, project, workspaceName}) => {
15-
const navigate= useNavigate()
13+
const ButtonBar: React.FC<Props> = ({
14+
weekly,
15+
setWeekly,
16+
project,
17+
workspaceName,
18+
}) => {
19+
const navigate = useNavigate();
1620
return (
1721
<div className='project-upper-cont'>
1822
<div className='button-bar'>
19-
<button className='back-btn' onClick={()=>navigate(`/workspace/${workspaceName}`)} >&larr; Back</button>
23+
<button
24+
className='back-btn'
25+
onClick={() => navigate(`/workspace/${workspaceName}`)}
26+
>
27+
&larr; Back
28+
</button>
2029
<TimeRangeSwitch weekly={weekly} setWeekly={setWeekly} />
2130
</div>
22-
{ project&&<>
23-
<h1>{project.name}</h1>
24-
<p>
25-
{project.description}
26-
</p>
27-
</>}
31+
{project && (
32+
<>
33+
<h1>{project.name}</h1>
34+
<p>{project.description}</p>
35+
</>
36+
)}
2837
</div>
2938
);
3039
};
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
.modal-footer {
2+
height: 100%;
3+
display: flex;
4+
flex-direction: column;
5+
align-items: center;
6+
justify-content: center;
7+
font-size: 0.5rem;
8+
font-weight: 600;
9+
a {
10+
text-decoration: none;
11+
}
12+
}
13+
14+
.firstvisit-btn {
15+
background-color: #402aa4;
16+
border: none;
17+
color: white;
18+
padding: 0.5rem 1rem;
19+
border-radius: 5rem;
20+
border: 1px solid #402aa4;
21+
font-size: 1rem;
22+
}
23+
24+
.firstvisit-btn:hover {
25+
background-color: whitesmoke;
26+
border: none;
27+
color: #402aa4;
28+
padding: 0.5rem 1rem;
29+
border-radius: 5rem;
30+
border: 1px solid #402aa4;
31+
font-size: 1rem;
32+
}
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { useEffect, useState } from 'react';
2+
import Popup from '../popup';
3+
import './index.scss';
4+
5+
export default function FirstVisit() {
6+
const [show, setShow] = useState(false);
7+
useEffect(() => {
8+
const visit = localStorage.getItem('visit');
9+
if (visit !== 'true') {
10+
localStorage.setItem('visit', 'true');
11+
12+
setShow(true);
13+
}
14+
}, []);
15+
16+
return (
17+
<>
18+
{show && (
19+
<Popup
20+
title={'Welcome to Activity Leaderboard!'}
21+
onClose={() => setShow(false)}
22+
footer={
23+
<div className='modal-footer'>
24+
<h1>
25+
Google Summer of Code is a global, online program focused on
26+
bringing new contributors into open source software development.
27+
</h1>
28+
<a
29+
href='https://summerofcode.withgoogle.com/'
30+
target='blank'
31+
className='firstvisit-btn'
32+
>
33+
Visit GSOC
34+
</a>
35+
</div>
36+
}
37+
popup_zindex={{ overlay: 3000, modal: 4000 }}
38+
/>
39+
)}
40+
</>
41+
);
42+
}

src/app/components/popup/index.scss

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
.popup-overlay {
2+
position: fixed;
3+
top: 0;
4+
left: 0;
5+
right: 0;
6+
bottom: 0;
7+
background-color: rgba(0, 0, 0, 0.5);
8+
}
9+
10+
.popup-modal {
11+
position: fixed;
12+
top: 50%;
13+
left: 50%;
14+
transform: translate(-50%, -50%);
15+
background-color: white;
16+
border-radius: 10px;
17+
max-width: 500px;
18+
width: 100%;
19+
max-height: 67vh;
20+
overflow-y: auto;
21+
color: black;
22+
}
23+
24+
.popup-title {
25+
display: flex;
26+
justify-content: space-between;
27+
align-items: center;
28+
border-bottom: 1px solid black;
29+
padding: 0.5em 1em 0.5em 1em;
30+
background-color: #402aa4;
31+
color: white;
32+
}
33+
34+
.popup-body {
35+
text-align: center;
36+
padding: 0.5em 1em 0.5em 1em;
37+
}
38+
39+
.popup-footer {
40+
display: flex;
41+
flex-direction: row-reverse;
42+
margin: 0.6em;
43+
}
44+
45+
.close-btn {
46+
background: none;
47+
border: none;
48+
padding: 0.1em;
49+
color: white;
50+
}
51+
52+
.modal-btn {
53+
width: 30px;
54+
height: 30px;
55+
background-color: transparent;
56+
border: none;
57+
color: white;
58+
border: 1px solid white;
59+
border-radius: 50%;
60+
}
61+
62+
.modal-btn:hover {
63+
width: 30px;
64+
height: 30px;
65+
background-color: white;
66+
border: none;
67+
color: #402aa4;
68+
border: 1px solid #402aa4;
69+
border-radius: 50%;
70+
}

src/app/components/popup/index.tsx

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import './index.scss';
2+
import ReactPortal from '../reactPortal';
3+
import { ReactNode } from 'react';
4+
type _POPUP_PROPS = {
5+
onClose?: () => void;
6+
onSubmit?: () => void;
7+
title: string | ReactNode;
8+
type?: 'success' | 'error';
9+
submit?: string;
10+
content?: string | ReactNode;
11+
footer?: ReactNode;
12+
popup_zindex?: {
13+
overlay: number;
14+
modal: number;
15+
};
16+
};
17+
18+
const Popup = ({
19+
title,
20+
content,
21+
type,
22+
onClose,
23+
onSubmit,
24+
submit,
25+
footer,
26+
popup_zindex,
27+
}: _POPUP_PROPS) => {
28+
return (
29+
<ReactPortal>
30+
<div
31+
className='popup-overlay'
32+
style={{ zIndex: popup_zindex?.overlay ?? 1000 }}
33+
/>
34+
<div className='popup-modal' style={{ zIndex: popup_zindex?.modal ?? 2000 }}>
35+
<div className='popup-title'>
36+
{typeof title === 'string' ? (
37+
<span>{title}</span>
38+
) : (
39+
<div>{title}</div>
40+
)}
41+
{onClose && (
42+
<button type='button' className='modal-btn' onClick={onClose}>
43+
<svg
44+
className='h-5 w-5'
45+
fill='none'
46+
viewBox='0 0 24 24'
47+
stroke='currentColor'
48+
aria-hidden='true'
49+
>
50+
<path
51+
strokeLinecap='round'
52+
strokeLinejoin='round'
53+
strokeWidth='3'
54+
d='M6 18L18 6M6 6l12 12'
55+
/>
56+
</svg>
57+
</button>
58+
)}
59+
</div>
60+
{content && <div className='popup-body'>{content}</div>}
61+
<div className='popup-footer'>
62+
{onSubmit && (
63+
<button
64+
className='modal-btn'
65+
style={
66+
type && {
67+
backgroundColor: type === 'success' ? 'green' : 'red',
68+
}
69+
}
70+
onClick={onSubmit}
71+
>
72+
{submit ?? 'Okay'}
73+
</button>
74+
)}
75+
<div>{footer}</div>
76+
</div>
77+
</div>
78+
</ReactPortal>
79+
);
80+
};
81+
82+
export default Popup;
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { ReactNode, useEffect, useState } from 'react';
2+
import { createPortal } from 'react-dom';
3+
4+
/**
5+
* Ensures that document.body is available
6+
*/
7+
export default function ReactPortal({ children }: { children: ReactNode }) {
8+
const [mounted, setMounted] = useState(false);
9+
useEffect(() => {
10+
setMounted(true);
11+
}, []);
12+
13+
return <>{mounted && createPortal(<>{children}</>, document.body)}</>;
14+
}

src/app/components/timeRangeSwitch/index.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ interface Props {
1313
const TimeRangeSwitch: React.FC<Props> = ({ weekly, setWeekly }) => {
1414
// const dispatch = useDispatch();
1515
// const isWeekly = useSelector((state: timeRangeModel) => state.isWeekly.value);
16-
useEffect(()=>{
17-
console.log(weekly)
18-
},[weekly, setWeekly])
16+
useEffect(() => {
17+
console.log(weekly);
18+
}, [weekly, setWeekly]);
1919
return (
2020
<div className='timerange-cont'>
2121
<button
2222
onClick={() => setWeekly(true)}
23-
className={weekly ? 'active' :''}
23+
className={weekly ? 'active' : ''}
2424
// className={'active'}
2525
>
2626
Weekly{' '}

0 commit comments

Comments
 (0)