|
1 | 1 | import { useAuth } from "../contexts/AuthContext";
|
2 | 2 | import { useState, useEffect } from "react";
|
3 | 3 | import { useNavigate } from "react-router-dom";
|
4 |
| -import { Tabs, Tab, Snackbar, Alert, IconButton, Button } from "@mui/material"; |
| 4 | +import { Tabs, Tab, Snackbar, Alert, IconButton, Button, TextField } from "@mui/material"; |
5 | 5 | import { styled } from "@mui/material/styles";
|
6 | 6 | import LogoutIcon from "@mui/icons-material/Logout";
|
| 7 | +import EditIcon from "@mui/icons-material/Edit"; |
| 8 | +import SaveIcon from "@mui/icons-material/Save"; |
| 9 | +import CancelIcon from "@mui/icons-material/Cancel"; |
7 | 10 | import { activityService } from "../services/activityService";
|
8 | 11 | import AvatarUpload from "../components/Avator";
|
9 | 12 | import ParticipantsList from "../components/ParticipantsList";
|
@@ -45,6 +48,8 @@ export default function Home() {
|
45 | 48 | severity: "success",
|
46 | 49 | actions: null,
|
47 | 50 | });
|
| 51 | + const [editingActivity, setEditingActivity] = useState(null); |
| 52 | + const [editedActivity, setEditedActivity] = useState(null); |
48 | 53 |
|
49 | 54 | const handleChange = async (event, newValue) => {
|
50 | 55 | setValue(newValue);
|
@@ -256,6 +261,84 @@ export default function Home() {
|
256 | 261 | navigate("/create-activity");
|
257 | 262 | };
|
258 | 263 |
|
| 264 | + const handleEditActivity = (activity) => { |
| 265 | + setEditingActivity(activity.activityId); |
| 266 | + |
| 267 | + // Convert backend date format (YYYY-MM-DD HH:mm) to datetime-local format (YYYY-MM-DDTHH:mm) |
| 268 | + const convertToDateTimeLocal = (dateTimeStr) => { |
| 269 | + if (!dateTimeStr) return ''; |
| 270 | + // Replace space with T for datetime-local input |
| 271 | + return dateTimeStr.replace(' ', 'T'); |
| 272 | + }; |
| 273 | + |
| 274 | + setEditedActivity({ |
| 275 | + name: activity.name, |
| 276 | + description: activity.description, |
| 277 | + location: activity.location, |
| 278 | + startDateTime: convertToDateTimeLocal(activity.startDateTime), |
| 279 | + endDateTime: convertToDateTimeLocal(activity.endDateTime) |
| 280 | + }); |
| 281 | + }; |
| 282 | + |
| 283 | + const handleCancelEdit = () => { |
| 284 | + setEditingActivity(null); |
| 285 | + setEditedActivity(null); |
| 286 | + }; |
| 287 | + |
| 288 | + const handleSaveEdit = async (activityId) => { |
| 289 | + try { |
| 290 | + // Format the dates to match the backend's expected format (YYYY-MM-DD HH:mm) |
| 291 | + const formatDateTime = (dateTimeStr) => { |
| 292 | + if (!dateTimeStr) return ''; |
| 293 | + |
| 294 | + // Parse the datetime-local input value and format it properly |
| 295 | + const date = new Date(dateTimeStr); |
| 296 | + |
| 297 | + // Format as YYYY-MM-DD HH:mm (without seconds) |
| 298 | + const year = date.getFullYear(); |
| 299 | + const month = String(date.getMonth() + 1).padStart(2, '0'); |
| 300 | + const day = String(date.getDate()).padStart(2, '0'); |
| 301 | + const hours = String(date.getHours()).padStart(2, '0'); |
| 302 | + const minutes = String(date.getMinutes()).padStart(2, '0'); |
| 303 | + |
| 304 | + return `${year}-${month}-${day} ${hours}:${minutes}`; |
| 305 | + }; |
| 306 | + |
| 307 | + const formattedActivity = { |
| 308 | + name: editedActivity.name || '', |
| 309 | + description: editedActivity.description || '', |
| 310 | + location: editedActivity.location || '', |
| 311 | + startDateTime: formatDateTime(editedActivity.startDateTime), |
| 312 | + endDateTime: formatDateTime(editedActivity.endDateTime) |
| 313 | + }; |
| 314 | + |
| 315 | + console.log("Payload to updateActivity:", formattedActivity); |
| 316 | + |
| 317 | + await activityService.updateActivity(activityId, formattedActivity); |
| 318 | + const activities = await activityService.getParticipantActivities(); |
| 319 | + setParticipantActivities(activities); |
| 320 | + setEditingActivity(null); |
| 321 | + setEditedActivity(null); |
| 322 | + notifySuccess("Activity updated successfully"); |
| 323 | + } catch (error) { |
| 324 | + console.error("Error updating activity:", error); |
| 325 | + let errorMessage = "Failed to update activity"; |
| 326 | + if (error.response?.data?.message) { |
| 327 | + errorMessage = error.response.data.message; |
| 328 | + } else if (error.response?.data?.errors) { |
| 329 | + errorMessage = JSON.stringify(error.response.data.errors); |
| 330 | + } |
| 331 | + notifyError(errorMessage); |
| 332 | + } |
| 333 | + }; |
| 334 | + |
| 335 | + const handleEditChange = (field, value) => { |
| 336 | + setEditedActivity(prev => ({ |
| 337 | + ...prev, |
| 338 | + [field]: value |
| 339 | + })); |
| 340 | + }; |
| 341 | + |
259 | 342 | return (
|
260 | 343 | <div style={styles.container}>
|
261 | 344 | <Snackbar
|
@@ -360,53 +443,130 @@ export default function Home() {
|
360 | 443 | <TabPanel value={value} index={1}>
|
361 | 444 | <div style={styles.activitiesGrid}>
|
362 | 445 | {participantActivities.map((activity, index) => {
|
363 |
| - console.log("participantActivities", activity); |
364 | 446 | const isAdmin = activity.role === "ADMIN";
|
| 447 | + const isEditing = editingActivity === activity.activityId; |
365 | 448 | const startDate = new Date(activity.startDateTime);
|
366 | 449 | const endDate = new Date(activity.endDateTime);
|
367 | 450 | const formatDateTime = (date) =>
|
368 | 451 | `${date.toLocaleDateString()} ${date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}`;
|
369 | 452 |
|
370 | 453 | return (
|
371 | 454 | <div key={index} style={styles.activityCard}>
|
372 |
| - <h3 style={styles.activityTitle}>{activity.name}</h3> |
373 |
| - <p style={styles.activityDescription}>{activity.description}</p> |
374 |
| - <div style={styles.activityDetails}> |
375 |
| - <div style={styles.activityMeta}> |
376 |
| - <span style={styles.metaIcon}>🕐</span> |
377 |
| - <span> |
378 |
| - <strong>Start:</strong> {formatDateTime(startDate)} |
379 |
| - </span> |
380 |
| - </div> |
381 |
| - <div style={styles.activityMeta}> |
382 |
| - <span style={styles.metaIcon}>🕕</span> |
383 |
| - <span> |
384 |
| - <strong>End:</strong> {formatDateTime(endDate)} |
385 |
| - </span> |
386 |
| - </div> |
387 |
| - <div style={styles.activityMeta}> |
388 |
| - <span style={styles.metaIcon}>📍</span> |
389 |
| - <span>{activity.location}</span> |
390 |
| - </div> |
391 |
| - </div> |
392 |
| - <div style={styles.activityActions}> |
393 |
| - <ParticipantsList |
394 |
| - activityId={activity.activityId} |
395 |
| - onError={(message) => setNotification({ |
396 |
| - open: true, |
397 |
| - message, |
398 |
| - severity: "error", |
399 |
| - })} |
400 |
| - /> |
401 |
| - <button |
402 |
| - style={styles.joinButton} |
403 |
| - onClick={() => |
404 |
| - isAdmin ? handleDeleteActivity(activity.activityId) : handleLeaveActivity(activity.activityId) |
405 |
| - } |
406 |
| - > |
407 |
| - {isAdmin ? "Delete Activity" : "Leave Activity"} |
408 |
| - </button> |
409 |
| - </div> |
| 455 | + {isEditing ? ( |
| 456 | + <> |
| 457 | + <TextField |
| 458 | + fullWidth |
| 459 | + value={editedActivity.name} |
| 460 | + onChange={(e) => handleEditChange("name", e.target.value)} |
| 461 | + margin="normal" |
| 462 | + label="Activity Name" |
| 463 | + /> |
| 464 | + <TextField |
| 465 | + fullWidth |
| 466 | + multiline |
| 467 | + rows={3} |
| 468 | + value={editedActivity.description} |
| 469 | + onChange={(e) => handleEditChange("description", e.target.value)} |
| 470 | + margin="normal" |
| 471 | + label="Description" |
| 472 | + /> |
| 473 | + <TextField |
| 474 | + fullWidth |
| 475 | + value={editedActivity.location} |
| 476 | + onChange={(e) => handleEditChange("location", e.target.value)} |
| 477 | + margin="normal" |
| 478 | + label="Location" |
| 479 | + /> |
| 480 | + <TextField |
| 481 | + fullWidth |
| 482 | + type="datetime-local" |
| 483 | + value={editedActivity.startDateTime.slice(0, 16)} |
| 484 | + onChange={(e) => handleEditChange("startDateTime", e.target.value)} |
| 485 | + margin="normal" |
| 486 | + label="Start Time" |
| 487 | + InputLabelProps={{ shrink: true }} |
| 488 | + /> |
| 489 | + <TextField |
| 490 | + fullWidth |
| 491 | + type="datetime-local" |
| 492 | + value={editedActivity.endDateTime.slice(0, 16)} |
| 493 | + onChange={(e) => handleEditChange("endDateTime", e.target.value)} |
| 494 | + margin="normal" |
| 495 | + label="End Time" |
| 496 | + InputLabelProps={{ shrink: true }} |
| 497 | + /> |
| 498 | + <div style={styles.editActions}> |
| 499 | + <Button |
| 500 | + variant="contained" |
| 501 | + color="primary" |
| 502 | + startIcon={<SaveIcon />} |
| 503 | + onClick={() => handleSaveEdit(activity.activityId)} |
| 504 | + > |
| 505 | + Save |
| 506 | + </Button> |
| 507 | + <Button |
| 508 | + variant="outlined" |
| 509 | + color="secondary" |
| 510 | + startIcon={<CancelIcon />} |
| 511 | + onClick={handleCancelEdit} |
| 512 | + > |
| 513 | + Cancel |
| 514 | + </Button> |
| 515 | + </div> |
| 516 | + </> |
| 517 | + ) : ( |
| 518 | + <> |
| 519 | + <h3 style={styles.activityTitle}>{activity.name}</h3> |
| 520 | + <p style={styles.activityDescription}>{activity.description}</p> |
| 521 | + <div style={styles.activityDetails}> |
| 522 | + <div style={styles.activityMeta}> |
| 523 | + <span style={styles.metaIcon}>🕐</span> |
| 524 | + <span> |
| 525 | + <strong>Start:</strong> {formatDateTime(startDate)} |
| 526 | + </span> |
| 527 | + </div> |
| 528 | + <div style={styles.activityMeta}> |
| 529 | + <span style={styles.metaIcon}>🕕</span> |
| 530 | + <span> |
| 531 | + <strong>End:</strong> {formatDateTime(endDate)} |
| 532 | + </span> |
| 533 | + </div> |
| 534 | + <div style={styles.activityMeta}> |
| 535 | + <span style={styles.metaIcon}>📍</span> |
| 536 | + <span>{activity.location}</span> |
| 537 | + </div> |
| 538 | + </div> |
| 539 | + <div style={styles.activityActions}> |
| 540 | + <ParticipantsList |
| 541 | + activityId={activity.activityId} |
| 542 | + onError={(message) => setNotification({ |
| 543 | + open: true, |
| 544 | + message, |
| 545 | + severity: "error", |
| 546 | + })} |
| 547 | + /> |
| 548 | + {isAdmin && ( |
| 549 | + <Button |
| 550 | + variant="outlined" |
| 551 | + color="primary" |
| 552 | + startIcon={<EditIcon />} |
| 553 | + onClick={() => handleEditActivity(activity)} |
| 554 | + style={styles.editButton} |
| 555 | + > |
| 556 | + Edit Activity |
| 557 | + </Button> |
| 558 | + )} |
| 559 | + <button |
| 560 | + style={styles.joinButton} |
| 561 | + onClick={() => |
| 562 | + isAdmin ? handleDeleteActivity(activity.activityId) : handleLeaveActivity(activity.activityId) |
| 563 | + } |
| 564 | + > |
| 565 | + {isAdmin ? "Delete Activity" : "Leave Activity"} |
| 566 | + </button> |
| 567 | + </div> |
| 568 | + </> |
| 569 | + )} |
410 | 570 | </div>
|
411 | 571 | );
|
412 | 572 | })}
|
@@ -678,4 +838,13 @@ const styles = {
|
678 | 838 | margin: "0 auto",
|
679 | 839 | boxSizing: "border-box",
|
680 | 840 | },
|
| 841 | + editActions: { |
| 842 | + display: "flex", |
| 843 | + gap: "1rem", |
| 844 | + marginTop: "1rem", |
| 845 | + justifyContent: "center", |
| 846 | + }, |
| 847 | + editButton: { |
| 848 | + marginBottom: "0.5rem", |
| 849 | + }, |
681 | 850 | };
|
0 commit comments