Skip to content

Commit ce60bb0

Browse files
committed
feat: add testimony form and enhance map controls for Hebrew support
- Introduced a new TestimonyForm component for user input on testimonies. - Updated BaseMapControls to support Hebrew language titles for buttons. - Enhanced useMap hook to localize drawing tooltips and messages based on Hebrew language setting. - Added styles for the testimony form in index.css to improve UI consistency.
1 parent 0436fe5 commit ce60bb0

5 files changed

Lines changed: 173 additions & 19 deletions

File tree

src/index.css

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,3 +786,31 @@ a:hover {
786786
outline: none;
787787
box-shadow: none;
788788
}
789+
790+
.testimony-form {
791+
background: rgba(20, 20, 20, 0.4);
792+
backdrop-filter: blur(12px);
793+
-webkit-backdrop-filter: blur(12px);
794+
border-radius: 10px;
795+
padding: 14px;
796+
display: flex;
797+
flex-direction: column;
798+
gap: 8px;
799+
min-width: 360px;
800+
}
801+
802+
.testimony-field {
803+
border-radius: 6px !important;
804+
}
805+
806+
.testimony-buttons {
807+
display: flex;
808+
gap: 4px;
809+
direction: rtl;
810+
}
811+
812+
.testimony-buttons .shape-name-input-btn {
813+
flex: 1;
814+
border-radius: 6px;
815+
}
816+

src/pages/MapPage/BaseMapControls.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ interface BaseMapControlsProps {
66
mapRef: React.MutableRefObject<L.Map | null>;
77
drawControlRef: React.MutableRefObject<L.Control.Draw | null>;
88
featureCount: number;
9+
isHebrew?: boolean;
910
}
1011

