Skip to content

Commit 46d6d89

Browse files
committed
refactor(Options.tsx): remove the states and replace them with a single one that stores an object
1 parent e649931 commit 46d6d89

File tree

7 files changed

+132
-140
lines changed

7 files changed

+132
-140
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ None of the fields are required. Every query parameter has a default value displ
5454
| Parameter | Example | Default value | Description|
5555
|---------- |---------|---------------|------------|
5656
| **title** | `?title=My%20Title` | My Tech Stack | The title of the card. %20 can be used as a space. |
57-
| **theme** | `?theme=github_dark` | github | The theme of the card. You can browse between the themes [here](#-themes). |
57+
| **theme** | `?theme=github_dark` | github | The theme of the card. You can browse between the themes [here](docs/THEMES.md). |
5858
| **align** | `?align=center` | left | The alignment of the badges. (`left`, `center`, `right`) |
5959
| **showBorder** | `?showBorder=false` | true | Display the border around the card or not. (`true`, `false`) |
6060
| **borderRadius** | `?borderRadius=12.5` | 4.5 | Value between 0 and 50. |

client/src/components/input/LineInput.tsx

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,38 @@
11
import { FC, useState } from "react";
2-
import { Badge, Line } from "../../types/line";
2+
import { Badge, Line } from "../../types/card";
33
import { AiOutlinePlus } from "react-icons/ai";
44
import BlurOverlay from "../popups/BlurOverlay";
55
import LinePopup from "../popups/LinePopup";
66
import HoverText from "../hover/HoverText";
77
import { AiOutlineQuestionCircle } from "react-icons/ai";
88

99
interface InputProps {
10-
line: string;
10+
line: Line;
1111
updateLine: (line: Line) => void;
1212
className?: string;
1313
}
1414

1515
const LineInput: FC<InputProps> = (props) => {
16-
const [badges, setBadges] = useState<Badge[]>([]);
1716
const [isPopupOpen, setIsPopupOpen] = useState<boolean>(false);
1817

1918
const addBadge = (badge: Badge) => {
2019
props.updateLine({
21-
badges: [...badges, badge],
22-
lineNumber: props.line,
20+
badges: [...props.line.badges, badge],
21+
lineNumber: props.line.lineNumber,
2322
});
24-
25-
setBadges((prev) => [...prev, badge]);
2623
};
2724

2825
const removeBadge = (badge: Badge) => {
29-
setBadges((prev) =>
30-
[...prev].filter(
31-
(b) =>
32-
!(
33-
b.color === badge.color &&
34-
b.iconName === badge.iconName &&
35-
b.label === badge.label
36-
)
37-
)
38-
);
39-
4026
props.updateLine({
41-
badges: [...badges].filter(
27+
lineNumber: props.line.lineNumber,
28+
badges: [...props.line.badges].filter(
4229
(b) =>
4330
!(
4431
b.color === badge.color &&
4532
b.iconName === badge.iconName &&
4633
b.label === badge.label
4734
)
4835
),
49-
lineNumber: props.line,
5036
});
5137
};
5238

@@ -60,12 +46,12 @@ const LineInput: FC<InputProps> = (props) => {
6046
<LinePopup
6147
addBadge={addBadge}
6248
isActive={isPopupOpen}
63-
lineNumber={props.line}
49+
lineNumber={props.line.lineNumber}
6450
closePopup={() => setIsPopupOpen(false)}
6551
/>
6652

6753
<span className="text-sm text-gh-text-secondary font-semibold w-fit">
68-
Line {props.line}
54+
Line {props.line.lineNumber}
6955
</span>
7056

7157
<div
@@ -76,7 +62,9 @@ const LineInput: FC<InputProps> = (props) => {
7662
className="flex items-center justify-between border-b
7763
border-solid border-gh-border px-3 py-2 gap-2"
7864
>
79-
<span className="font-semibold">Badges: {badges.length}</span>
65+
<span className="font-semibold">
66+
Badges: {props.line.badges.length}
67+
</span>
8068

8169
<HoverText label="Click the badge to remove it" className="ml-auto">
8270
<div
@@ -100,15 +88,15 @@ const LineInput: FC<InputProps> = (props) => {
10088
</HoverText>
10189
</div>
10290

103-
{badges.length < 1 && (
91+
{props.line.badges.length < 1 && (
10492
<div className="text-gh-text-secondary italic px-4 py-2">
10593
There are no badges selected. 🥱
10694
</div>
10795
)}
10896

109-
{badges.length > 0 && (
97+
{props.line.badges.length > 0 && (
11098
<div className="flex items-center gap-3 p-2 overflow-hidden flex-wrap">
111-
{badges.map((badge) => {
99+
{props.line.badges.map((badge) => {
112100
return (
113101
<div
114102
key={`${badge.iconName}-${Math.random()}`}

client/src/components/popups/LinePopup.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { FC, useState } from "react";
2-
import { Badge } from "../../types/line";
2+
import { Badge } from "../../types/card";
33
import GreenButton from "../buttons/GreenButton";
44
import { FiSave } from "react-icons/fi";
55
import SecondaryButton from "../buttons/SecondaryButton";

client/src/pages/Options.tsx

Lines changed: 64 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { VscSettings } from "react-icons/vsc";
33
import { IoHammerOutline } from "react-icons/io5";
44
import SelectInput from "../components/input/SelectInput";
55
import GreenButton from "../components/buttons/GreenButton";
6-
import { FC, useCallback, useEffect, useState } from "react";
6+
import { FC, useCallback, useState } from "react";
77
import LineInput from "../components/input/LineInput";
8-
import { Line } from "../types/line";
8+
import { Card, Line, newCard } from "../types/card";
99
import { generateLink } from "../utils/generate";
1010
import { useFetchThemes } from "../hooks/useFetchThemes";
1111
import NumberInput from "../components/input/NumberInput";
@@ -19,66 +19,43 @@ interface OptionsProps {
1919

2020
const Options: FC<OptionsProps> = (props) => {
2121
const themes = useFetchThemes();
22-
const [lineChars, setLineChars] = useState(["1"]);
23-
24-
const [title, setTitle] = useState<string>("My Tech Stack");
25-
const [lineCount, setLineCount] = useState<string>("1");
26-
const [theme, setTheme] = useState<string>("github");
27-
const [align, setAlign] = useState<string>("left");
28-
const [lines, setLines] = useState<Line[]>([]);
29-
const [showBorder, setShowBorder] = useState(true);
30-
const [borderRadius, setBorderRadius] = useState<string>("4.5");
31-
const [fontWeight, setFontWeight] = useState<string>("semibold");
32-
const [fontSize, setFontSize] = useState<string>("18");
33-
34-
useEffect(() => {
35-
// create an array with the numbers of lineCount to 1
36-
const res: string[] = [];
37-
for (let i = 1; i <= Number(lineCount); i++) {
38-
res.push(`${i}`);
39-
setLines((prev) => [
40-
...prev,
41-
{
42-
badges: [],
43-
lineNumber: `${i}`,
44-
},
45-
]);
46-
}
47-
setLineChars(res);
48-
}, [lineCount, setLineCount, setLines]);
49-
50-
const reset = () => {
51-
setTitle("My Tech Stack");
52-
setLineCount("1");
53-
setTheme("github");
54-
setAlign("left");
55-
setShowBorder(true);
56-
setLines([]);
57-
setBorderRadius("4.5");
58-
setFontSize("18");
59-
setFontWeight("semibold");
60-
};
22+
const [card, setCard] = useState<Card>(newCard());
6123

62-
const updateLine = useCallback(
63-
(line: Line) => {
64-
setLines((prev) => {
65-
const res: Line[] = [];
24+
const updateLineCount = useCallback(
25+
(lineNumber: number) => {
26+
// storing just the line numbers in an array
27+
const lineNums: number[] = card.lines.map((x) => Number(x.lineNumber));
6628

67-
for (const l of [...prev]) {
68-
if (l.lineNumber === line.lineNumber) {
69-
res.push(line);
70-
continue;
71-
}
29+
// variable to store the result
30+
const updated: Line[] = [];
7231

73-
res.push(l);
32+
for (let i = 1; i <= lineNumber; i++) {
33+
// if the card.lines contain line with this lineNumber
34+
if (lineNums.includes(i)) {
35+
updated.push(card.lines.filter((x) => x.lineNumber === `${i}`)[0]);
36+
continue;
7437
}
7538

76-
return res;
77-
});
39+
// else push a new one
40+
updated.push({
41+
badges: [],
42+
lineNumber: `${i}`,
43+
});
44+
}
45+
46+
setCard({ ...card, lines: updated });
7847
},
79-
[setLines]
48+
[card]
8049
);
8150

51+
const updateLine = (line: Line) => {
52+
const lines = [...card.lines];
53+
54+
lines[lines.findIndex((l) => l.lineNumber === line.lineNumber)] = line;
55+
56+
setCard({ ...card, lines: lines });
57+
};
58+
8259
const validateBorderRadius = (val: string): string => {
8360
const num = parseInt(val);
8461

@@ -108,40 +85,44 @@ const Options: FC<OptionsProps> = (props) => {
10885
<Input
10986
label="Title"
11087
placeholder="My Tech Stack"
111-
value={title}
112-
setValue={(val) => setTitle(val)}
88+
value={card.title}
89+
setValue={(v) => setCard({ ...card, title: v, lines: card.lines })}
11390
validate={() => ""}
11491
/>
11592

11693
<div className="flex items-center gap-4">
11794
<SelectInput
11895
label="Theme"
11996
options={themes}
120-
value={theme}
121-
setValue={setTheme}
97+
value={card.theme}
98+
setValue={(v) => setCard({ ...card, theme: v, lines: card.lines })}
12299
searchField={true}
123100
/>
124101

125102
<SelectInput
126103
label="Badge Align"
127104
options={["left", "center", "right"]}
128-
value={align}
129-
setValue={(val) => setAlign(val)}
105+
value={card.align}
106+
setValue={(v) => setCard({ ...card, align: v, lines: card.lines })}
130107
/>
131108
</div>
132109

133110
<div className="flex items-start gap-4">
134111
<SelectInput
135112
label="Font Weight"
136113
options={["thin", "normal", "semibold", "bold"]}
137-
value={fontWeight}
138-
setValue={(val) => setFontWeight(val)}
114+
value={card.fontWeight}
115+
setValue={(v) =>
116+
setCard({ ...card, fontWeight: v, lines: card.lines })
117+
}
139118
/>
140119

141120
<NumberInput
142121
label="Font Size"
143-
value={fontSize}
144-
setValue={(val) => setFontSize(val)}
122+
value={card.fontSize}
123+
setValue={(v) =>
124+
setCard({ ...card, fontSize: v, lines: card.lines })
125+
}
145126
minValue={15}
146127
maxValue={30}
147128
/>
@@ -150,23 +131,27 @@ const Options: FC<OptionsProps> = (props) => {
150131
<Input
151132
label="Border Radius"
152133
placeholder="4.5"
153-
value={borderRadius}
154-
setValue={(val) => setBorderRadius(val)}
134+
value={card.borderRadius}
135+
setValue={(v) =>
136+
setCard({ ...card, borderRadius: v, lines: card.lines })
137+
}
155138
helperText="A number between 0 and 50."
156139
validate={(val) => validateBorderRadius(val)}
157140
/>
158141

159142
<div className="flex items-start gap-4">
160143
<TrueFalseInput
161144
label="Border"
162-
setValue={(val) => setShowBorder(val)}
163-
value={showBorder}
145+
value={card.showBorder}
146+
setValue={(v) =>
147+
setCard({ ...card, showBorder: v, lines: card.lines })
148+
}
164149
/>
165150

166151
<NumberInput
167152
label="Lines"
168-
value={lineCount}
169-
setValue={(val) => setLineCount(val)}
153+
value={`${card.lines.length}`}
154+
setValue={(v) => updateLineCount(Number(v))}
170155
minValue={1}
171156
maxValue={5}
172157
/>
@@ -176,36 +161,26 @@ const Options: FC<OptionsProps> = (props) => {
176161
<div className="my-4 flex flex-col gap-4 px-4">
177162
<div className="w-full h-[.8px] bg-gh-border mx-auto" />
178163

179-
{lineChars.map((line) => (
180-
<LineInput line={line} updateLine={updateLine} key={line} />
164+
{card.lines.map((line) => (
165+
<LineInput
166+
line={line}
167+
updateLine={updateLine}
168+
key={line.lineNumber}
169+
/>
181170
))}
182171

183172
<div className="w-full h-[.8px] bg-gh-border mx-auto" />
184173

185174
<div className="flex items-stretch gap-3">
186175
<GreenButton
187176
icon={IoHammerOutline}
188-
onClick={() => {
189-
props.setLink(
190-
generateLink(
191-
title,
192-
lineCount,
193-
theme,
194-
align,
195-
lines,
196-
showBorder,
197-
borderRadius,
198-
fontWeight,
199-
fontSize
200-
)
201-
);
202-
}}
203-
disabled={validateBorderRadius(borderRadius) !== ""}
177+
onClick={() => props.setLink(generateLink(card))}
178+
disabled={validateBorderRadius(card.borderRadius) !== ""}
204179
text="Generate"
205180
/>
206181

207182
<SecondaryButton
208-
onClick={() => reset()}
183+
onClick={() => setCard(newCard())}
209184
text="Reset"
210185
className="text-red-500 font-semibold"
211186
/>

0 commit comments

Comments
 (0)