diff --git a/dist/api/index.php b/dist/api/index.php
index fcd86b4..07fce1d 100644
--- a/dist/api/index.php
+++ b/dist/api/index.php
@@ -59,6 +59,139 @@ $app->get("/timelineData/{timeline}", function (Request $request, Response $resp
return $response->withStatus(404);
});
+$app->patch("/timelineData/{timeline}/{id}", function (Request $request, Response $response, array $args)
+{
+ global $timelineData;
+ $data = $request->getParsedBody();
+ if ($args["timeline"] == "edu" && $args["id"] != "undefined")
+ {
+ if (empty($data["dateFrom"]) || empty($data["dateTo"]) || empty($data["grade"]) || empty($data["course"]))
+ {
+ // uh oh sent some empty data
+ $response->getBody()->write(json_encode(array("error" => "Only some of the data was sent")));
+ return $response->withStatus(400);
+ }
+
+
+ if (!$timelineData->updateEduData($data["dateFrom"], $data["dateTo"], $data["grade"], $data["course"], $args["id"]))
+ {
+ // uh oh something went wrong
+ $response->getBody()->write(json_encode(array("error" => "Something went wrong")));
+ return $response->withStatus(500);
+ }
+
+ return $response->withStatus(200);
+ }
+
+ if ($args["timeline"] == "work" && $args["id"] != null)
+ {
+ if (empty($data["dateFrom"]) || empty($data["dateTo"]) || empty($data["companyName"]) || empty($data["area"]) || empty($data["title"]))
+ {
+ // uh oh sent some empty data
+ $response->getBody()->write(json_encode(array("error" => "Only some of the data was sent")));
+ return $response->withStatus(400);
+ }
+
+ if (!$timelineData->updateWorkData($data["dateFrom"], $data["dateTo"], $data["companyName"], $data["area"], $data["title"], $args["id"]))
+ {
+ // uh oh something went wrong
+ $response->getBody()->write(json_encode(array("error" => "Something went wrong")));
+ return $response->withStatus(500);
+ }
+
+ return $response->withStatus(200);
+ }
+
+ $response->getBody()->write(json_encode(array("error" => "The correct data was not sent")));
+ return $response->withStatus(400);
+});
+
+$app->delete("/timelineData/{timeline}/{id}", function (Request $request, Response $response, array $args)
+{
+ global $timelineData;
+ if ($args["timeline"] == "edu" && $args["id"] != null)
+ {
+ if (!$timelineData->deleteEduData($args["id"]))
+ {
+ // uh oh something went wrong
+ $response->getBody()->write(json_encode(array("error" => "Something went wrong")));
+ return $response->withStatus(500);
+ }
+
+ return $response->withStatus(200);
+ }
+
+ if ($args["timeline"] == "work" && $args["id"] != null)
+ {
+ if (!$timelineData->deleteWorkData($args["id"]))
+ {
+ // uh oh something went wrong
+ $response->getBody()->write(json_encode(array("error" => "Something went wrong")));
+ return $response->withStatus(500);
+ }
+
+ return $response->withStatus(200);
+ }
+
+ $response->getBody()->write(json_encode(array("error" => "The correct data was not sent")));
+ return $response->withStatus(400);
+});
+
+$app->post("/timelineData/{timeline}", function (Request $request, Response $response, array $args)
+{
+ global $timelineData;
+ $data = $request->getParsedBody();
+ if ($args["timeline"] == "edu")
+ {
+ if (empty($data["dateFrom"]) || empty($data["dateTo"]) || empty($data["grade"]) || empty($data["course"]))
+ {
+ // uh oh sent some empty data
+ $response->getBody()->write(json_encode(array("error" => "Only some of the data was sent")));
+ return $response->withStatus(400);
+ }
+
+ $insertedID = $timelineData->addEduData($data["dateFrom"], $data["dateTo"], $data["grade"], $data["course"]);
+ if (!is_int($insertedID))
+ {
+ // uh oh something went wrong
+ $response->getBody()->write(json_encode(array("error" => "Something went wrong")));
+ return $response->withStatus(500);
+ }
+
+ $response->getBody()->write(json_encode(array("ID" => $insertedID)));
+ return $response->withStatus(200);
+ }
+
+ if ($args["timeline"] == "work")
+ {
+ if (empty($data["dateFrom"]) || empty($data["companyName"]) || empty($data["area"]) || empty($data["title"]))
+ {
+ // uh oh sent some empty data
+ $response->getBody()->write(json_encode(array("error" => "Only some of the data was sent")));
+ return $response->withStatus(400);
+ }
+
+ if (empty($data["dateTo"]))
+ {
+ $data["dateTo"] = "";
+ }
+
+ $insertedID = $timelineData->addWorkData($data["dateFrom"], $data["dateTo"], $data["companyName"], $data["area"], $data["title"]);
+ if (!is_int($insertedID))
+ {
+ // uh oh something went wrong
+ $response->getBody()->write(json_encode(array("error" => "Something went wrong")));
+ return $response->withStatus(500);
+ }
+
+ $response->getBody()->write(json_encode(array("ID" => $insertedID)));
+ return $response->withStatus(200);
+ }
+
+ $response->getBody()->write(json_encode(array("error" => "The correct data was not sent")));
+ return $response->withStatus(400);
+});
+
$app->get("/projectData", function (Request $request, Response $response)
{
global $projectData;
@@ -373,39 +506,7 @@ $app->post("/user/changePassword", function (Request $request, Response $respons
return $response->withStatus(500);
});
-$app->patch("/timelineData/{timeline}/{id}", function (Request $request, Response $response, array $args)
-{
- global $timelineData;
- if ($args["timeline"] == "edu" && $args["id"] != "undefined")
- {
- $data = $request->getParsedBody();
- if (empty($data["dateFrom"]) || empty($data["dateTo"]) || empty($data["grade"]) || empty($data["course"]))
- {
- // uh oh sent some empty data
- $response->getBody()->write(json_encode(array("error" => "Only some of the data was sent")));
- return $response->withStatus(400);
- }
-
-
- if (!$timelineData->updateEduData($data["dateFrom"], $data["dateTo"], $data["grade"], $data["course"], $args["id"]))
- {
- // uh oh something went wrong
- $response->getBody()->write(json_encode(array("error" => "Something went wrong")));
- return $response->withStatus(500);
- }
-
- return $response->withStatus(200);
- }
-
- if ($args["timeline"] == "work" && $args["id"] != null)
- {
-
- return $response->withStatus(200);
- }
-
- $response->getBody()->write(json_encode(array("error" => "The correct data was not sent")));
- return $response->withStatus(400);
-});
+
diff --git a/dist/api/timelineData.php b/dist/api/timelineData.php
index 29f5cd5..fe62458 100644
--- a/dist/api/timelineData.php
+++ b/dist/api/timelineData.php
@@ -1,5 +1,7 @@
prepare("SELECT startPeriod, endPeriod, companyName, area, title FROM work ORDER BY work.startPeriod DESC;");
+ $stmt = $conn->prepare("SELECT ID, startPeriod, endPeriod, companyName, area, title FROM work ORDER BY work.startPeriod DESC;");
$stmt->execute();
// set the resulting array to associative
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
-
+
if ($result)
{
return $result;
@@ -71,4 +73,103 @@ class timelineData
return $stmt->execute();
}
+ /**
+ * Update work data
+ * @param string $dateFrom - Start date
+ * @param string $dateTo - End date
+ * @param string $companyName - Company name
+ * @param string $area - Area
+ * @param string $title - Title
+ * @param string $id - ID of the work data
+ * @return bool - True if successful, false if not
+ */
+ public function updateWorkData(string $dateFrom, string $dateTo, string $companyName, string $area, string $title, string $id): bool
+ {
+ $conn = dbConn();
+ $stmt = $conn->prepare("UPDATE work SET startPeriod = :dateFrom, endPeriod = :dateTo, companyName = :companyName, area = :area, title = :title WHERE ID = :id;");
+ $stmt->bindParam(":dateFrom", $dateFrom);
+ $stmt->bindParam(":dateTo", $dateTo);
+ $stmt->bindParam(":companyName", $companyName);
+ $stmt->bindParam(":area", $area);
+ $stmt->bindParam(":title", $title);
+ $stmt->bindParam(":id", $id);
+ return $stmt->execute();
+ }
+
+ /**
+ * Delete education data by ID
+ * @param int $id
+ * @return bool - True if successful, false if not
+ */
+ function deleteEduData(int $id): bool
+ {
+ $conn = dbConn();
+ $stmt = $conn->prepare("DELETE FROM edu WHERE ID = :id;");
+ $stmt->bindParam(":id", $id);
+ return $stmt->execute();
+ }
+
+ /**
+ * Delete work data by ID
+ * @param int $id
+ * @return bool - True if successful, false if not
+ */
+ function deleteWorkData(int $id): bool
+ {
+ $conn = dbConn();
+ $stmt = $conn->prepare("DELETE FROM work WHERE ID = :id;");
+ $stmt->bindParam(":id", $id);
+ return $stmt->execute();
+ }
+
+ /**
+ * Create new education data
+ * @param string $dateFrom - Start date
+ * @param string $dateTo - End date
+ * @param string $grade - Grade
+ * @param string $course - Course
+ * @return bool|int - ID of the new education data or false if not successful
+ */
+ function addEduData(string $dateFrom, string $dateTo, string $grade, string $course): bool|int
+ {
+ $conn = dbConn();
+ $stmt = $conn->prepare("INSERT INTO edu (startPeriod, endPeriod, grade, course) VALUES (:dateFrom, :dateTo, :grade, :course);");
+ $stmt->bindParam(":dateFrom", $dateFrom);
+ $stmt->bindParam(":dateTo", $dateTo);
+ $stmt->bindParam(":grade", $grade);
+ $stmt->bindParam(":course", $course);
+
+ if($stmt->execute())
+ {
+ return $conn->lastInsertId();
+ }
+ return false;
+ }
+
+ /**
+ * Create new work data
+ * @param string $dateFrom - Start date
+ * @param string $dateTo - End date
+ * @param string $companyName - Company name
+ * @param string $area - Area
+ * @param string $title - Title
+ * @return bool|int - ID of the new work data if successful, false if not
+ */
+ function addWorkData(string $dateFrom, string $dateTo, string $companyName, string $area, string $title): bool|int
+ {
+ $conn = dbConn();
+ $stmt = $conn->prepare("INSERT INTO work (startPeriod, endPeriod, companyName, area, title) VALUES (:dateFrom, :dateTo, :companyName, :area, :title);");
+ $stmt->bindParam(":dateFrom", $dateFrom);
+ $stmt->bindParam(":dateTo", $dateTo);
+ $stmt->bindParam(":companyName", $companyName);
+ $stmt->bindParam(":area", $area);
+ $stmt->bindParam(":title", $title);
+
+ if($stmt->execute())
+ {
+ return $conn->lastInsertId();
+ }
+ return false;
+ }
+
}
diff --git a/dist/editor/css/main.css b/dist/editor/css/main.css
index f71a59c..326ca32 100644
--- a/dist/editor/css/main.css
+++ b/dist/editor/css/main.css
@@ -1 +1 @@
-/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}:root{--mainHue:80;--mainSat:60%;--mainLight:50%;--primaryDefault:hsla(var(--mainHue), var(--mainSat), var(--mainLight), 1);--primaryHover:hsla(var(--mainHue), var(--mainSat), calc(var(--mainLight) - 10%), 1);--timelineItemBrdr:hsla(var(--mainHue), var(--mainSat), calc(var(--mainLight) - 20%), 1);--errorDefault:hsla(0, calc(var(--mainSat) + 10%),calc(var(--mainLight) + 10%), 1);--errorHover:hsla(0, calc(var(--mainSat) + 10%), calc(var(--mainLight) - 10%), 1);--grey:hsla(0, 0%, 39%, 1);--notAvailableDefault:hsla(0, 0%, 39%, 1);--notAvailableHover:hsla(0, 0%,32%, 1);--mutedGrey:hsla(0, 0%, 78%, 1);--mutedBlack:hsla(0, 0%, 0%, 0.25);--navBack:hsla(0, 0%, 30%, 1);--titleFS:2.25rem;--generalFS:1.125rem;--headingFS:1.5rem}*{box-sizing:border-box}html{scroll-behavior:smooth}body{font-family:Noto Sans KR,sans-serif;font-style:normal;font-weight:500;font-size:var(--generalFS);line-height:1.625rem}a:visited{color:inherit}h1,nav{font-family:Share Tech Mono,monospace;font-style:normal;font-weight:400;font-size:var(--titleFS);line-height:2.5625rem;text-transform:lowercase}h2{font-family:Noto Sans KR,sans-serif;font-style:normal;font-weight:500;font-size:var(--headingFS);line-height:2.1875rem}a.btn,form input[type=submit]{text-decoration:none;display:inline-block;padding:1em 2em;border-radius:.625em;border:.3215em solid var(--primaryDefault);color:#fff;text-align:center}form input[type=submit]{padding:1.1em 2em}a.btn:hover,form input[type=submit]:hover{border:.3215em solid var(--primaryHover)}a.btnPrimary,form input[type=submit]{background:var(--primaryDefault);cursor:pointer}a.btnOutline{background:#fff;color:var(--primaryDefault)}a.btnPrimary[disabled]{pointer-events:none;background:var(--notAvailableDefault);border:.3215em solid var(--notAvailableDefault)}a.btnPrimary[disabled]:hover{background:var(--notAvailableHover);border:.3215em solid var(--notAvailableHover)}a.btnPrimary:hover,form input[type=submit]:hover{background:var(--primaryHover)}a.btn:active,form input[type=submit]:active{padding:.8rem 1.8rem}.boxShadowOut:hover{box-shadow:0 6px 4px 0 var(--mutedBlack)}.boxShadowIn:active{box-shadow:inset 0 6px 4px 0 var(--mutedBlack)}.textShadow:hover{text-shadow:0 6px 4px var(--mutedBlack)}form .formControl{width:100%}form .formControl input:not([type=submit]),form .formControl textarea{width:100%;border:4px solid var(--primaryDefault);background:0 0;outline:0;-webkit-border-radius:1em;-moz-border-radius:1em;border-radius:.5em;padding:0 .5em}form .formControl textarea{padding:.5em}form .formControl input:not([type=submit]).invalid:invalid,form .formControl textarea.invalid:invalid{border:4px solid var(--errorDefault)}form .formControl input:not([type=submit]).invalid:invalid:focus,form .formControl textarea.invalid:invalid:focus{border:4px solid var(--errorHover);box-shadow:0 4px 2px 0 var(--mutedBlack)}form .formControl input:not([type=submit]):focus,form .formControl textarea:focus{border:4px solid var(--primaryHover)}form .formControl input:not([type=submit]){height:3em}form .formControl{width:100%}form input[type=submit]{align-self:flex-start}form .formControl input:not([type=submit]),form .formControl textarea{width:100%;border:4px solid var(--primaryDefault);background:0 0;outline:0;-webkit-border-radius:1em;-moz-border-radius:1em;border-radius:.5em;padding:0 .5em}form .formControl textarea{padding:.5em}form .formControl input:not([type=submit]).invalid:invalid,form .formControl textarea.invalid:invalid{border:4px solid var(--errorDefault)}form .formControl input:not([type=submit]).invalid:invalid:focus,form .formControl textarea.invalid:invalid:focus{border:4px solid var(--errorHover);box-shadow:0 4px 2px 0 var(--mutedBlack)}form .formControl input:not([type=submit]):focus,form .formControl textarea:focus{border:4px solid var(--primaryHover)}form .formControl input:not([type=submit]){height:3em}form .formControl i.fa-eye,form .formControl i.fa-eye-slash{margin-left:-40px;cursor:pointer;color:var(--primaryDefault)}form .formControl input:not([type=submit]):focus+i.fa-eye,form .formControl input:not([type=submit]):focus+i.fa-eye-slash{color:var(--primaryHover)}section#about,section#curriculumVitae h1{padding:0 5rem}h1{text-transform:none}body,html{height:100%}main.login{height:100%;display:flex;flex-direction:column;justify-content:center;align-items:center;background-image:radial-gradient(var(--primaryDefault),#597226)}div.container{flex-direction:column;justify-content:center;align-items:center;background-color:#fff;padding:2em 5em;-webkit-border-radius:1em;-moz-border-radius:1em;border-radius:1em;box-shadow:0 6px 4px 0 var(--mutedBlack);-webkit-transform:translateX(-150vw);-moz-transform:translateX(-150vw);-ms-transform:translateX(-150vw);-o-transform:translateX(-150vw);transform:translateX(-150vw);-webkit-transition:transform .4s ease-in-out;-moz-transition:transform .4s ease-in-out;-ms-transition:transform .4s ease-in-out;-o-transition:transform .4s ease-in-out;transition:transform .4s ease-in-out;overflow:hidden}div.container.shown{-webkit-transform:translateX(0);-moz-transform:translateX(0);-ms-transform:translateX(0);-o-transform:translateX(0);transform:translateX(0)}div.container form{display:flex;flex-direction:column;justify-content:center;align-items:center;gap:1em}div#login #password{font-family:Verdana,serif;letter-spacing:.125em}div#login input[type=submit]{margin:0}div.error{background:var(--errorDefault);color:#fff;padding:.5em .8em;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;display:flex;justify-content:center;align-items:center;align-self:flex-start;flex-direction:row-reverse;position:relative;height:75px;visibility:visible;overflow:hidden;-webkit-transition:all .5s ease-in-out;-moz-transition:all .5s ease-in-out;-ms-transition:all .5s ease-in-out;-o-transition:all .5s ease-in-out;transition:all .5s ease-in-out;opacity:1;margin-top:1em}div.error button{border:none;background:0 0;outline:0;cursor:pointer;color:#fff;font-size:1.25rem;margin-top:-5px;position:absolute;transform:translate(0,0);transform-origin:0 0;right:10px;top:10px}div.error.hidden{opacity:0;visibility:hidden;height:0;margin:0;padding:0}div.error button:hover{text-shadow:-1px 2px var(--mutedBlack)}div.btnContainer{width:100%;display:flex;flex-direction:row;justify-content:space-between;align-items:center}div.btnContainer a:not(.btn){color:#000}nav{font-size:var(--headingFS)}nav.sideNav{height:100%;width:250px;z-index:1;position:fixed;top:0;left:0;background-color:var(--primaryHover);overflow-x:hidden;-webkit-transition:.5s;-moz-transition:.5s;-ms-transition:.5s;-o-transition:.5s;transition:.5s;padding-top:60px}nav.sideNav ul li{list-style:none}nav.sideNav a{padding:8px 8px 8px 0;text-decoration:none;color:#fff;display:block;-webkit-transition:.3s;-moz-transition:.3s;-ms-transition:.3s;-o-transition:.3s;transition:.3s}nav.sideNav .closeBtn{position:absolute;top:0;right:25px;margin-left:50px;font-size:var(--titleFS);display:none}nav.sideNav ul li span{visibility:hidden}nav.sideNav ul li .active span,nav.sideNav ul li a:hover span{visibility:visible}span#navOpen{font-size:var(--titleFS);cursor:pointer}main.editor{margin-left:250px}.title{display:flex;flex-direction:column;justify-content:center;align-items:center}#navOpen{visibility:hidden;padding:.25em 0 0 .25em;align-self:flex-start}section#curriculumVitae,section#projects,section#settings{margin:0 2em}input[type=submit]{margin-top:2em}.delete,.edit{border:none;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;outline:0;background-color:var(--primaryDefault);color:#fff;cursor:pointer}div.editorContainer{display:flex;flex-direction:row;justify-content:center;align-items:baseline;gap:2em;margin-bottom:.5em}div.editorContainer>*{width:45%}div.modifyBtnContainer{display:flex;flex-direction:row;justify-content:space-between;align-items:center;margin-bottom:.5em}div.dateContainer{display:flex;flex-direction:row;justify-content:center;align-items:center;gap:1em;margin-bottom:.5em}section#curriculumVitae .timeline{position:relative;max-width:30em;gap:1em;display:flex;flex-direction:column;height:100%}section#curriculumVitae .timelineItem{color:#fff;border:2px solid var(--timelineItemBrdr);-webkit-border-radius:10px;-moz-border-radius:10px;border-radius:10px;padding:0 1rem;position:relative;background-color:var(--primaryHover)}section#curriculumVitae .timelineItem.editing{color:#000;border:5px solid var(--primaryDefault);padding:.5em;background-color:#fff}form div.gradeContainer.formControl{display:flex;flex-direction:row;justify-content:flex-start;align-items:center}section#curriculumVitae form.timelineItem:not(.editing) .delete,section#curriculumVitae form.timelineItem:not(.editing) .edit{color:var(--primaryHover);background-color:#fff}section#curriculumVitae form.timelineItem:not(.editing) div.dateContainer{display:none}section#curriculumVitae form.timelineItem.editing .timelineHeader{display:none}section#curriculumVitae form.timelineItem.editing div.gradeContainer.formControl{gap:1em;margin-bottom:.5em}section#curriculumVitae form.timelineItem:not(.editing) .formControl .courseText,section#curriculumVitae form.timelineItem:not(.editing) div.gradeContainer.formControl input{outline:0;border:none;color:#fff;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}section#curriculumVitae form.timelineItem:not(.editing) div.gradeContainer.formControl input{padding:0 .25em}section#curriculumVitae form.timelineItem:not(.editing) div.formControl .courseText{padding:0}section#curriculumVitae form.timelineItem:not(.editing) input[type=submit]{display:none}.courseText{resize:none}@media only screen and (max-width:75em){nav.sideNav .closeBtn{display:block}}
\ No newline at end of file
+/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}:root{--mainHue:80;--mainSat:60%;--mainLight:50%;--primaryDefault:hsla(var(--mainHue), var(--mainSat), var(--mainLight), 1);--primaryHover:hsla(var(--mainHue), var(--mainSat), calc(var(--mainLight) - 10%), 1);--timelineItemBrdr:hsla(var(--mainHue), var(--mainSat), calc(var(--mainLight) - 20%), 1);--errorDefault:hsla(0, calc(var(--mainSat) + 10%),calc(var(--mainLight) + 10%), 1);--errorHover:hsla(0, calc(var(--mainSat) + 10%), calc(var(--mainLight) - 10%), 1);--grey:hsla(0, 0%, 39%, 1);--notAvailableDefault:hsla(0, 0%, 39%, 1);--notAvailableHover:hsla(0, 0%,32%, 1);--mutedGrey:hsla(0, 0%, 78%, 1);--mutedBlack:hsla(0, 0%, 0%, 0.25);--navBack:hsla(0, 0%, 30%, 1);--titleFS:2.25rem;--generalFS:1.125rem;--headingFS:1.5rem}*{box-sizing:border-box}html{scroll-behavior:smooth}body{font-family:Noto Sans KR,sans-serif;font-style:normal;font-weight:500;font-size:var(--generalFS);line-height:1.625rem}a:visited{color:inherit}h1,nav{font-family:Share Tech Mono,monospace;font-style:normal;font-weight:400;font-size:var(--titleFS);line-height:2.5625rem;text-transform:lowercase}h2{font-family:Noto Sans KR,sans-serif;font-style:normal;font-weight:500;font-size:var(--headingFS);line-height:2.1875rem}a.btn,form input[type=submit]{text-decoration:none;display:inline-block;padding:1em 2em;border-radius:.625em;border:.3215em solid var(--primaryDefault);color:#fff;text-align:center}form input[type=submit]{padding:1.1em 2em}a.btn:hover,form input[type=submit]:hover{border:.3215em solid var(--primaryHover)}a.btnPrimary,form input[type=submit]{background:var(--primaryDefault);cursor:pointer}a.btnOutline{background:#fff;color:var(--primaryDefault)}a.btnPrimary[disabled]{pointer-events:none;background:var(--notAvailableDefault);border:.3215em solid var(--notAvailableDefault)}a.btnPrimary[disabled]:hover{background:var(--notAvailableHover);border:.3215em solid var(--notAvailableHover)}a.btnPrimary:hover,form input[type=submit]:hover{background:var(--primaryHover)}a.btn:active,form input[type=submit]:active{padding:.8rem 1.8rem}.boxShadowOut:hover{box-shadow:0 6px 4px 0 var(--mutedBlack)}.boxShadowIn:active{box-shadow:inset 0 6px 4px 0 var(--mutedBlack)}.textShadow:hover{text-shadow:0 6px 4px var(--mutedBlack)}form .formControl{width:100%}form .formControl input:not([type=submit]),form .formControl textarea{width:100%;border:4px solid var(--primaryDefault);background:0 0;outline:0;-webkit-border-radius:1em;-moz-border-radius:1em;border-radius:.5em;padding:0 .5em}form .formControl textarea{padding:.5em}form .formControl input:not([type=submit]).invalid:invalid,form .formControl textarea.invalid:invalid{border:4px solid var(--errorDefault)}form .formControl input:not([type=submit]).invalid:invalid:focus,form .formControl textarea.invalid:invalid:focus{border:4px solid var(--errorHover);box-shadow:0 4px 2px 0 var(--mutedBlack)}form .formControl input:not([type=submit]):focus,form .formControl textarea:focus{border:4px solid var(--primaryHover)}form .formControl input:not([type=submit]){height:3em}form .formControl{width:100%}form input[type=submit]{align-self:flex-start}form .formControl input:not([type=submit]),form .formControl textarea{width:100%;border:4px solid var(--primaryDefault);background:0 0;outline:0;-webkit-border-radius:1em;-moz-border-radius:1em;border-radius:.5em;padding:0 .5em}form .formControl textarea{padding:.5em}form .formControl input:not([type=submit]).invalid:invalid,form .formControl textarea.invalid:invalid{border:4px solid var(--errorDefault)}form .formControl input:not([type=submit]).invalid:invalid:focus,form .formControl textarea.invalid:invalid:focus{border:4px solid var(--errorHover);box-shadow:0 4px 2px 0 var(--mutedBlack)}form .formControl input:not([type=submit]):focus,form .formControl textarea:focus{border:4px solid var(--primaryHover)}form .formControl input:not([type=submit]){height:3em}form .formControl i.fa-eye,form .formControl i.fa-eye-slash{margin-left:-40px;cursor:pointer;color:var(--primaryDefault)}form .formControl input:not([type=submit]):focus+i.fa-eye,form .formControl input:not([type=submit]):focus+i.fa-eye-slash{color:var(--primaryHover)}section#about,section#curriculumVitae h1{padding:0 5rem}h1{text-transform:none}body,html{height:100%}main.login{height:100%;display:flex;flex-direction:column;justify-content:center;align-items:center;background-image:radial-gradient(var(--primaryDefault),#597226)}div.container{flex-direction:column;justify-content:center;align-items:center;background-color:#fff;padding:2em 5em;-webkit-border-radius:1em;-moz-border-radius:1em;border-radius:1em;box-shadow:0 6px 4px 0 var(--mutedBlack);-webkit-transform:translateX(-150vw);-moz-transform:translateX(-150vw);-ms-transform:translateX(-150vw);-o-transform:translateX(-150vw);transform:translateX(-150vw);-webkit-transition:transform .4s ease-in-out;-moz-transition:transform .4s ease-in-out;-ms-transition:transform .4s ease-in-out;-o-transition:transform .4s ease-in-out;transition:transform .4s ease-in-out;overflow:hidden}div.container.shown{-webkit-transform:translateX(0);-moz-transform:translateX(0);-ms-transform:translateX(0);-o-transform:translateX(0);transform:translateX(0)}div.container form{display:flex;flex-direction:column;justify-content:center;align-items:center;gap:1em}div#login #password{font-family:Verdana,serif;letter-spacing:.125em}div#login input[type=submit]{margin:0}div.error{background:var(--errorDefault);color:#fff;padding:.5em .8em;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;display:flex;justify-content:center;align-items:center;align-self:flex-start;flex-direction:row-reverse;position:relative;height:75px;visibility:visible;overflow:hidden;-webkit-transition:all .5s ease-in-out;-moz-transition:all .5s ease-in-out;-ms-transition:all .5s ease-in-out;-o-transition:all .5s ease-in-out;transition:all .5s ease-in-out;opacity:1;margin-top:1em}div.error button{border:none;background:0 0;outline:0;cursor:pointer;color:#fff;font-size:1.25rem;margin-top:-5px;position:absolute;transform:translate(0,0);transform-origin:0 0;right:10px;top:10px}div.error.hidden{opacity:0;visibility:hidden;height:0;margin:0;padding:0}div.error button:hover{text-shadow:-1px 2px var(--mutedBlack)}div.btnContainer{width:100%;display:flex;flex-direction:row;justify-content:space-between;align-items:center}div.btnContainer a:not(.btn){color:#000}nav{font-size:var(--headingFS)}nav.sideNav{height:100%;width:250px;z-index:1;position:fixed;top:0;left:0;background-color:var(--primaryHover);overflow-x:hidden;-webkit-transition:.5s;-moz-transition:.5s;-ms-transition:.5s;-o-transition:.5s;transition:.5s;padding-top:60px}nav.sideNav ul li{list-style:none}nav.sideNav a{padding:8px 8px 8px 0;text-decoration:none;color:#fff;display:block;-webkit-transition:.3s;-moz-transition:.3s;-ms-transition:.3s;-o-transition:.3s;transition:.3s}nav.sideNav .closeBtn{position:absolute;top:0;right:25px;margin-left:50px;font-size:var(--titleFS);display:none}nav.sideNav ul li span{visibility:hidden}nav.sideNav ul li .active span,nav.sideNav ul li a:hover span{visibility:visible}span#navOpen{font-size:var(--titleFS);cursor:pointer}main.editor{margin-left:250px}.title{display:flex;flex-direction:column;justify-content:center;align-items:center}#navOpen{visibility:hidden;padding:.25em 0 0 .25em;align-self:flex-start}section#curriculumVitae,section#projects,section#settings{margin:0 2em}input[type=submit]{margin-top:2em}.delete,.edit{border:none;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;outline:0;background-color:var(--primaryDefault);color:#fff;cursor:pointer}.timelineHeader{font-weight:400}div.editorContainer{display:flex;flex-direction:row;justify-content:center;align-items:baseline;gap:2em;margin-bottom:.5em}div.editorContainer>*{width:45%}div.modifyBtnContainer{display:flex;flex-direction:row;justify-content:space-between;align-items:center;margin-bottom:.5em}div.companyAreaContainer,div.dateContainer{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;gap:1em;margin-bottom:.5em}section#curriculumVitae .timeline{position:relative;max-width:30em;gap:1em;display:flex;flex-direction:column;height:100%}section#curriculumVitae .timelineItem{color:#fff;border:2px solid var(--timelineItemBrdr);-webkit-border-radius:10px;-moz-border-radius:10px;border-radius:10px;padding:0 1rem;position:relative;background-color:var(--primaryHover)}section#curriculumVitae .timelineItem.editing{color:#000;border:5px solid var(--primaryDefault);padding:.5em;background-color:#fff}form div.gradeContainer.formControl{display:flex;flex-direction:row;justify-content:flex-start;align-items:center}section#curriculumVitae form.timelineItem:not(.editing) .delete,section#curriculumVitae form.timelineItem:not(.editing) .edit{color:var(--primaryHover);background-color:#fff}section#curriculumVitae form.timelineItem:not(.editing) div.dateContainer{display:none}section#curriculumVitae form.timelineItem.editing .timelineHeader{display:none}section#curriculumVitae form.timelineItem.editing div.gradeContainer.formControl{gap:1em;margin-bottom:.5em}section#curriculumVitae form.timelineItem:not(.editing) .formControl .courseText,section#curriculumVitae form.timelineItem:not(.editing) .formControl .jobTitleText,section#curriculumVitae form.timelineItem:not(.editing) div.companyAreaContainer.formControl input,section#curriculumVitae form.timelineItem:not(.editing) div.gradeContainer.formControl input{outline:0;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}section#curriculumVitae form.timelineItem:not(.editing) div.companyAreaContainer.formControl>*,section#curriculumVitae form.timelineItem:not(.editing) div.gradeContainer.formControl>*{color:#e5e5e5}section#curriculumVitae form.timelineItem:not(.editing) .formControl .courseText,section#curriculumVitae form.timelineItem:not(.editing) .formControl .jobTitleText{color:#fff}section#curriculumVitae form.timelineItem:not(.editing) div.gradeContainer.formControl input{padding:0 .25em}section#curriculumVitae form.timelineItem:not(.editing) .formControl .courseText,section#curriculumVitae form.timelineItem:not(.editing) div.formControl .courseText{padding:0}section#curriculumVitae form.timelineItem:not(.editing) input[type=submit]{display:none}.courseText{resize:none}section#curriculumVitae form.timelineItem:not(.editing) div.companyAreaContainer input{width:30%}@media only screen and (max-width:75em){nav.sideNav .closeBtn{display:block}}
\ No newline at end of file
diff --git a/dist/editor/editor.html b/dist/editor/editor.html
index 2c5f687..5c7095f 100644
--- a/dist/editor/editor.html
+++ b/dist/editor/editor.html
@@ -1 +1 @@
-
Editor × ☰
Editor
\ No newline at end of file
+Editor × ☰
Editor
\ No newline at end of file
diff --git a/dist/editor/js/editor.js b/dist/editor/js/editor.js
index 9544b59..69639fc 100644
--- a/dist/editor/js/editor.js
+++ b/dist/editor/js/editor.js
@@ -1 +1 @@
-let dateOptions={month:"short",year:"numeric"};function edit(e){document.querySelector("#timelineItem"+e).classList.toggle("editing"),document.querySelector("#grade"+e).toggleAttribute("disabled"),document.querySelector("#course"+e).toggleAttribute("disabled")}function updateEduItem(e,t){t.preventDefault();let n={};n.dateFrom=document.querySelector("#dateFrom"+e).value,n.dateTo=document.querySelector("#dateTo"+e).value,n.grade=document.querySelector("#grade"+e).value,n.course=document.querySelector("#course"+e).value,fetch("/api/timelineData/edu/"+e,{method:"PATCH",body:JSON.stringify(n),headers:{"Content-Type":"application/json",Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{if(t.ok)return document.querySelector("#timelineHeader"+e).innerHTML=new Date(document.querySelector("#dateFrom"+e).value).toLocaleString("en-gb",dateOptions)+" - "+new Date(document.querySelector("#dateTo"+e).value).toLocaleString("en-gb",dateOptions),document.querySelector("#timelineItem"+e).classList.toggle("editing"),document.querySelector("#grade"+e).setAttribute("disabled",""),void document.querySelector("#course"+e).setAttribute("disabled","");401!==t.status?t.json().then((t=>{document.querySelector("#eduError"+e).classList.remove("hidden"),document.querySelector(`#eduError${e} div`).innerHTML=t.error})):window.location.href="./"}))}document.addEventListener("DOMContentLoaded",(()=>{document.querySelector("#dateFrom").max=(new Date).toISOString().split("T")[0],fetch("/api/timelineData/edu").then((e=>{e.json().then((t=>{if(e.ok)for(let e=0;eupdateEduItem(n,e),o.innerHTML=`\n \n \n \n
\n \n \n -\n \n
\n\t\t\t\t\t\n \n Grade: \n \n
\n\t\t\t\t\t\n\t\t\t\t\t \n\t\t\t\t\t
\n\t\t\t\t\t\n \n\t\t\t\t\t \n\t\t\t\t`,document.getElementById("edu").appendChild(o)}else document.querySelector("#edu").innerHTML="No education data found"}))}))})),document.querySelector("#navOpen").addEventListener("click",(e=>{document.querySelector("nav.sideNav").style.removeProperty("width"),document.querySelector("main.editor").style.removeProperty("margin-left"),e.target.style.removeProperty("visibility")})),document.querySelector("#navClose").addEventListener("click",(()=>{document.querySelector("nav.sideNav").style.width="0",document.querySelector("main.editor").style.marginLeft="0",document.querySelector("#navOpen").style.visibility="visible"}));
\ No newline at end of file
+let dateOptions={month:"short",year:"numeric"};function edit(e){if(document.querySelector("#timelineItem"+e).classList.toggle("editing"),e.includes("e"))return document.querySelector("#grade"+e).toggleAttribute("disabled"),void document.querySelector("#course"+e).toggleAttribute("disabled");document.querySelector("#companyName"+e).toggleAttribute("disabled"),document.querySelector("#area"+e).toggleAttribute("disabled"),document.querySelector("#jobTitle"+e).toggleAttribute("disabled")}function addEduData(e,t,o,n,r,a=!1){let d=e+"e",i=document.createElement("form");i.id="timelineItem"+d,i.classList.add("timelineItem"),i.onsubmit=t=>updateEduItem(e,t),i.innerHTML=`\n \n \n \n
\n \n \n -\n \n
\n \n \n Grade: \n \n
\n \n \n
\n \n \n \n `,a?document.querySelector("#edu").prepend(i):document.getElementById("edu").appendChild(i)}function addWorkData(e,t,o,n,r,a,d=!1){let i=e+"w",l=document.createElement("form");l.id="timelineItem"+i,l.classList.add("timelineItem"),l.onsubmit=t=>updateWorkItem(e,t),l.innerHTML=`\n \n \n \n
\n \n \n -\n \n
\n \n \n \n -\n \n
\n \n \n
\n \n \n \n\t`,d?document.querySelector("#work").prepend(l):document.getElementById("work").appendChild(l)}function updateEduItem(e,t){t.preventDefault();let o={};o.dateFrom=document.querySelector(`#dateFrom${e}e`).value,o.dateTo=document.querySelector(`#dateTo${e}e`).value,o.grade=document.querySelector(`#grade${e}e`).value,o.course=document.querySelector(`#course${e}e`).value,fetch("/api/timelineData/edu/"+e,{method:"PATCH",body:JSON.stringify(o),headers:{"Content-Type":"application/json",Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{if(t.ok)return document.querySelector(`#timelineHeader${e}e`).innerHTML=new Date(document.querySelector(`#dateFrom${e}e`).value).toLocaleString("en-gb",dateOptions)+" - "+new Date(document.querySelector(`#dateTo${e}e`).value).toLocaleString("en-gb",dateOptions),document.querySelector(`#timelineItem${e}e`).classList.toggle("editing"),document.querySelector(`#grade${e}e`).setAttribute("disabled",""),void document.querySelector(`#course${e}e`).setAttribute("disabled","");401!==t.status?t.json().then((t=>{document.querySelector(`#eduError${e}e`).classList.remove("hidden"),document.querySelector(`#eduError${e}e div`).innerHTML=t.error})):window.location.href="./"}))}function updateWorkItem(e,t){t.preventDefault();let o={};o.dateFrom=document.querySelector(`#dateFrom${e}w`).value,o.dateTo=document.querySelector(`#dateTo${e}w`).value,o.companyName=document.querySelector(`#companyName${e}w`).value,o.area=document.querySelector(`#area${e}w`).value,o.title=document.querySelector(`#jobTitle${e}w`).value,fetch("/api/timelineData/work/"+e,{method:"PATCH",body:JSON.stringify(o),headers:{"Content-Type":"application/json",Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{if(t.ok)return document.querySelector(`#timelineHeader${e}w`).innerHTML=new Date(document.querySelector(`#dateFrom${e}w`).value).toLocaleString("en-gb",dateOptions)+" - "+new Date(document.querySelector(`#dateTo${e}w`).value).toLocaleString("en-gb",dateOptions),document.querySelector(`#timelineItem${e}w`).classList.toggle("editing"),document.querySelector(`#companyName${e}w`).setAttribute("disabled",""),document.querySelector(`#area${e}w`).setAttribute("disabled",""),void document.querySelector(`#jobTitle${e}w`).setAttribute("disabled","");401!==t.status?t.json().then((t=>{document.querySelector(`#workError${e}w`).classList.remove("hidden"),document.querySelector(`#workError${e}w div`).innerHTML=t.error})):window.location.href="./"}))}function deleteEduItem(e){fetch("/api/timelineData/edu/"+e,{method:"DELETE",headers:{Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{t.ok?document.querySelector(`#timelineItem${e}e`).remove():401!==t.status?t.json().then((e=>alert(e.error))):window.location.href="./"}))}function deleteWorkItem(e){fetch("/api/timelineData/work/"+e,{method:"DELETE",headers:{Authorization:"Bearer "+localStorage.getItem("token")}}).then((t=>{t.ok?document.querySelector(`#timelineItem${e}w`).remove():401!==t.status?t.json().then((e=>alert(e.error))):window.location.href="./"}))}document.addEventListener("DOMContentLoaded",(()=>{fetch("/api/user/isLoggedIn").then((e=>{e.ok||(window.location.href="./")})),document.querySelector("#dateFromE").max=(new Date).toISOString().split("T")[0],document.querySelector("#dateFromW").max=(new Date).toISOString().split("T")[0],fetch("/api/timelineData/edu").then((e=>{e.json().then((t=>{if(e.ok)for(let e=0;e{e.json().then((t=>{if(e.ok)for(let e=0;e{document.querySelector("nav.sideNav").style.removeProperty("width"),document.querySelector("main.editor").style.removeProperty("margin-left"),e.target.style.removeProperty("visibility")})),document.querySelector("#navClose").addEventListener("click",(()=>{document.querySelector("nav.sideNav").style.width="0",document.querySelector("main.editor").style.marginLeft="0",document.querySelector("#navOpen").style.visibility="visible"})),document.querySelector("#addEdu").addEventListener("submit",(e=>{e.preventDefault();let t=new FormData;t.append("dateFrom",document.querySelector("#dateFromE").value),t.append("dateTo",document.querySelector("#dateToE").value),t.append("grade",document.querySelector("#grade").value),t.append("course",document.querySelector("#courseTitle").value),fetch("/api/timelineData/edu",{method:"POST",body:t,headers:{Authentication:localStorage.getItem("token")}}).then((e=>e.json().then((o=>{if(e.ok)return addEduData(o.ID,t.get("dateFrom"),t.get("dateTo"),t.get("grade"),t.get("course"),!0),void document.querySelector("#addEdu").reset();401!==e.status?(document.querySelector("#eduError").classList.remove("hidden"),document.querySelector("#eduError div").innerHTML=o.error):window.location.href="./"}))))})),document.querySelector("#addWork").addEventListener("submit",(e=>{e.preventDefault();let t=new FormData;t.append("dateFrom",document.querySelector("#dateFromW").value),t.append("dateTo",document.querySelector("#dateToW").value),t.append("companyName",document.querySelector("#company").value),t.append("area",document.querySelector("#area").value),t.append("title",document.querySelector("#jobTitle").value),fetch("/api/timelineData/work",{method:"POST",body:t,headers:{Authentication:localStorage.getItem("token")}}).then((e=>e.json().then((o=>{if(e.ok){let e=null===t.get("dateTo")?"Present":t.get("dateTo ");return addWorkData(o.ID,t.get("dateFrom"),e,t.get("companyName"),t.get("area"),t.get("title"),!0),void document.querySelector("#addEdu").reset()}401!==e.status?(document.querySelector("#eduError").classList.remove("hidden"),document.querySelector("#eduError div").innerHTML=o.error):window.location.href="./"}))))}));
\ No newline at end of file
diff --git a/dist/js/main.js b/dist/js/main.js
index 5936e6f..ae15f45 100644
--- a/dist/js/main.js
+++ b/dist/js/main.js
@@ -1 +1 @@
-const scrollLimit=150;var dataText=["full stack developer","web designer","student","gamer","drummer"];function typeWriter(t,e,n){e_',setTimeout((function(){typeWriter(t,e+1,n)}),100)):"function"==typeof n&&setTimeout(n,700)}function StartTextAnimation(t){void 0===dataText[t]?setTimeout((function(){StartTextAnimation(0)}),1500):t{e.json().then((n=>{e.ok&&n.forEach((e=>{let n=document.createElement("div");n.classList.add("timelineItem"),n.innerHTML=`\n\t\t\t\t\t\n\t\t\t\t\tGrade: ${e.grade} \n\t\t\t\t\t${e.course}
\n\t\t\t\t`,document.getElementById("edu").appendChild(n)}))}))})),fetch("/api/timelineData/work").then((e=>{e.json().then((n=>{e.ok&&n.forEach((e=>{let n=document.createElement("div");n.classList.add("timelineItem"),n.innerHTML=`\n\t\t\t\t\t\n\t\t\t\t\t${e.companyName} - ${e.area} \n\t\t\t\t\t${e.title}
\n\t\t\t\t`,document.getElementById("work").appendChild(n)}))}))}))}function getProjectData(){fetch("/api/projectData").then((t=>{t.json().then((e=>{t.ok&&e.forEach((t=>{if("1"===t.isMainProject)return document.getElementById("mainProj").innerHTML=`\n\t\t\t\t\t\t${t.title} \n\t\t\t\t\t\t\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t
${t.information}
\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t`,null;document.querySelector("#otherProj div").innerHTML+=`\n \n
\n
\n
\n `}))}))}))}window.onscroll=()=>{document.body.scrollTop>=150||document.documentElement.scrollTop>=150?document.querySelector("nav").classList.add("scrolled"):document.querySelector("nav").classList.remove("scrolled");let t="";document.querySelectorAll("section").forEach((e=>{const n=e.offsetTop;window.pageYOffset>=n-60&&(t=e.getAttribute("id"))})),document.querySelectorAll("nav ul li a").forEach((e=>{e.classList.remove("active"),e.href.includes(t)&&""!==t?e.classList.add("active"):""===t&&document.querySelector("nav ul li a").classList.add("active")}))},document.addEventListener("DOMContentLoaded",(()=>{StartTextAnimation(0),getTimelineData(),getProjectData()})),document.querySelector("#contactError .close").addEventListener("click",(()=>document.querySelector("#contactError").classList.toggle("hidden"))),document.querySelector("#goBackToTop").addEventListener("click",(()=>{window.scrollTo(0,0)})),document.querySelector("#contactForm").addEventListener("submit",(t=>{t.preventDefault();let e=new FormData;e.append("fName",document.querySelector("#fName").value),e.append("lName",document.querySelector("#lName").value),e.append("email",document.querySelector("#email").value),e.append("subject",document.querySelector("#subject").value),e.append("message",document.querySelector("#message").value);let n=!1;if(["#fName","#lName","#email","#subject","#message"].forEach((t=>{const e=document.querySelector(t);0===e.value.length?(e.classList.add("invalid"),n=!0):(e.classList.remove("invalid"),document.querySelector("#contactError").classList.remove("error"))})),n)return document.querySelector("#contactError").classList.add("error"),document.querySelector("#contactError").classList.remove("hidden"),void(document.querySelector("#contactError div").innerText="Please fill out all fields.");fetch("/api/contact",{method:"POST",body:e}).then((t=>{t.ok&&(document.querySelector("#contactError").classList.remove("hidden"),document.querySelector("#contactError div").innerText="Thanks for contacting me, I will get back to you as soon as possible.")}))}));
\ No newline at end of file
+const scrollLimit=150;var dataText=["full stack developer","web designer","student","gamer","drummer"];function typeWriter(t,e,n){e_',setTimeout((function(){typeWriter(t,e+1,n)}),100)):"function"==typeof n&&setTimeout(n,700)}function StartTextAnimation(t){void 0===dataText[t]?setTimeout((function(){StartTextAnimation(0)}),1500):t{e.json().then((n=>{e.ok&&n.forEach((e=>{let n=document.createElement("div");n.classList.add("timelineItem"),n.innerHTML=`\n\t\t\t\t\t\n\t\t\t\t\tGrade: ${e.grade} \n\t\t\t\t\t${e.course}
\n\t\t\t\t`,document.getElementById("edu").appendChild(n)}))}))})),fetch("/api/timelineData/work").then((e=>{e.json().then((n=>{e.ok&&n.forEach((e=>{let n=document.createElement("div");n.classList.add("timelineItem");let o=null===e.endPeriod?"Present":new Date(e.endPeriod).toLocaleString("en-gb",t);n.innerHTML=`\n\t\t\t\t\t\n\t\t\t\t\t${e.companyName} - ${e.area} \n\t\t\t\t\t${e.title}
\n\t\t\t\t`,document.getElementById("work").appendChild(n)}))}))}))}function getProjectData(){fetch("/api/projectData").then((t=>{t.json().then((e=>{t.ok&&e.forEach((t=>{if("1"===t.isMainProject)return document.getElementById("mainProj").innerHTML=`\n\t\t\t\t\t\t${t.title} \n\t\t\t\t\t\t\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t
${t.information}
\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t`,null;document.querySelector("#otherProj div").innerHTML+=`\n \n
\n
\n
\n `}))}))}))}window.onscroll=()=>{document.body.scrollTop>=150||document.documentElement.scrollTop>=150?document.querySelector("nav").classList.add("scrolled"):document.querySelector("nav").classList.remove("scrolled");let t="";document.querySelectorAll("section").forEach((e=>{const n=e.offsetTop;window.pageYOffset>=n-60&&(t=e.getAttribute("id"))})),document.querySelectorAll("nav ul li a").forEach((e=>{e.classList.remove("active"),e.href.includes(t)&&""!==t?e.classList.add("active"):""===t&&document.querySelector("nav ul li a").classList.add("active")}))},document.addEventListener("DOMContentLoaded",(()=>{StartTextAnimation(0),getTimelineData(),getProjectData()})),document.querySelector("#contactError .close").addEventListener("click",(()=>document.querySelector("#contactError").classList.toggle("hidden"))),document.querySelector("#goBackToTop").addEventListener("click",(()=>{window.scrollTo(0,0)})),document.querySelector("#contactForm").addEventListener("submit",(t=>{t.preventDefault();let e=new FormData;e.append("fName",document.querySelector("#fName").value),e.append("lName",document.querySelector("#lName").value),e.append("email",document.querySelector("#email").value),e.append("subject",document.querySelector("#subject").value),e.append("message",document.querySelector("#message").value);let n=!1;if(["#fName","#lName","#email","#subject","#message"].forEach((t=>{const e=document.querySelector(t);0===e.value.length?(e.classList.add("invalid"),n=!0):(e.classList.remove("invalid"),document.querySelector("#contactError").classList.remove("error"))})),n)return document.querySelector("#contactError").classList.add("error"),document.querySelector("#contactError").classList.remove("hidden"),void(document.querySelector("#contactError div").innerText="Please fill out all fields.");fetch("/api/contact",{method:"POST",body:e}).then((t=>{t.ok&&(document.querySelector("#contactError").classList.remove("hidden"),document.querySelector("#contactError div").innerText="Thanks for contacting me, I will get back to you as soon as possible.")}))}));
\ No newline at end of file
diff --git a/src/api/index.php b/src/api/index.php
index fcd86b4..07fce1d 100644
--- a/src/api/index.php
+++ b/src/api/index.php
@@ -59,6 +59,139 @@ $app->get("/timelineData/{timeline}", function (Request $request, Response $resp
return $response->withStatus(404);
});
+$app->patch("/timelineData/{timeline}/{id}", function (Request $request, Response $response, array $args)
+{
+ global $timelineData;
+ $data = $request->getParsedBody();
+ if ($args["timeline"] == "edu" && $args["id"] != "undefined")
+ {
+ if (empty($data["dateFrom"]) || empty($data["dateTo"]) || empty($data["grade"]) || empty($data["course"]))
+ {
+ // uh oh sent some empty data
+ $response->getBody()->write(json_encode(array("error" => "Only some of the data was sent")));
+ return $response->withStatus(400);
+ }
+
+
+ if (!$timelineData->updateEduData($data["dateFrom"], $data["dateTo"], $data["grade"], $data["course"], $args["id"]))
+ {
+ // uh oh something went wrong
+ $response->getBody()->write(json_encode(array("error" => "Something went wrong")));
+ return $response->withStatus(500);
+ }
+
+ return $response->withStatus(200);
+ }
+
+ if ($args["timeline"] == "work" && $args["id"] != null)
+ {
+ if (empty($data["dateFrom"]) || empty($data["dateTo"]) || empty($data["companyName"]) || empty($data["area"]) || empty($data["title"]))
+ {
+ // uh oh sent some empty data
+ $response->getBody()->write(json_encode(array("error" => "Only some of the data was sent")));
+ return $response->withStatus(400);
+ }
+
+ if (!$timelineData->updateWorkData($data["dateFrom"], $data["dateTo"], $data["companyName"], $data["area"], $data["title"], $args["id"]))
+ {
+ // uh oh something went wrong
+ $response->getBody()->write(json_encode(array("error" => "Something went wrong")));
+ return $response->withStatus(500);
+ }
+
+ return $response->withStatus(200);
+ }
+
+ $response->getBody()->write(json_encode(array("error" => "The correct data was not sent")));
+ return $response->withStatus(400);
+});
+
+$app->delete("/timelineData/{timeline}/{id}", function (Request $request, Response $response, array $args)
+{
+ global $timelineData;
+ if ($args["timeline"] == "edu" && $args["id"] != null)
+ {
+ if (!$timelineData->deleteEduData($args["id"]))
+ {
+ // uh oh something went wrong
+ $response->getBody()->write(json_encode(array("error" => "Something went wrong")));
+ return $response->withStatus(500);
+ }
+
+ return $response->withStatus(200);
+ }
+
+ if ($args["timeline"] == "work" && $args["id"] != null)
+ {
+ if (!$timelineData->deleteWorkData($args["id"]))
+ {
+ // uh oh something went wrong
+ $response->getBody()->write(json_encode(array("error" => "Something went wrong")));
+ return $response->withStatus(500);
+ }
+
+ return $response->withStatus(200);
+ }
+
+ $response->getBody()->write(json_encode(array("error" => "The correct data was not sent")));
+ return $response->withStatus(400);
+});
+
+$app->post("/timelineData/{timeline}", function (Request $request, Response $response, array $args)
+{
+ global $timelineData;
+ $data = $request->getParsedBody();
+ if ($args["timeline"] == "edu")
+ {
+ if (empty($data["dateFrom"]) || empty($data["dateTo"]) || empty($data["grade"]) || empty($data["course"]))
+ {
+ // uh oh sent some empty data
+ $response->getBody()->write(json_encode(array("error" => "Only some of the data was sent")));
+ return $response->withStatus(400);
+ }
+
+ $insertedID = $timelineData->addEduData($data["dateFrom"], $data["dateTo"], $data["grade"], $data["course"]);
+ if (!is_int($insertedID))
+ {
+ // uh oh something went wrong
+ $response->getBody()->write(json_encode(array("error" => "Something went wrong")));
+ return $response->withStatus(500);
+ }
+
+ $response->getBody()->write(json_encode(array("ID" => $insertedID)));
+ return $response->withStatus(200);
+ }
+
+ if ($args["timeline"] == "work")
+ {
+ if (empty($data["dateFrom"]) || empty($data["companyName"]) || empty($data["area"]) || empty($data["title"]))
+ {
+ // uh oh sent some empty data
+ $response->getBody()->write(json_encode(array("error" => "Only some of the data was sent")));
+ return $response->withStatus(400);
+ }
+
+ if (empty($data["dateTo"]))
+ {
+ $data["dateTo"] = "";
+ }
+
+ $insertedID = $timelineData->addWorkData($data["dateFrom"], $data["dateTo"], $data["companyName"], $data["area"], $data["title"]);
+ if (!is_int($insertedID))
+ {
+ // uh oh something went wrong
+ $response->getBody()->write(json_encode(array("error" => "Something went wrong")));
+ return $response->withStatus(500);
+ }
+
+ $response->getBody()->write(json_encode(array("ID" => $insertedID)));
+ return $response->withStatus(200);
+ }
+
+ $response->getBody()->write(json_encode(array("error" => "The correct data was not sent")));
+ return $response->withStatus(400);
+});
+
$app->get("/projectData", function (Request $request, Response $response)
{
global $projectData;
@@ -373,39 +506,7 @@ $app->post("/user/changePassword", function (Request $request, Response $respons
return $response->withStatus(500);
});
-$app->patch("/timelineData/{timeline}/{id}", function (Request $request, Response $response, array $args)
-{
- global $timelineData;
- if ($args["timeline"] == "edu" && $args["id"] != "undefined")
- {
- $data = $request->getParsedBody();
- if (empty($data["dateFrom"]) || empty($data["dateTo"]) || empty($data["grade"]) || empty($data["course"]))
- {
- // uh oh sent some empty data
- $response->getBody()->write(json_encode(array("error" => "Only some of the data was sent")));
- return $response->withStatus(400);
- }
-
-
- if (!$timelineData->updateEduData($data["dateFrom"], $data["dateTo"], $data["grade"], $data["course"], $args["id"]))
- {
- // uh oh something went wrong
- $response->getBody()->write(json_encode(array("error" => "Something went wrong")));
- return $response->withStatus(500);
- }
-
- return $response->withStatus(200);
- }
-
- if ($args["timeline"] == "work" && $args["id"] != null)
- {
-
- return $response->withStatus(200);
- }
-
- $response->getBody()->write(json_encode(array("error" => "The correct data was not sent")));
- return $response->withStatus(400);
-});
+
diff --git a/src/api/timelineData.php b/src/api/timelineData.php
index 29f5cd5..fe62458 100644
--- a/src/api/timelineData.php
+++ b/src/api/timelineData.php
@@ -1,5 +1,7 @@
prepare("SELECT startPeriod, endPeriod, companyName, area, title FROM work ORDER BY work.startPeriod DESC;");
+ $stmt = $conn->prepare("SELECT ID, startPeriod, endPeriod, companyName, area, title FROM work ORDER BY work.startPeriod DESC;");
$stmt->execute();
// set the resulting array to associative
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
-
+
if ($result)
{
return $result;
@@ -71,4 +73,103 @@ class timelineData
return $stmt->execute();
}
+ /**
+ * Update work data
+ * @param string $dateFrom - Start date
+ * @param string $dateTo - End date
+ * @param string $companyName - Company name
+ * @param string $area - Area
+ * @param string $title - Title
+ * @param string $id - ID of the work data
+ * @return bool - True if successful, false if not
+ */
+ public function updateWorkData(string $dateFrom, string $dateTo, string $companyName, string $area, string $title, string $id): bool
+ {
+ $conn = dbConn();
+ $stmt = $conn->prepare("UPDATE work SET startPeriod = :dateFrom, endPeriod = :dateTo, companyName = :companyName, area = :area, title = :title WHERE ID = :id;");
+ $stmt->bindParam(":dateFrom", $dateFrom);
+ $stmt->bindParam(":dateTo", $dateTo);
+ $stmt->bindParam(":companyName", $companyName);
+ $stmt->bindParam(":area", $area);
+ $stmt->bindParam(":title", $title);
+ $stmt->bindParam(":id", $id);
+ return $stmt->execute();
+ }
+
+ /**
+ * Delete education data by ID
+ * @param int $id
+ * @return bool - True if successful, false if not
+ */
+ function deleteEduData(int $id): bool
+ {
+ $conn = dbConn();
+ $stmt = $conn->prepare("DELETE FROM edu WHERE ID = :id;");
+ $stmt->bindParam(":id", $id);
+ return $stmt->execute();
+ }
+
+ /**
+ * Delete work data by ID
+ * @param int $id
+ * @return bool - True if successful, false if not
+ */
+ function deleteWorkData(int $id): bool
+ {
+ $conn = dbConn();
+ $stmt = $conn->prepare("DELETE FROM work WHERE ID = :id;");
+ $stmt->bindParam(":id", $id);
+ return $stmt->execute();
+ }
+
+ /**
+ * Create new education data
+ * @param string $dateFrom - Start date
+ * @param string $dateTo - End date
+ * @param string $grade - Grade
+ * @param string $course - Course
+ * @return bool|int - ID of the new education data or false if not successful
+ */
+ function addEduData(string $dateFrom, string $dateTo, string $grade, string $course): bool|int
+ {
+ $conn = dbConn();
+ $stmt = $conn->prepare("INSERT INTO edu (startPeriod, endPeriod, grade, course) VALUES (:dateFrom, :dateTo, :grade, :course);");
+ $stmt->bindParam(":dateFrom", $dateFrom);
+ $stmt->bindParam(":dateTo", $dateTo);
+ $stmt->bindParam(":grade", $grade);
+ $stmt->bindParam(":course", $course);
+
+ if($stmt->execute())
+ {
+ return $conn->lastInsertId();
+ }
+ return false;
+ }
+
+ /**
+ * Create new work data
+ * @param string $dateFrom - Start date
+ * @param string $dateTo - End date
+ * @param string $companyName - Company name
+ * @param string $area - Area
+ * @param string $title - Title
+ * @return bool|int - ID of the new work data if successful, false if not
+ */
+ function addWorkData(string $dateFrom, string $dateTo, string $companyName, string $area, string $title): bool|int
+ {
+ $conn = dbConn();
+ $stmt = $conn->prepare("INSERT INTO work (startPeriod, endPeriod, companyName, area, title) VALUES (:dateFrom, :dateTo, :companyName, :area, :title);");
+ $stmt->bindParam(":dateFrom", $dateFrom);
+ $stmt->bindParam(":dateTo", $dateTo);
+ $stmt->bindParam(":companyName", $companyName);
+ $stmt->bindParam(":area", $area);
+ $stmt->bindParam(":title", $title);
+
+ if($stmt->execute())
+ {
+ return $conn->lastInsertId();
+ }
+ return false;
+ }
+
}
diff --git a/src/editor/css/editor.css b/src/editor/css/editor.css
index 2cc35cc..e2e1cd5 100644
--- a/src/editor/css/editor.css
+++ b/src/editor/css/editor.css
@@ -8,7 +8,7 @@ input[type="submit"] {
margin-top: 2em;
}
-.edit, .delete{
+.edit, .delete {
border: none;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
@@ -19,6 +19,10 @@ input[type="submit"] {
cursor: pointer;
}
+.timelineHeader {
+ font-weight: 400;
+}
+
div.editorContainer {
display: flex;
flex-direction: row;
@@ -40,10 +44,10 @@ div.modifyBtnContainer {
margin-bottom: 0.5em;
}
-div.dateContainer {
+div.dateContainer, div.companyAreaContainer {
display: flex;
flex-direction: row;
- justify-content: center;
+ justify-content: flex-start;
align-items: center;
gap: 1em;
margin-bottom: 0.5em;
@@ -103,20 +107,32 @@ section#curriculumVitae form.timelineItem.editing div.gradeContainer.formControl
}
section#curriculumVitae form.timelineItem:not(.editing) div.gradeContainer.formControl input,
-section#curriculumVitae form.timelineItem:not(.editing) .formControl .courseText {
+section#curriculumVitae form.timelineItem:not(.editing) div.companyAreaContainer.formControl input,
+section#curriculumVitae form.timelineItem:not(.editing) .formControl .courseText,
+section#curriculumVitae form.timelineItem:not(.editing) .formControl .jobTitleText {
outline: none;
border: none;
- color: #FFFFFF;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
}
+section#curriculumVitae form.timelineItem:not(.editing) div.gradeContainer.formControl > *,
+section#curriculumVitae form.timelineItem:not(.editing) div.companyAreaContainer.formControl > * {
+ color: hsl(0, 0%, 90%);
+}
+
+section#curriculumVitae form.timelineItem:not(.editing) .formControl .courseText,
+section#curriculumVitae form.timelineItem:not(.editing) .formControl .jobTitleText {
+ color: #FFFFFF;
+}
+
section#curriculumVitae form.timelineItem:not(.editing) div.gradeContainer.formControl input {
padding: 0 0.25em;
}
-section#curriculumVitae form.timelineItem:not(.editing) div.formControl .courseText {
+section#curriculumVitae form.timelineItem:not(.editing) div.formControl .courseText,
+section#curriculumVitae form.timelineItem:not(.editing) .formControl .courseText {
padding: 0;
}
@@ -126,4 +142,8 @@ section#curriculumVitae form.timelineItem:not(.editing) input[type=submit] {
.courseText {
resize: none;
-}
\ No newline at end of file
+}
+
+section#curriculumVitae form.timelineItem:not(.editing) div.companyAreaContainer input {
+ width: 30%;
+}
diff --git a/src/editor/editor.html b/src/editor/editor.html
index 97cd409..37d1c5c 100644
--- a/src/editor/editor.html
+++ b/src/editor/editor.html
@@ -24,20 +24,19 @@
curriculum vitae
-
Education
diff --git a/src/editor/js/editor.js b/src/editor/js/editor.js
index d95dd0d..89ea773 100644
--- a/src/editor/js/editor.js
+++ b/src/editor/js/editor.js
@@ -1,15 +1,17 @@
let dateOptions = {month: 'short', year: 'numeric'};
+
document.addEventListener('DOMContentLoaded', () =>
{
// check if the user is logged in, if not redirect to log in
- /* fetch('/api/user/isLoggedIn').then(res =>
+ fetch('/api/user/isLoggedIn').then(res =>
{
if (!res.ok)
{
window.location.href = './';
}
- });*/
- document.querySelector("#dateFrom").max = new Date().toISOString().split("T")[0];
+ });
+ document.querySelector("#dateFromE").max = new Date().toISOString().split("T")[0];
+ document.querySelector("#dateFromW").max = new Date().toISOString().split("T")[0];
fetch("/api/timelineData/edu").then(res =>
@@ -20,37 +22,24 @@ document.addEventListener('DOMContentLoaded', () =>
{
for (let i = 0; i < json.length; i++)
{
- let id = json[i].ID;
- let timelineItem = document.createElement("form")
- timelineItem.id = "timelineItem" + id;
- timelineItem.classList.add("timelineItem");
- timelineItem.onsubmit = e => updateEduItem(id, e);
- timelineItem.innerHTML = `
-
-
-
-
-
-
- -
-
-
-
-
- Grade:
-
-
-
- ${json[i]['course']}
-
-
-
-
- `;
- document.getElementById("edu").appendChild(timelineItem);
+ addEduData(json[i].ID, json[i].startPeriod, json[i].endPeriod, json[i].grade, json[i].course);
+ }
+ return;
+ }
+ document.querySelector("#edu").innerHTML = "No education data found";
+ })
+ });
+
+ fetch("/api/timelineData/work").then(res =>
+ {
+ res.json().then(json =>
+ {
+ if (res.ok)
+ {
+ for (let i = 0; i < json.length; i++)
+ {
+ let endPeriod = json[i].endPeriod === null ? "Present" : json[i].endPeriod;
+ addWorkData(json[i].ID, json[i].startPeriod, endPeriod, json[i].companyName, json[i].area, json[i].title);
}
return;
}
@@ -73,6 +62,79 @@ document.querySelector("#navClose").addEventListener("click", () =>
document.querySelector("#navOpen").style.visibility = "visible";
});
+document.querySelector("#addEdu").addEventListener("submit", e =>
+{
+ e.preventDefault();
+ let data = new FormData();
+ data.append("dateFrom", document.querySelector("#dateFromE").value);
+ data.append("dateTo", document.querySelector("#dateToE").value);
+ data.append("grade", document.querySelector("#grade").value);
+ data.append("course", document.querySelector("#courseTitle").value);
+
+ fetch("/api/timelineData/edu", {
+ method: "POST",
+ body: data,
+ headers: {
+ "Authentication": localStorage.getItem("token")
+ }
+ }).then(res => res.json().then(json =>
+ {
+ if (res.ok)
+ {
+ addEduData(json.ID, data.get("dateFrom"), data.get("dateTo"), data.get("grade"), data.get("course"), true);
+ document.querySelector("#addEdu").reset();
+ return;
+ }
+
+ if (res.status === 401)
+ {
+ window.location.href = "./";
+ return;
+ }
+
+ document.querySelector("#eduError").classList.remove("hidden");
+ document.querySelector("#eduError div").innerHTML = json.error;
+ }));
+});
+
+document.querySelector("#addWork").addEventListener("submit", e =>
+{
+ e.preventDefault();
+ let data = new FormData();
+ data.append("dateFrom", document.querySelector("#dateFromW").value);
+ data.append("dateTo", document.querySelector("#dateToW").value);
+ data.append("companyName", document.querySelector("#company").value);
+ data.append("area", document.querySelector("#area").value);
+ data.append("title", document.querySelector("#jobTitle").value);
+
+ fetch("/api/timelineData/work", {
+ method: "POST",
+ body: data,
+ headers: {
+ "Authentication": localStorage.getItem("token")
+ }
+ }).then(res => res.json().then(json =>
+ {
+ if (res.ok)
+ {
+ let endPeriod = data.get("dateTo") === null ? "Present" : data.get("dateTo ");
+ addWorkData(json.ID, data.get("dateFrom"), endPeriod, data.get("companyName"), data.get("area"), data.get("title"), true);
+ document.querySelector("#addEdu").reset();
+ return;
+ }
+
+ if (res.status === 401)
+ {
+ window.location.href = "./";
+ return;
+ }
+
+ document.querySelector("#eduError").classList.remove("hidden");
+ document.querySelector("#eduError div").innerHTML = json.error;
+ }));
+});
+
+
/**
* Switches the timeline item between edit and view mode
* @param id the id of the timeline item
@@ -80,19 +142,131 @@ document.querySelector("#navClose").addEventListener("click", () =>
function edit(id)
{
document.querySelector("#timelineItem" + id).classList.toggle("editing");
- document.querySelector("#grade" + id).toggleAttribute("disabled");
- document.querySelector("#course" + id).toggleAttribute("disabled");
+ if (id.includes("e"))
+ {
+ document.querySelector("#grade" + id).toggleAttribute("disabled");
+ document.querySelector("#course" + id).toggleAttribute("disabled");
+ return;
+ }
+ document.querySelector("#companyName" + id).toggleAttribute("disabled");
+ document.querySelector("#area" + id).toggleAttribute("disabled");
+ document.querySelector("#jobTitle" + id).toggleAttribute("disabled");
}
+/**
+ * Updates the education timeline item with the given id
+ * @param ID - the id of the course timeline item
+ * @param startPeriod - the start date of the course
+ * @param endPeriod - the end date of the course
+ * @param grade - the grade of the course
+ * @param course - the name of the course
+ * @param prepend - whether to prepend the timeline item to the timeline
+ */
+function addEduData(ID, startPeriod, endPeriod, grade, course, prepend=false)
+{
+ let id = ID + "e";
+ let timelineItem = document.createElement("form")
+ timelineItem.id = "timelineItem" + id;
+ timelineItem.classList.add("timelineItem");
+ timelineItem.onsubmit = e => updateEduItem(ID, e);
+ timelineItem.innerHTML = `
+
+
+
+
+
+
+ -
+
+
+
+
+ Grade:
+
+
+
+ ${course}
+
+
+
+
+ `;
+ if (prepend)
+ {
+ document.querySelector("#edu").prepend(timelineItem);
+ return;
+ }
+ document.getElementById("edu").appendChild(timelineItem);
+}
+
+/**
+ * Adds a new work timeline item to the page
+ * @param ID - the id of the work timeline item
+ * @param startPeriod - the start date of the job
+ * @param endPeriod - the end date of the job
+ * @param companyName - the name of the company
+ * @param area - the area of the company
+ * @param jobTitle - the job title
+ * @param prepend - whether to prepend the timeline item to the timeline
+ */
+function addWorkData(ID, startPeriod, endPeriod, companyName, area, jobTitle, prepend=false)
+{
+ let id = ID + "w";
+ let timelineItem = document.createElement("form")
+ timelineItem.id = "timelineItem" + id;
+ timelineItem.classList.add("timelineItem");
+ timelineItem.onsubmit = e => updateWorkItem(ID, e);
+ timelineItem.innerHTML = `
+
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+ ${jobTitle}
+
+
+
+
+ `;
+ if (prepend)
+ {
+ document.querySelector("#work").prepend(timelineItem);
+ return;
+ }
+
+ document.getElementById("work").appendChild(timelineItem);
+}
+
+/**
+ * Updates the edu timeline item with the given id
+ * @param id the id of the edu timeline item
+ * @param e the event that triggered the function
+ */
function updateEduItem(id, e)
{
e.preventDefault();
-
let data = {}
- data["dateFrom"] = document.querySelector("#dateFrom" + id).value;
- data["dateTo"] = document.querySelector("#dateTo" + id).value;
- data["grade"] = document.querySelector("#grade" + id).value;
- data["course"] = document.querySelector("#course" + id).value;
+ data["dateFrom"] = document.querySelector(`#dateFrom${id}e`).value;
+ data["dateTo"] = document.querySelector(`#dateTo${id}e`).value;
+ data["grade"] = document.querySelector(`#grade${id}e`).value;
+ data["course"] = document.querySelector(`#course${id}e`).value;
fetch("/api/timelineData/edu/" + id, {
method: "PATCH",
@@ -105,10 +279,10 @@ function updateEduItem(id, e)
{
if (res.ok)
{
- document.querySelector("#timelineHeader" + id).innerHTML = new Date(document.querySelector("#dateFrom" + id).value).toLocaleString('en-gb', dateOptions) + " - " + new Date(document.querySelector("#dateTo" + id).value).toLocaleString('en-gb', dateOptions);
- document.querySelector("#timelineItem" + id).classList.toggle("editing");
- document.querySelector("#grade" + id).setAttribute("disabled", "");
- document.querySelector("#course" + id).setAttribute("disabled", "");
+ document.querySelector(`#timelineHeader${id}e`).innerHTML = new Date(document.querySelector(`#dateFrom${id}e`).value).toLocaleString('en-gb', dateOptions) + " - " + new Date(document.querySelector(`#dateTo${id}e`).value).toLocaleString('en-gb', dateOptions);
+ document.querySelector(`#timelineItem${id}e`).classList.toggle("editing");
+ document.querySelector(`#grade${id}e`).setAttribute("disabled", "");
+ document.querySelector(`#course${id}e`).setAttribute("disabled", "");
return;
}
@@ -120,9 +294,114 @@ function updateEduItem(id, e)
res.json().then(json =>
{
- document.querySelector("#eduError" + id).classList.remove("hidden");
- document.querySelector(`#eduError${id} div`).innerHTML = json.error;
+ document.querySelector(`#eduError${id}e`).classList.remove("hidden");
+ document.querySelector(`#eduError${id}e div`).innerHTML = json.error;
});
})
-}
\ No newline at end of file
+}
+
+/**
+ * Updates the work timeline item with the given id
+ * @param id the id of the work timeline item
+ * @param e the event that triggered the function
+ */
+function updateWorkItem(id, e)
+{
+ e.preventDefault();
+ let data = {}
+ data["dateFrom"] = document.querySelector(`#dateFrom${id}w`).value;
+ data["dateTo"] = document.querySelector(`#dateTo${id}w`).value;
+ data["companyName"] = document.querySelector(`#companyName${id}w`).value;
+ data["area"] = document.querySelector(`#area${id}w`).value;
+ data["title"] = document.querySelector(`#jobTitle${id}w`).value;
+
+ fetch("/api/timelineData/work/" + id, {
+ method: "PATCH",
+ body: JSON.stringify(data),
+ headers: {
+ "Content-Type": "application/json",
+ "Authorization": "Bearer " + localStorage.getItem("token")
+ }
+ }).then(res =>
+ {
+ if(res.ok)
+ {
+ document.querySelector(`#timelineHeader${id}w`).innerHTML = new Date(document.querySelector(`#dateFrom${id}w`).value).toLocaleString('en-gb', dateOptions) + " - " + new Date(document.querySelector(`#dateTo${id}w`).value).toLocaleString('en-gb', dateOptions);
+ document.querySelector(`#timelineItem${id}w`).classList.toggle("editing");
+ document.querySelector(`#companyName${id}w`).setAttribute("disabled", "");
+ document.querySelector(`#area${id}w`).setAttribute("disabled", "");
+ document.querySelector(`#jobTitle${id}w`).setAttribute("disabled", "");
+ return;
+ }
+
+ if (res.status === 401)
+ {
+ window.location.href = "./";
+ return;
+ }
+
+ res.json().then(json =>
+ {
+ document.querySelector(`#workError${id}w`).classList.remove("hidden");
+ document.querySelector(`#workError${id}w div`).innerHTML = json.error;
+ });
+ });
+}
+
+/**
+ * Deletes the timeline item with the given id
+ * @param id the id of the timeline item
+ */
+function deleteEduItem(id)
+{
+ fetch("/api/timelineData/edu/" + id, {
+ method: "DELETE",
+ headers: {
+ "Authorization": "Bearer " + localStorage.getItem("token")
+ }
+ }).then(res =>
+ {
+ if (res.ok)
+ {
+ document.querySelector(`#timelineItem${id}e`).remove();
+ return;
+ }
+
+ if (res.status === 401)
+ {
+ window.location.href = "./";
+ return;
+ }
+ res.json().then(json => alert(json.error));
+ });
+}
+
+/**
+ * Updates the timeline item with the given id
+ * @param id the id of the timeline item
+ */
+function deleteWorkItem(id)
+{
+ fetch("/api/timelineData/work/" + id, {
+ method: "DELETE",
+ headers: {
+ "Authorization": "Bearer " + localStorage.getItem("token")
+ }
+ }).then(res =>
+ {
+ if (res.ok)
+ {
+ document.querySelector(`#timelineItem${id}w`).remove();
+ return;
+ }
+
+ if (res.status === 401)
+ {
+ window.location.href = "./";
+ return;
+ }
+ res.json().then(json => alert(json.error));
+
+ });
+}
diff --git a/src/js/main.js b/src/js/main.js
index 5026466..cbff7e6 100644
--- a/src/js/main.js
+++ b/src/js/main.js
@@ -139,8 +139,9 @@ function getTimelineData()
{
let timelineItem = document.createElement("div")
timelineItem.classList.add("timelineItem");
+ let endPeriod = item["endPeriod"] === null ? "Present" : new Date(item["endPeriod"]).toLocaleString('en-gb', dateOptions);
timelineItem.innerHTML = `
-
+
${item["companyName"]} - ${item["area"]}
${item["title"]}
`;