Skip to content

Commit df55239

Browse files
committed
client(LinePopup.tsx): added full form validation
1 parent 9ca5bd3 commit df55239

File tree

4 files changed

+46
-35
lines changed

4 files changed

+46
-35
lines changed

client/src/components/buttons/GreenButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const GreenButton: FC<GreenButtonProps> = (props) => {
1919
px-3 py-2 text-sm font-semibold transition-all
2020
${
2121
props.disabled
22-
? "text-gh-text border-gh-green"
22+
? "text-gh-text border-gh-green-dark bg-gh-green-dark"
2323
: "hover:bg-gh-green-active text-white border-gh-green-active"
2424
}`}
2525
>

client/src/components/input/LineInput.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ const LineInput: FC<InputProps> = (props) => {
5252

5353
return (
5454
<div className={`${props.className} w-full flex flex-col gap-1 text-sm`}>
55-
<BlurOverlay isActive={isPopupOpen} />
55+
<BlurOverlay
56+
isActive={isPopupOpen}
57+
closePopup={() => setIsPopupOpen(false)}
58+
/>
5659

5760
<LinePopup
5861
addBadge={addBadge}
@@ -62,7 +65,7 @@ const LineInput: FC<InputProps> = (props) => {
6265
/>
6366

6467
<span className="text-sm text-gh-text-secondary font-semibold w-fit">
65-
Line {props.line}:
68+
Line {props.line}
6669
</span>
6770

6871
<div
@@ -114,15 +117,14 @@ const LineInput: FC<InputProps> = (props) => {
114117
hover:border-gh-red transition-all duration-150"
115118
>
116119
<div className="text-gh-text-secondary">
117-
{/* <FaGithub /> */}
118120
<img
119121
className="w-4 h-4"
120122
src={`https://cdn.simpleicons.org/${badge.iconName}/${
121123
badge.color === "auto"
122124
? ""
123125
: badge.color.replace("#", "")
124126
}`}
125-
alt="alt"
127+
alt=""
126128
/>
127129
</div>
128130

client/src/components/popups/LinePopup.tsx

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FC, useEffect, useState } from "react";
1+
import { FC, useState } from "react";
22
import { Badge } from "../../types/line";
33
import GreenButton from "../buttons/GreenButton";
44
import { FiSave } from "react-icons/fi";
@@ -13,32 +13,34 @@ interface LinePopupProps {
1313
}
1414

1515
const LinePopup: FC<LinePopupProps> = (props) => {
16-
const [icon, setIcon] = useState<string>("");
17-
const [label, setLabel] = useState<string>("");
18-
const [color, setColor] = useState<string>("");
19-
20-
const [errorMsg, setErrorMsg] = useState<string | undefined>(
21-
"Please fill in all fields."
22-
);
23-
24-
useEffect(() => {
25-
if (icon.trim().length < 3) {
26-
setErrorMsg("The icon name should be greater than 2 characters.");
27-
return;
16+
const [icon, setIcon] = useState<string>("react");
17+
const [label, setLabel] = useState<string>("react");
18+
const [color, setColor] = useState<string>("#3498db");
19+
20+
const validateIconAndLabel = (
21+
val: string,
22+
iorl: "icon" | "label"
23+
): string => {
24+
if (val.length < 3 || val.length > 32) {
25+
return `The ${iorl} should be between 2 and 32 characters.`;
2826
}
2927

30-
if (label.trim().length < 3) {
31-
setErrorMsg("The label name should be greater than 2 characters.");
32-
return;
28+
return "";
29+
};
30+
31+
const validateHex = (val: string): string => {
32+
if (val === "auto") {
33+
return "";
3334
}
3435

35-
if (color.trim().length < 4) {
36-
setErrorMsg("Please provide a color.");
37-
return;
36+
// starts with #, 3 or 6 characters long, contains only hexadecimal values
37+
const hexColorRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
38+
if (!hexColorRegex.test(val)) {
39+
return "The color should be a valid hexadecimal color or the value auto.";
3840
}
3941

40-
setErrorMsg(undefined);
41-
}, [icon, label, color]);
42+
return "";
43+
};
4244

4345
const handleSave = () => {
4446
props.addBadge({
@@ -52,9 +54,9 @@ const LinePopup: FC<LinePopupProps> = (props) => {
5254

5355
const handleCancel = () => {
5456
props.closePopup();
55-
setIcon("");
56-
setLabel("");
57-
setColor("");
57+
setIcon("react");
58+
setLabel("react");
59+
setColor("#3498db");
5860
};
5961

6062
const activeClasses = "opacity-100 pointer-events-auto scale-100";
@@ -63,7 +65,7 @@ const LinePopup: FC<LinePopupProps> = (props) => {
6365
return (
6466
<div
6567
className={`border border-solid border-gh-border rounded-md bg-gh-bg-secondary
66-
shadow-lg left-1/2 z-30 -translate-x-1/2 -translate-y-1/2
68+
shadow-3xl left-1/2 z-30 -translate-x-1/2 -translate-y-1/2
6769
transition-all duration-150 fixed top-1/2 max-h-[95vh] overflow-y-auto w-[95%]
6870
sm:w-[60%] md:w-[50%] lg:w-[40%] ${
6971
props.isActive ? activeClasses : inactiveClasses
@@ -73,7 +75,7 @@ const LinePopup: FC<LinePopupProps> = (props) => {
7375
className="border-b border-solid border-gh-border px-4
7476
py-2 font-semibold text-lg text-gh-text"
7577
>
76-
Line #{props.lineNumber}: Add badge
78+
Line {props.lineNumber}: Add badge
7779
</div>
7880

7981
<div className="flex flex-col gap-3 my-3 px-6">
@@ -82,7 +84,7 @@ const LinePopup: FC<LinePopupProps> = (props) => {
8284
placeholder="react"
8385
value={icon}
8486
setValue={(val: string) => setIcon(val)}
85-
validate={() => ""}
87+
validate={(val) => validateIconAndLabel(val, "icon")}
8688
helperText="You can browse between the icons here: https://simpleicons.org/"
8789
/>
8890

@@ -93,7 +95,7 @@ const LinePopup: FC<LinePopupProps> = (props) => {
9395
placeholder="react"
9496
value={label}
9597
setValue={(val: string) => setLabel(val)}
96-
validate={() => ""}
98+
validate={(val) => validateIconAndLabel(val, "label")}
9799
/>
98100

99101
<div className="w-[95%] h-[.8px] bg-gh-border mx-auto" />
@@ -103,7 +105,7 @@ const LinePopup: FC<LinePopupProps> = (props) => {
103105
placeholder="#3498db"
104106
value={color}
105107
setValue={(val: string) => setColor(val)}
106-
validate={() => ""}
108+
validate={(val) => validateHex(val)}
107109
helperText="The badge color is either a hexadecimal color code or the value auto."
108110
/>
109111
</div>
@@ -114,7 +116,13 @@ const LinePopup: FC<LinePopupProps> = (props) => {
114116
icon={FiSave}
115117
onClick={handleSave}
116118
text="Save"
117-
disabled={errorMsg !== undefined}
119+
disabled={
120+
!(
121+
validateHex(color) === "" &&
122+
validateIconAndLabel(icon, "icon") === "" &&
123+
validateIconAndLabel(label, "label") === ""
124+
)
125+
}
118126
/>
119127

120128
<SecondaryButton onClick={handleCancel} text="Cancel" />

client/tailwind.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ module.exports = {
1919
"gh-red-active": "#F78166",
2020
"gh-green": "#238636",
2121
"gh-green-active": "#2EA043",
22+
"gh-green-dark": "#1b752b",
2223
"gh-border": "#30363D",
2324
white: "#fff",
2425
black: "#000",

0 commit comments

Comments
 (0)