223 lines
6.0 KiB
JavaScript
223 lines
6.0 KiB
JavaScript
import { useState, useEffect } from "react";
|
|
import { getGroceryLists, updateGroceryList } from "../groceryApi";
|
|
|
|
function PinnedGroceryLists({ onShowToast }) {
|
|
const [pinnedLists, setPinnedLists] = useState([]);
|
|
|
|
useEffect(() => {
|
|
loadPinnedLists();
|
|
}, []);
|
|
|
|
const loadPinnedLists = async () => {
|
|
try {
|
|
const allLists = await getGroceryLists();
|
|
const pinned = allLists.filter((list) => list.is_pinned);
|
|
setPinnedLists(pinned);
|
|
} catch (error) {
|
|
console.error("Failed to load pinned lists", error);
|
|
}
|
|
};
|
|
|
|
const handleToggleItem = async (listId, itemIndex) => {
|
|
const list = pinnedLists.find((l) => l.id === listId);
|
|
if (!list || !list.can_edit) return;
|
|
|
|
const updatedItems = [...list.items];
|
|
const item = updatedItems[itemIndex];
|
|
|
|
if (item.startsWith("✓ ")) {
|
|
updatedItems[itemIndex] = item.substring(2);
|
|
} else {
|
|
updatedItems[itemIndex] = "✓ " + item;
|
|
}
|
|
|
|
try {
|
|
await updateGroceryList(listId, { items: updatedItems });
|
|
setPinnedLists(
|
|
pinnedLists.map((l) =>
|
|
l.id === listId ? { ...l, items: updatedItems } : l
|
|
)
|
|
);
|
|
} catch (error) {
|
|
onShowToast?.(error.message, "error");
|
|
}
|
|
};
|
|
|
|
if (pinnedLists.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<div className="pinned-grocery-lists">
|
|
{pinnedLists.map((list) => (
|
|
<div key={list.id} className="pinned-note">
|
|
<div className="pin-icon">📌</div>
|
|
<h3 className="note-title">{list.name}</h3>
|
|
<ul className="note-items">
|
|
{list.items.length === 0 ? (
|
|
<li className="empty-note">הרשימה ריקה</li>
|
|
) : (
|
|
list.items.map((item, index) => {
|
|
const isChecked = item.startsWith("✓ ");
|
|
const itemText = isChecked ? item.substring(2) : item;
|
|
return (
|
|
<li
|
|
key={index}
|
|
className={`note-item ${isChecked ? "checked" : ""}`}
|
|
onClick={() =>
|
|
list.can_edit && handleToggleItem(list.id, index)
|
|
}
|
|
style={{ cursor: list.can_edit ? "pointer" : "default" }}
|
|
>
|
|
<span className="checkbox">{isChecked ? "☑" : "☐"}</span>
|
|
<span className="item-text">{itemText}</span>
|
|
</li>
|
|
);
|
|
})
|
|
)}
|
|
</ul>
|
|
</div>
|
|
))}
|
|
|
|
<style jsx>{`
|
|
@import url('https://fonts.googleapis.com/css2?family=Caveat:wght@400;700&display=swap');
|
|
|
|
.pinned-grocery-lists {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1.5rem;
|
|
padding: 1rem;
|
|
max-width: 320px;
|
|
}
|
|
|
|
.pinned-note {
|
|
position: relative;
|
|
background: linear-gradient(135deg, #fff9e6 0%, #fffaed 100%);
|
|
padding: 2rem 1.5rem 1.5rem;
|
|
border-radius: 4px;
|
|
box-shadow:
|
|
0 2px 4px rgba(0, 0, 0, 0.1),
|
|
0 4px 12px rgba(0, 0, 0, 0.08),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.5);
|
|
border: 1px solid #f5e6c8;
|
|
transform: rotate(-1deg);
|
|
transition: all 0.3s ease;
|
|
font-family: 'Caveat', cursive;
|
|
}
|
|
|
|
.pinned-note:nth-child(even) {
|
|
transform: rotate(1deg);
|
|
background: linear-gradient(135deg, #fff5e1 0%, #fff9eb 100%);
|
|
}
|
|
|
|
.pinned-note:hover {
|
|
transform: rotate(0deg) scale(1.02);
|
|
box-shadow:
|
|
0 4px 8px rgba(0, 0, 0, 0.15),
|
|
0 8px 20px rgba(0, 0, 0, 0.1),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.6);
|
|
}
|
|
|
|
.pin-icon {
|
|
position: absolute;
|
|
top: -8px;
|
|
right: 20px;
|
|
font-size: 2rem;
|
|
filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.2));
|
|
transform: rotate(25deg);
|
|
}
|
|
|
|
.note-title {
|
|
margin: 0 0 1rem 0;
|
|
font-size: 1.8rem;
|
|
color: #5a4a2a;
|
|
font-weight: 700;
|
|
text-align: center;
|
|
border-bottom: 2px solid rgba(90, 74, 42, 0.2);
|
|
padding-bottom: 0.5rem;
|
|
letter-spacing: 0.5px;
|
|
}
|
|
|
|
.note-items {
|
|
list-style: none;
|
|
padding: 0;
|
|
margin: 0;
|
|
}
|
|
|
|
.empty-note {
|
|
text-align: center;
|
|
color: #9a8a6a;
|
|
font-size: 1.3rem;
|
|
padding: 1rem;
|
|
font-style: italic;
|
|
}
|
|
|
|
.note-item {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 0.75rem;
|
|
padding: 0.5rem 0;
|
|
font-size: 1.4rem;
|
|
color: #4a3a1a;
|
|
line-height: 1.6;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.note-item:hover {
|
|
color: #2a1a0a;
|
|
}
|
|
|
|
.note-item.checked .item-text {
|
|
text-decoration: line-through;
|
|
opacity: 0.5;
|
|
}
|
|
|
|
.checkbox {
|
|
font-size: 1.3rem;
|
|
flex-shrink: 0;
|
|
margin-top: 2px;
|
|
}
|
|
|
|
.item-text {
|
|
flex: 1;
|
|
word-break: break-word;
|
|
}
|
|
|
|
/* Paper texture overlay */
|
|
.pinned-note::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background-image:
|
|
repeating-linear-gradient(
|
|
0deg,
|
|
transparent,
|
|
transparent 31px,
|
|
rgba(90, 74, 42, 0.03) 31px,
|
|
rgba(90, 74, 42, 0.03) 32px
|
|
);
|
|
pointer-events: none;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
/* Light mode specific adjustments */
|
|
@media (prefers-color-scheme: light) {
|
|
.pinned-note {
|
|
background: linear-gradient(135deg, #fffbf0 0%, #fffef8 100%);
|
|
border-color: #f0e0c0;
|
|
}
|
|
|
|
.pinned-note:nth-child(even) {
|
|
background: linear-gradient(135deg, #fff8e8 0%, #fffcf3 100%);
|
|
}
|
|
}
|
|
`}</style>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default PinnedGroceryLists;
|