Skip to content

Commit 5d0c495

Browse files
committed
UPDATE - prj creation and fields
1 parent 93f35ad commit 5d0c495

11 files changed

Lines changed: 1427 additions & 129 deletions

File tree

client/src/components/AdminPage.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import "./AdminPage.css";
44
const adminLinks = [
55
{ href: "/admin/stats", icon: "📊", title: "Platform Statistics", desc: "Overview of projects, hours, users, and shop activity" },
66
{ href: "/admin/users", icon: "👥", title: "Users", desc: "Bolts, projects, hours, journals, and shop activity per participant" },
7-
{ href: "/admin/journals", icon: "🧾", title: "Journal entries (CSV)", desc: "All journal rows in one spreadsheet, sorted by project then time" },
7+
{ href: "/api/admin/journals.csv", icon: "🧾", title: "Journal entries (CSV)", desc: "All journal rows in one spreadsheet, sorted by project then time" },
88
{ href: "/admin/review", icon: "📋", title: "Project Review", desc: "Review shipped projects and approve hours" },
99
{ href: "/admin/shop", icon: "🛒", title: "Shop Admin", desc: "Manage catalog, categories, and pricing" },
1010
{ href: "/admin/shop/orders", icon: "📦", title: "Shop orders", desc: "Fulfillment queue, group by user or item, refunds" },

client/src/components/AdminShopPage.jsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ const emptyForm = {
1010
itemLink: "",
1111
imageUrl: "",
1212
description: "",
13-
position: "",
1413
active: true,
1514
};
1615

@@ -251,7 +250,7 @@ export function AdminShopPage() {
251250
}
252251

253252
function ShopItemForm({ value, submitLabel, onChange, onSubmit }) {
254-
const coinValue = value.priceUsd ? Number(value.priceUsd) * 10 : 0;
253+
const coinValue = value.priceUsd ? Math.ceil(Number(value.priceUsd) * 10) : 0;
255254

256255
return (
257256
<form className="admin-shop-form" onSubmit={onSubmit}>
@@ -279,7 +278,7 @@ function ShopItemForm({ value, submitLabel, onChange, onSubmit }) {
279278
</label>
280279
<label>
281280
Coins
282-
<input type="number" step="0.01" value={coinValue || ""} readOnly />
281+
<input type="number" value={coinValue || ""} readOnly />
283282
</label>
284283
<label>
285284
Max purchases per person
@@ -293,10 +292,6 @@ function ShopItemForm({ value, submitLabel, onChange, onSubmit }) {
293292
Image URL
294293
<input value={value.imageUrl || ""} onChange={(event) => onChange("imageUrl", event.target.value)} />
295294
</label>
296-
<label>
297-
Position
298-
<input type="number" value={value.position || ""} onChange={(event) => onChange("position", event.target.value)} />
299-
</label>
300295
<label>
301296
Active
302297
<input type="checkbox" checked={Boolean(value.active)} onChange={(event) => onChange("active", event.target.checked)} />

client/src/components/PlatformStatusBar.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export function PlatformStatusBar({ user, className = "" }) {
1515
const avatarSrc = user?.profileImageUrl || defaultAvatar;
1616
const username = user?.name || user?.slug || user?.email?.split("@")[0] || "User";
1717
const isAdmin = user?.role === "admin";
18+
const coins = Math.floor(Number(user?.coins ?? 0));
1819

1920
useEffect(() => {
2021
function onDocClick(event) {
@@ -67,7 +68,7 @@ export function PlatformStatusBar({ user, className = "" }) {
6768
<div className="platform-status__content">
6869
<div className="platform-status__row">
6970
<img className="platform-status__icon platform-status__icon--coin" src={coinIcon} alt="" aria-hidden="true" />
70-
<span className="platform-status__text">1234</span>
71+
<span className="platform-status__text">{coins}</span>
7172
</div>
7273
<div className="platform-status__row">
7374
<img className="platform-status__icon platform-status__icon--hearts" src={heartsIcon} alt="" aria-hidden="true" />

client/src/components/ProjectsPage.css

Lines changed: 202 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,37 @@
3535
cursor: pointer;
3636
}
3737

38+
.projects-page__card--add .projects-page__title {
39+
font-size: clamp(1.6rem, 2.4vw, 2.45rem);
40+
}
41+
42+
.projects-page__add-plus {
43+
position: relative;
44+
display: block;
45+
margin: -0.2rem 0 0.1rem;
46+
color: #fff8d8;
47+
font-size: clamp(2.2rem, 4vw, 4rem);
48+
line-height: 0.8;
49+
text-shadow: 0 3px 0 #50483f;
50+
z-index: 1;
51+
}
52+
53+
.projects-page__status {
54+
align-self: center;
55+
justify-self: center;
56+
padding: 1rem 1.2rem;
57+
border: 3px solid #162456;
58+
border-radius: 16px;
59+
background: #fff8d8;
60+
color: #162456;
61+
box-shadow: 5px 5px 0 #162456;
62+
font-size: 1.1rem;
63+
}
64+
65+
.projects-page__status--error {
66+
color: #b3261e;
67+
}
68+
3869
.projects-page__studs {
3970
position: absolute;
4071
left: 50%;
@@ -100,26 +131,51 @@
100131
width: min(11rem, 27vw);
101132
}
102133

103-
.projects-page__next {
134+
.projects-page__block-nav {
104135
position: fixed;
105-
left: 50%;
106136
bottom: max(1rem, calc(env(safe-area-inset-bottom) + 0.55rem));
107-
transform: translateX(-50%);
108137
z-index: 6;
138+
border: 0;
139+
padding: 0;
140+
background: transparent;
141+
cursor: pointer;
109142
}
110143

111-
.projects-page__next img {
144+
.projects-page__block-nav img {
112145
width: min(10rem, 28vw);
113146
transition: transform 150ms ease;
114147
}
115148

116-
.projects-page__next:hover img {
149+
.projects-page__block-nav--prev {
150+
left: calc(50% - min(8rem, 22vw));
151+
transform: translateX(-50%);
152+
}
153+
154+
.projects-page__block-nav--prev img {
155+
transform: scaleX(-1);
156+
}
157+
158+
.projects-page__block-nav--next {
159+
left: calc(50% + min(8rem, 22vw));
160+
transform: translateX(-50%);
161+
}
162+
163+
.projects-page__block-nav--solo {
164+
left: 50%;
165+
}
166+
167+
.projects-page__block-nav--next:hover img {
117168
transform: translateY(-2px);
118169
}
119170

120-
.projects-page__next:focus-visible {
171+
.projects-page__block-nav--prev:hover img {
172+
transform: scaleX(-1) translateY(-2px);
173+
}
174+
175+
.projects-page__block-nav:focus-visible {
121176
outline: 3px solid #1d55c9;
122177
outline-offset: 4px;
178+
border-radius: 10px;
123179
}
124180

125181
.projects-page__card:focus-visible {
@@ -155,7 +211,7 @@
155211
width: min(8.4rem, 32vw);
156212
}
157213

158-
.projects-page__next img {
214+
.projects-page__block-nav img {
159215
width: min(8.9rem, 33vw);
160216
}
161217
}
@@ -199,6 +255,23 @@
199255
line-height: 1.1;
200256
}
201257

258+
.projects-page__modal-description {
259+
margin: 0 0 0.8rem;
260+
color: #304389;
261+
font-size: 0.98rem;
262+
}
263+
264+
.projects-page__project-image {
265+
display: block;
266+
width: 100%;
267+
max-height: 12rem;
268+
object-fit: cover;
269+
border: 3px solid #c7d6ff;
270+
border-radius: 14px;
271+
margin: 0 0 0.85rem;
272+
background: #fff;
273+
}
274+
202275
.projects-page__modal-row {
203276
display: flex;
204277
justify-content: space-between;
@@ -212,3 +285,125 @@
212285
.projects-page__modal-row strong {
213286
color: #12235c;
214287
}
288+
289+
.projects-page__modal-link {
290+
display: inline-flex;
291+
margin: 0.45rem 0.7rem 0 0;
292+
color: #1b4cc0;
293+
font-weight: 700;
294+
}
295+
296+
.projects-page__modal-actions {
297+
display: flex;
298+
gap: 0.6rem;
299+
margin-top: 1rem;
300+
}
301+
302+
.projects-page__modal-actions button,
303+
.projects-page__form button {
304+
border: 0;
305+
border-radius: 10px;
306+
padding: 0.65rem 0.9rem;
307+
background: #dd3b45;
308+
color: #fff;
309+
font-weight: 700;
310+
cursor: pointer;
311+
box-shadow: 0 4px 0 #a82931;
312+
}
313+
314+
.projects-page__modal-actions button:disabled {
315+
opacity: 0.55;
316+
cursor: not-allowed;
317+
filter: grayscale(0.25);
318+
}
319+
320+
.projects-page__ship-lock {
321+
margin: 0.75rem 0 0;
322+
border: 2px dashed #9cb7ff;
323+
border-radius: 12px;
324+
padding: 0.6rem;
325+
color: #304389;
326+
font-weight: 700;
327+
}
328+
329+
.projects-page__danger-btn {
330+
background: #304389 !important;
331+
box-shadow: 0 4px 0 #1d2a57 !important;
332+
}
333+
334+
.projects-page__modal--form {
335+
width: min(34rem, 94vw);
336+
}
337+
338+
.projects-page__modal--journal {
339+
width: min(40rem, 94vw);
340+
max-height: min(46rem, 92vh);
341+
overflow: auto;
342+
}
343+
344+
.projects-page__form {
345+
display: grid;
346+
gap: 0.75rem;
347+
}
348+
349+
.projects-page__form label {
350+
display: grid;
351+
gap: 0.25rem;
352+
color: #27376f;
353+
font-weight: 700;
354+
}
355+
356+
.projects-page__form input,
357+
.projects-page__form textarea,
358+
.projects-page__form select {
359+
border: 2px solid #c7d6ff;
360+
border-radius: 10px;
361+
padding: 0.55rem 0.65rem;
362+
background: #fff;
363+
color: #12235c;
364+
font: inherit;
365+
}
366+
367+
.projects-page__form textarea {
368+
min-height: 5rem;
369+
resize: vertical;
370+
}
371+
372+
.projects-page__hackatime-disabled {
373+
border: 2px dashed #9cb7ff;
374+
border-radius: 12px;
375+
color: #304389;
376+
}
377+
378+
.projects-page__hackatime-disabled p {
379+
margin: 0.35rem 0 0;
380+
}
381+
382+
.projects-page__journal-list {
383+
margin-top: 1rem;
384+
border-top: 2px solid #c7d6ff;
385+
padding-top: 0.85rem;
386+
color: #27376f;
387+
}
388+
389+
.projects-page__journal-list h3 {
390+
margin: 0 0 0.6rem;
391+
color: #1d2a57;
392+
}
393+
394+
.projects-page__journal-entry {
395+
margin: 0.55rem 0;
396+
border: 2px solid #c7d6ff;
397+
border-radius: 12px;
398+
padding: 0.7rem;
399+
background: rgba(255, 255, 255, 0.72);
400+
}
401+
402+
.projects-page__journal-entry p {
403+
margin: 0.35rem 0;
404+
}
405+
406+
.projects-page__journal-entry small {
407+
color: #304389;
408+
font-weight: 700;
409+
}

0 commit comments

Comments
 (0)