11-
const BaseMapControls = ({ mapRef, drawControlRef, featureCount }: BaseMapControlsProps) => {
12+
const BaseMapControls = ({ mapRef, drawControlRef, featureCount, isHebrew }: BaseMapControlsProps) => {
1213
const navigate = useNavigate();
1314

1415
const disableAllModes = () => {
@@ -94,50 +95,50 @@ const BaseMapControls = ({ mapRef, drawControlRef, featureCount }: BaseMapContro
9495
<button
9596
className="base-map-control-btn"
9697
onClick={() => handleDrawTool("polygon")}
97-
title="Polygon"
98+
title={isHebrew ? "מצולע" : "Polygon"}
9899
>
99100
100101
</button>
101102
<button
102103
className="base-map-control-btn"
103104
onClick={() => handleDrawTool("polyline")}
104-
title="Line"
105+
title={isHebrew ? "קו" : "Line"}
105106
>
106107
107108
</button>
108109
<button
109110
className="base-map-control-btn"
110111
onClick={() => handleDrawTool("marker")}
111-
title="Point"
112+
title={isHebrew ? "נקודה" : "Point"}
112113
>
113114
+
114115
</button>
115116
<button
116117
className="base-map-control-btn"
117118
onClick={handleEditMode}
118-
title="Edit"
119+
title={isHebrew ? "עריכה" : "Edit"}
119120
>
120121
121122
</button>
122123
<button
123124
className="base-map-control-btn"
124125
onClick={handleDeleteMode}
125-
title="Delete"
126+
title={isHebrew ? "מחיקה" : "Delete"}
126127
>
127128
×
128129
</button>
129130
<div className="base-map-controls-divider"></div>
130131
<button
131132
className="base-map-control-btn"
132133
onClick={handleHome}
133-
title="Projects"
134+
title={isHebrew ? "פרויקטים" : "Projects"}
134135
>
135136
136137
</button>
137138
<button
138139
className="base-map-control-btn"
139140
onClick={handleSignOut}
140-
title="Sign Out"
141+
title={isHebrew ? "התנתק" : "Sign Out"}
141142
>
142143
143144
</button>
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { useState, useRef, useEffect } from "react";
2+
3+
interface TestimonyFormProps {
4+
onSubmit: (name: string | null, description: string | null) => void;
5+
onCancel: () => void;
6+
}
7+
8+
const NAME_QUESTION = "תנו שם לרשומה";
9+
const TESTIMONY_QUESTION = "ספר/י מה קרה כאן";
10+
11+
const TestimonyForm = ({ onSubmit, onCancel }: TestimonyFormProps) => {
12+
const [step, setStep] = useState<1 | 2>(1);
13+
const [name, setName] = useState("");
14+
const [testimony, setTestimony] = useState("");
15+
const inputRef = useRef<HTMLInputElement | HTMLTextAreaElement>(null);
16+
17+
useEffect(() => {
18+
inputRef.current?.focus();
19+
}, [step]);
20+
21+
const question = step === 1 ? NAME_QUESTION : TESTIMONY_QUESTION;
22+
const value = step === 1 ? name : testimony;
23+
const canNext = value.trim().length > 0;
24+
25+
const handleNext = () => {
26+
if (step === 1) {
27+
setStep(2);
28+
} else {
29+
onSubmit(name.trim() || null, testimony.trim() || null);
30+
}
31+
};
32+
33+
return (
34+
<div className="shape-name-input-container">
35+
<form
36+
onSubmit={(e) => {
37+
e.preventDefault();
38+
if (canNext) handleNext();
39+
}}
40+
className="testimony-form"
41+
dir="rtl"
42+
>
43+
<label className="shape-name-input-label">{question}</label>
44+
{step === 1 ? (
45+
<input
46+
ref={inputRef as React.RefObject<HTMLInputElement>}
47+
type="text"
48+
value={name}
49+
onChange={(e) => setName(e.target.value)}
50+
onKeyDown={(e) => e.key === "Escape" && onCancel()}
51+
className="shape-name-input-field testimony-field"
52+
dir="rtl"
53+
/>
54+
) : (
55+
<textarea
56+
ref={inputRef as React.RefObject<HTMLTextAreaElement>}
57+
value={testimony}
58+
onChange={(e) => setTestimony(e.target.value)}
59+
onKeyDown={(e) => e.key === "Escape" && onCancel()}
60+
className="shape-description-input-field testimony-field"
61+
rows={5}
62+
dir="rtl"
63+
/>
64+
)}
65+
<div className="testimony-buttons">
66+
<button
67+
type="submit"
68+
className="shape-name-input-btn"
69+
disabled={!canNext}
70+
>
71+
{step === 1 ? "הבא" : "שמור"}
72+
</button>
73+
<button
74+
type="button"
75+
onClick={onCancel}
76+
className="shape-name-input-btn"
77+
>
78+
ביטול
79+
</button>
80+
</div>
81+
</form>
82+
</div>
83+
);
84+
};
85+
86+
export default TestimonyForm;

src/pages/MapPage/hooks/useMap.ts

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ interface UseMapProps {
1616
center: L.LatLngExpression;
1717
enabled?: boolean;
1818
onShapeCreated?: (layer: L.Layer, callback: (name: string | null, description: string | null) => void) => void;
19+
isHebrew?: boolean;
1920
}
2021

2122
interface UseMapReturn {
@@ -24,7 +25,7 @@ interface UseMapReturn {
2425
featureCount: number;
2526
}
2627

27-
export const useMap = ({ center, enabled = true, onShapeCreated }: UseMapProps): UseMapReturn => {
28+
export const useMap = ({ center, enabled = true, onShapeCreated, isHebrew }: UseMapProps): UseMapReturn => {
2829
const mapRef = useRef<L.Map | null>(null);
2930
const drawnItemsRef = useRef<L.FeatureGroup | null>(null);
3031
const drawControlRef = useRef<L.Control.Draw | null>(null);
@@ -63,6 +64,32 @@ export const useMap = ({ center, enabled = true, onShapeCreated }: UseMapProps):
6364
drawnItemsRef.current = new L.FeatureGroup();
6465
mapRef.current.addLayer(drawnItemsRef.current);
6566

67+
if (isHebrew) {
68+
L.drawLocal.draw.toolbar.actions.title = "בטל ציור";
69+
L.drawLocal.draw.toolbar.actions.text = "ביטול";
70+
L.drawLocal.draw.toolbar.finish.title = "סיים ציור";
71+
L.drawLocal.draw.toolbar.finish.text = "סיום";
72+
L.drawLocal.draw.toolbar.undo.title = "מחק נקודה אחרונה";
73+
L.drawLocal.draw.toolbar.undo.text = "מחק אחרון";
74+
L.drawLocal.draw.handlers.polygon.tooltip.start = "לחצו כדי להתחיל לצייר צורה";
75+
L.drawLocal.draw.handlers.polygon.tooltip.cont = "לחצו כדי להמשיך לצייר";
76+
L.drawLocal.draw.handlers.polygon.tooltip.end = "לחצו על הנקודה הראשונה כדי לסגור את הצורה";
77+
L.drawLocal.draw.handlers.polyline.tooltip.start = "לחצו כדי להתחיל לצייר קו";
78+
L.drawLocal.draw.handlers.polyline.tooltip.cont = "לחצו כדי להמשיך לצייר";
79+
L.drawLocal.draw.handlers.polyline.tooltip.end = "לחצו על הנקודה האחרונה כדי לסיים";
80+
L.drawLocal.draw.handlers.marker.tooltip.start = "לחצו על המפה כדי להוסיף נקודה";
81+
L.drawLocal.edit.toolbar.actions.save.title = "שמור שינויים";
82+
L.drawLocal.edit.toolbar.actions.save.text = "שמור";
83+
L.drawLocal.edit.toolbar.actions.cancel.title = "בטל שינויים";
84+
L.drawLocal.edit.toolbar.actions.cancel.text = "ביטול";
85+
L.drawLocal.edit.toolbar.actions.clearAll.title = "נקה הכל";
86+
L.drawLocal.edit.toolbar.actions.clearAll.text = "נקה הכל";
87+
L.drawLocal.edit.toolbar.buttons.edit = "ערוך שכבות";
88+
L.drawLocal.edit.toolbar.buttons.editDisabled = "אין שכבות לעריכה";
89+
L.drawLocal.edit.toolbar.buttons.remove = "מחק שכבות";
90+
L.drawLocal.edit.toolbar.buttons.removeDisabled = "אין שכבות למחיקה";
91+
}
92+
6693
const drawControl = new L.Control.Draw({
6794
position: "topleft",
6895
edit: { featureGroup: drawnItemsRef.current },
@@ -119,7 +146,7 @@ export const useMap = ({ center, enabled = true, onShapeCreated }: UseMapProps):
119146
const newFeature = await createGeometry(shapeName, description, geojson);
120147
if (newFeature) {
121148
layer.featureId = newFeature.id;
122-
const displayName = newFeature.name || "Unnamed";
149+
const displayName = newFeature.name || (isHebrew ? "ללא שם" : "Unnamed");
123150
layer.bindTooltip(displayName);
124151
}
125152
pendingLayersRef.current.delete(layer);
@@ -202,7 +229,7 @@ export const useMap = ({ center, enabled = true, onShapeCreated }: UseMapProps):
202229

203230
if (layer) {
204231
layer.featureId = feature.id;
205-
const displayName = feature.name || "Unnamed";
232+
const displayName = feature.name || (isHebrew ? "ללא שם" : "Unnamed");
206233
layer.bindTooltip(displayName);
207234
drawnItemsRef.current?.addLayer(layer);
208235
}
@@ -218,7 +245,7 @@ export const useMap = ({ center, enabled = true, onShapeCreated }: UseMapProps):
218245
drawControlRef.current = null;
219246
}
220247
};
221-
}, [center, enabled]);
248+
}, [center, enabled, isHebrew]);
222249

223250
return { mapRef, drawControlRef, featureCount };
224251
};

src/pages/MapPage/index.tsx

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import PinkLineMapPage from "./PinkLineMapPage";
66
import MemorialSitesMapPage from "./MemorialSitesMapPage";
77
import BaseMapControls from "./BaseMapControls";
88
import ShapeNameInput from "./ShapeNameInput";
9+
import TestimonyForm from "./TestimonyForm";
10+
11+
const TESTIMONY_PROJECT_ID = "11111111-1111-1111-1111-111111111111";
912

1013
const MapPage = () => {
1114
const { project, isLoading } = useProject();
@@ -55,15 +58,17 @@ const MapPage = () => {
5558
};
5659

5760
const isMemorialSites = project?.id === "33333333-3333-3333-3333-333333333333";
61+
const isTestimony = project?.id === TESTIMONY_PROJECT_ID;
5862
const isSpecialProject = project?.name === "Pink Line" || isMemorialSites;
5963
const { mapRef, drawControlRef, featureCount } = useMap({
6064
center: mapInitCenter,
6165
enabled: !isLoading && !isSpecialProject,
62-
onShapeCreated: handleShapeCreated
66+
onShapeCreated: handleShapeCreated,
67+
isHebrew: isTestimony,
6368
});
6469

6570
if (isLoading) {
66-
return <div>Loading project...</div>;
71+
return <div>טוען...</div>;
6772
}
6873

6974
if (project?.name === "Pink Line") return <PinkLineMapPage />;
@@ -72,12 +77,19 @@ const MapPage = () => {
7277
return (
7378
<>
7479
<div key={project?.id || "no-project"} id="map" style={{ height: "100vh", width: "100%" }}></div>
75-
<BaseMapControls mapRef={mapRef} drawControlRef={drawControlRef} featureCount={featureCount} />
80+
<BaseMapControls mapRef={mapRef} drawControlRef={drawControlRef} featureCount={featureCount} isHebrew={isTestimony} />
7681
{pendingLayer && (
77-
<ShapeNameInput
78-
onSubmit={handleShapeNameSubmit}
79-
onCancel={handleShapeNameCancel}
80-
/>
82+
project?.id === TESTIMONY_PROJECT_ID ? (
83+
<TestimonyForm
84+
onSubmit={handleShapeNameSubmit}
85+
onCancel={handleShapeNameCancel}
86+
/>
87+
) : (
88+
<ShapeNameInput
89+
onSubmit={handleShapeNameSubmit}
90+
onCancel={handleShapeNameCancel}
91+
/>
92+
)
8193
)}
8294
</>
8395
);

0 commit comments

Comments
 (0)