Skip to content

Commit 2a0933a

Browse files
committed
feat: get certification
1 parent 9a79208 commit 2a0933a

File tree

9 files changed

+165
-5
lines changed

9 files changed

+165
-5
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.certificateButton {
2+
font-size: small;
3+
margin-right: 32px;
4+
display: flex;
5+
align-items: center;
6+
justify-content: center;
7+
gap: 8px;
8+
padding: 8px 10px;
9+
border-radius: 8px;
10+
cursor: pointer;
11+
font-weight: bold;
12+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import { isTheTourCompleted } from "@/lib/client-functions";
2+
import React, { useEffect, useState } from "react";
3+
import styles from "./CertificateButton.module.css";
4+
import { LockIcon } from "@chakra-ui/icons";
5+
import {
6+
Box,
7+
Button,
8+
Flex,
9+
Input,
10+
Tooltip,
11+
useDisclosure,
12+
useToast,
13+
} from "@chakra-ui/react";
14+
import {
15+
Modal,
16+
ModalOverlay,
17+
ModalContent,
18+
ModalHeader,
19+
ModalFooter,
20+
ModalBody,
21+
ModalCloseButton,
22+
} from "@chakra-ui/react";
23+
import { googleSheetAPIRoute } from "@/lib/contentVariables";
24+
const submitCertificateReq = async (name: string, email: string) => {
25+
await fetch(googleSheetAPIRoute, {
26+
method: "POST",
27+
body: JSON.stringify({
28+
name,
29+
email,
30+
certificateReq: true,
31+
}),
32+
});
33+
};
34+
35+
export default function CertificateButton() {
36+
const { isOpen, onOpen, onClose } = useDisclosure();
37+
const [isTheTourCompletedState, setIsTheTourCompletedState] =
38+
useState(isTheTourCompleted());
39+
useEffect(() => {
40+
setIsTheTourCompletedState(isTheTourCompleted());
41+
}, [isTheTourCompleted()]);
42+
const [name, setName] = useState("");
43+
const [email, setEmail] = useState("");
44+
const toast = useToast();
45+
46+
return (
47+
<>
48+
<Tooltip
49+
label={
50+
isTheTourCompletedState
51+
? ""
52+
: "Complete the tour to get your certificate"
53+
}
54+
aria-label="A tooltip"
55+
>
56+
<Button
57+
size={"sm"}
58+
variant={"default"}
59+
className={styles.certificateButton}
60+
onClick={isTheTourCompletedState ? onOpen : () => {}}
61+
>
62+
{isTheTourCompletedState ? "" : <LockIcon />} Get Your Certificate
63+
</Button>
64+
</Tooltip>
65+
<Modal isOpen={isOpen} onClose={onClose}>
66+
<ModalOverlay />
67+
<ModalContent>
68+
<ModalHeader>Get Your Certificate</ModalHeader>
69+
<ModalCloseButton />
70+
<ModalBody>
71+
<Box mb={4}>We will email you your certificate</Box>
72+
<Flex direction="column" gap={4}>
73+
<Input
74+
placeholder="Name"
75+
onChange={(e) => setName(e.target.value)}
76+
value={name}
77+
/>
78+
<Input
79+
placeholder="Email"
80+
onChange={(e) => setEmail(e.target.value)}
81+
value={email}
82+
/>
83+
</Flex>
84+
</ModalBody>
85+
86+
<ModalFooter>
87+
<Button variant="ghost" onClick={onClose}>
88+
Close
89+
</Button>
90+
<Button
91+
variant="default"
92+
mr={3}
93+
onClick={() => {
94+
submitCertificateReq(name, email);
95+
onClose();
96+
toast({
97+
title: "Certificate Requested",
98+
description: "We will email you your certificate",
99+
status: "success",
100+
duration: 9000,
101+
isClosable: true,
102+
});
103+
}}
104+
>
105+
Submit
106+
</Button>
107+
</ModalFooter>
108+
</ModalContent>
109+
</Modal>
110+
</>
111+
);
112+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {default as default} from './CertificateButton';

app/components/Feedback/Feedback.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,13 @@ import Dislike from "@/app/styles/icons/BiDislike";
66
import { Flex } from "@chakra-ui/react";
77
import { usePathname } from "next/navigation";
88
import styles from "./Feedback.module.css";
9+
import { googleSheetAPIRoute } from "@/lib/contentVariables";
910

1011
export default function Feedback() {
11-
const APIRoute =
12-
"https://script.google.com/macros/s/AKfycbz0f87eDgEghSelILb3RSdHe-Rr7HKAdMxx8tvTq4fNAfJt0fZ7t-G-p1BrVEQM2Mws/exec";
1312
const [isSubmitted, setIsSubmitted] = useState(false);
1413
const pathname = usePathname();
1514
const submitFeedback = async (feedback: string) => {
16-
await fetch(APIRoute, {
15+
await fetch(googleSheetAPIRoute, {
1716
method: "POST",
1817
body: JSON.stringify({
1918
feedback: feedback,

app/components/OutlineDrawer/OutlineDrawer.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ import {
66
DrawerHeader,
77
DrawerCloseButton,
88
DrawerBody,
9+
Button,
910
} from "@chakra-ui/react";
1011
import styles from "./OutlineDrawer.module.css";
1112
import { ContentOutline } from "@/lib/types";
1213
import ChapterItem from "../ChapterItem";
1314
import { isChapterCompleted } from "@/lib/client-functions";
15+
import Link from "next/link";
16+
import CertificateButton from "../CertificateButton/CertificateButton";
1417

1518
export default function OutlineDrawer({
1619
isOpen,
@@ -39,7 +42,11 @@ export default function OutlineDrawer({
3942
<DrawerOverlay />
4043
<DrawerContent>
4144
<DrawerCloseButton />
42-
<DrawerHeader>Outline</DrawerHeader>
45+
<DrawerHeader display={"flex"} justifyContent={"space-between"}>
46+
47+
Outline
48+
<CertificateButton />
49+
</DrawerHeader>
4350

4451
<DrawerBody>
4552
<nav>

app/styles/theme.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,16 @@ const Popover = {
136136
},
137137
};
138138

139+
const Modal = {
140+
baseStyle: {
141+
dialog: {
142+
bg: "hsl(var(--background))",
143+
color: "hsl(var(--text))",
144+
borderRadius: "16px"
145+
}
146+
}
147+
}
148+
139149
export const theme = extendTheme({
140150
config: {
141151
initialColorMode: "light",
@@ -149,6 +159,6 @@ export const theme = extendTheme({
149159
},
150160
},
151161
},
152-
components: { Button, Menu, Switch, Drawer, Tooltip, Popover },
162+
components: { Button, Menu, Switch, Drawer, Tooltip, Popover, Modal },
153163
fonts: {},
154164
});

lib/client-functions.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { OutputReducerAction } from "./reducers";
77
import { CodeFile, TestCaseResult } from "./types";
88
import { hyperjumpCheckAnnotations, hyperjumpValidate } from "./validators";
99
import { sendGAEvent } from "@next/third-parties/google";
10+
import { contentManager } from "./contentManager";
1011

1112
export async function validateCode(
1213
codeString: string,
@@ -136,6 +137,13 @@ export function isChapterCompleted(chapterIndex: number, totalSteps: number) {
136137
return true;
137138
}
138139

140+
141+
export function isTheTourCompleted() {
142+
const totalStepsForAllChapters = contentManager.getNumberOfStepsFromAllChapters();
143+
const completedSteps = Object.keys(JSON.parse(localStorage.getItem("progress")!)).length;
144+
return totalStepsForAllChapters === completedSteps;
145+
}
146+
139147
export function hasNestedProperty(obj: any, path: string) {
140148
console.log(obj, path);
141149
const keys = path.split(".");

lib/contentManager.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,16 @@ export default class ContentManager {
101101
public getTotalSteps(chapterIndex: number) {
102102
return this.getOutline()[chapterIndex].steps.length;
103103
}
104+
105+
public getNumberOfStepsFromAllChapters() {
106+
let totalSteps = 0;
107+
let totalChapters = this.getTotalChapters();
108+
for (let i = 0; i < totalChapters; i++) {
109+
totalSteps += this.getTotalSteps(i);
110+
}
111+
return totalSteps;
112+
}
113+
104114
public getInstructionsFilePath(urlPath: string) {
105115
return `${contentFolderName}/${urlPath}/${instructionsFileName}`;
106116
}

lib/contentVariables.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ export const contentFolderPath: string = "./content";
44
export const contentFolderName: string = contentFolderPath.replace("./", "");
55
export const indexFileName = "index.mdx";
66
export const instructionsFileName = "instructions.mdx";
7+
export const googleSheetAPIRoute = "https://script.google.com/macros/s/AKfycbxjH778iyBlZ8_oY946fTLW6H0HcfByaNk0collEgIwERwnpeErkaYEuKjWxAQ2qg/exec"

0 commit comments

Comments
 (0)