Skip to content

Commit 2723a05

Browse files
committed
Feat: added category section binding
1 parent 5478016 commit 2723a05

File tree

8 files changed

+99
-39
lines changed

8 files changed

+99
-39
lines changed

src/components/controls/select/polyline/section-selector.tsx

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -40,35 +40,38 @@ const SectionSelector = ({ firstElement, selectedElementIds }) => {
4040
<hr />
4141
</div>
4242
<div className="flex flex-col gap-4">
43-
{sections.map((section, index) => (
44-
<div key={`category-${section.id}`} className="flex justify-start items-center gap-4">
45-
<input
46-
defaultValue={section.color}
47-
type="color"
48-
className="flex-shrink-0 w-6 h-6 p-0 bg-white rounded-color-input"
49-
onChange={(e) => onUpdateSection({ ...section, color: e.target.value })}
50-
/>
51-
<input
52-
defaultValue={section.stroke}
53-
type="color"
54-
className="flex-shrink-0 w-6 h-6 p-0 bg-white rounded-color-input"
55-
onChange={(e) => onUpdateSection({ ...section, stroke: e.target.value })}
56-
/>
57-
<Input
58-
defaultValue={section.name}
59-
className="h-8"
60-
onChange={(e) => onUpdateSection({ ...section, name: e.target.value })}
61-
/>
62-
<Trash2
63-
size={22}
64-
className={twMerge(
65-
"hover:text-gray-500 flex-shrink-0 cursor-pointer transition-all duration-medium",
66-
index === 0 && "opacity-0 pointer-events-none"
67-
)}
68-
onClick={() => onDeleteSection(section.id)}
69-
/>
70-
</div>
71-
))}
43+
{sections.map(
44+
(section, index) =>
45+
section.id !== "0" && (
46+
<div key={`category-${section.id}`} className="flex justify-start items-center gap-4">
47+
<input
48+
defaultValue={section.color}
49+
type="color"
50+
className="flex-shrink-0 w-6 h-6 p-0 bg-white rounded-color-input"
51+
onChange={(e) => onUpdateSection({ ...section, color: e.target.value })}
52+
/>
53+
<input
54+
defaultValue={section.stroke}
55+
type="color"
56+
className="flex-shrink-0 w-6 h-6 p-0 bg-white rounded-color-input"
57+
onChange={(e) => onUpdateSection({ ...section, stroke: e.target.value })}
58+
/>
59+
<Input
60+
defaultValue={section.name}
61+
className="h-8"
62+
onChange={(e) => onUpdateSection({ ...section, name: e.target.value })}
63+
/>
64+
<Trash2
65+
size={22}
66+
className={twMerge(
67+
"hover:text-gray-500 flex-shrink-0 cursor-pointer transition-all duration-medium",
68+
index === 0 && "opacity-0 pointer-events-none"
69+
)}
70+
onClick={() => onDeleteSection(section.id)}
71+
/>
72+
</div>
73+
)
74+
)}
7275
</div>
7376
</div>
7477
</PopoverContent>
@@ -89,7 +92,7 @@ const SectionSelector = ({ firstElement, selectedElementIds }) => {
8992
{sections.map((section) => (
9093
<SelectItem key={section.id} value={section.id}>
9194
<div className="flex gap-3 items-center">
92-
{section.id === 0 ? (
95+
{section.id === "0" ? (
9396
<div className="w-4 h-0.5 bg-black" />
9497
) : (
9598
<div className="h-4 w-4 rounded-full" style={{ backgroundColor: section.color }} />

src/components/controls/select/seats/categorizer.tsx

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
import { Trash2 } from "lucide-react";
1+
import { MouseEvent } from "react";
2+
import { PopoverClose } from "@radix-ui/react-popover";
3+
import { LayoutTemplate, Trash2 } from "lucide-react";
24
import { useSelector } from "react-redux";
35
import { debounce } from "lodash";
6+
import { twMerge } from "tailwind-merge";
47
import { Input, Popover, PopoverContent, PopoverTrigger } from "@/components/core";
58
import { dataAttributes } from "@/constants";
69
import { store } from "@/store";
@@ -13,8 +16,16 @@ const onDeleteCategory = (id: string) => store.dispatch(deleteCategory(id));
1316

1417
const onUpdateCategory = debounce((category) => store.dispatch(updateCategory(category)), 150);
1518

19+
const onSectionSelect = (e: MouseEvent<HTMLButtonElement>) => {
20+
const element = e.target as HTMLButtonElement;
21+
const categoryId = element.getAttribute(dataAttributes.category);
22+
const sectionId = element.getAttribute(dataAttributes.section);
23+
store.dispatch(updateCategory({ id: categoryId, section: +sectionId === 0 ? null : sectionId }));
24+
};
25+
1626
const Categorizer = ({ firstElement, selectedElementIds }) => {
1727
const categories = useSelector((state: any) => state.editor.categories);
28+
const sections = useSelector((state: any) => state.editor.sections);
1829

1930
return (
2031
<>
@@ -59,6 +70,36 @@ const Categorizer = ({ firstElement, selectedElementIds }) => {
5970
className="h-8"
6071
onChange={(e) => onUpdateCategory({ ...category, name: e.target.value })}
6172
/>
73+
<Popover>
74+
<PopoverTrigger>
75+
<LayoutTemplate
76+
size={22}
77+
className={twMerge(
78+
"flex-shrink-0 cursor-pointer transition-all duration-medium ",
79+
category.section ? "text-blue-600 hover:text-blue-500" : "hover:text-gray-500"
80+
)}
81+
/>
82+
</PopoverTrigger>
83+
<PopoverContent className="bg-white w-auto p-0 mr-4">
84+
{sections.map((section) => (
85+
<PopoverClose
86+
key={section.id}
87+
className={twMerge(
88+
"flex gap-3 items-center py-2 px-4 text-base cursor-pointer hover:bg-gray-100 transition-all duration-medium",
89+
section.id === "0" && "justify-center border-b pb-2"
90+
)}
91+
{...{ [dataAttributes.section]: section.id }}
92+
{...{ [dataAttributes.category]: category.id }}
93+
onClick={onSectionSelect}
94+
>
95+
{section.id !== "0" && (
96+
<div className="h-4 w-4 rounded-full" style={{ backgroundColor: section.color }} />
97+
)}
98+
{section.name}
99+
</PopoverClose>
100+
))}
101+
</PopoverContent>
102+
</Popover>
62103
<Trash2
63104
size={22}
64105
className="hover:text-gray-500 flex-shrink-0 cursor-pointer transition-all duration-medium"

src/components/core/popover.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ const PopoverTrigger = PopoverPrimitive.Trigger;
88

99
const PopoverAnchor = PopoverPrimitive.Anchor;
1010

11+
const PopoverClose = PopoverPrimitive.Close;
12+
1113
const PopoverContent = React.forwardRef<
1214
React.ElementRef<typeof PopoverPrimitive.Content>,
1315
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
@@ -27,4 +29,4 @@ const PopoverContent = React.forwardRef<
2729
));
2830
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
2931

30-
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
32+
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor, PopoverClose };

src/components/operations/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ const Operations: React.FC<ISTKProps> = ({
8080
Preview
8181
</Button>
8282
<Button
83-
className={twMerge("py-[0.35rem]", coreStyles?.button?.className)}
83+
className={twMerge("py-[0.35rem] text-center", coreStyles?.button?.className)}
8484
style={coreStyles?.button?.properties}
8585
onClick={onExportJson}
8686
>

src/components/workspace/elements/seat.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { forwardRef, useEffect, useMemo } from "react";
22
import { twMerge } from "tailwind-merge";
33
import { dataAttributes, seatStatusColors } from "@/constants";
44
import { ISTKProps } from "@/types";
5-
import { ISeat, ISeatCategory, SeatStatus } from "@/types/elements";
5+
import { ISeat, ISeatCategory, ISection, SeatStatus } from "@/types/elements";
66
import { d3Extended } from "@/utils";
77

88
export const seatSize = 28;
@@ -14,12 +14,17 @@ export interface ISeatProps extends ISeat {
1414
consumer: ISTKProps;
1515
element: ISeat;
1616
categories: ISeatCategory[];
17+
sections: ISection[];
1718
onClick: (e: any) => void;
1819
}
1920

2021
const Seat: React.FC<ISeatProps> = forwardRef(
21-
({ x, y, id, label, categories, category, status, onClick, consumer, element, ...props }, ref: any) => {
22+
({ x, y, id, label, categories, category, sections, status, onClick, consumer, element, ...props }, ref: any) => {
2223
const categoryObject = useMemo(() => categories?.find?.((c) => c.id === category), [categories, category]);
24+
const sectionObject = useMemo(
25+
() => sections?.find?.((s) => s.id === categoryObject?.section),
26+
[sections, categoryObject]
27+
);
2328

2429
const showLabel = consumer.options?.showSeatLabels ?? true;
2530

@@ -55,7 +60,7 @@ const Seat: React.FC<ISeatProps> = forwardRef(
5560
onClick(e);
5661
consumer.events?.onSeatClick?.({
5762
...element,
58-
category: categoryObject
63+
category: categoryObject ? { ...categoryObject, section: sectionObject } : null
5964
});
6065
};
6166

@@ -69,6 +74,7 @@ const Seat: React.FC<ISeatProps> = forwardRef(
6974
r={seatSize / 2}
7075
onClick={localOnClick}
7176
{...{ [dataAttributes.category]: category }}
77+
{...{ [dataAttributes.section]: categoryObject?.section }}
7278
{...{ [dataAttributes.status]: status ?? SeatStatus.Available }}
7379
{...props}
7480
className={twMerge(props.className, "filter hover:brightness-[1.05]")}

src/components/workspace/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ export const Workspace: React.FC<ISTKProps> = (props) => {
6868
<Element
6969
key={e.id}
7070
type={ElementType.Seat}
71+
sections={sections}
7172
categories={categories}
7273
category={e.category}
7374
status={e.status}

src/store/reducers/editor/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ export const slice = createSlice({
187187
},
188188
updateCategory: (state, action) => {
189189
const index = state.categories.findIndex((category) => category.id === action.payload.id);
190-
state.categories[index] = action.payload;
190+
state.categories[index] = { ...state.categories[index], ...action.payload };
191191
},
192192
addSection: (state) => {
193193
state.sections.push({
@@ -200,7 +200,7 @@ export const slice = createSlice({
200200
},
201201
updateSection: (state, action) => {
202202
const index = state.sections.findIndex((section) => section.id === action.payload.id);
203-
state.sections[index] = action.payload;
203+
state.sections[index] = { ...state.sections[index], ...action.payload };
204204
},
205205
deleteSection: (state, action) => {
206206
state.sections = state.sections.filter((section) => section.id !== action.payload);

src/types/elements/seat.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
import { ISection } from "./polyline";
2+
13
export interface ISeatCategory {
24
id: string;
35
name: string;
46
color: string;
57
textColor: string;
8+
section?: string;
69
}
710

811
export enum SeatStatus {
@@ -20,6 +23,10 @@ export interface ISeat {
2023
status?: SeatStatus | string;
2124
}
2225

26+
export interface IPopulatedSeatCategory extends Omit<ISeatCategory, "section"> {
27+
section?: ISection;
28+
}
29+
2330
export interface IPopulatedSeat extends Omit<ISeat, "category"> {
24-
category?: ISeatCategory;
31+
category?: IPopulatedSeatCategory;
2532
}

0 commit comments

Comments
 (0)