Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IDOL, shoutouts] - edit shoutouts #578

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions backend/src/API/shoutoutAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,24 @@ export const hideShoutout = async (
await shoutoutsDao.updateShoutout({ ...shoutout, hidden: hide });
};

export const editShoutout = async (
uuid: string,
newMessage: string,
user: IdolMember
): Promise<Shoutout> => {
const shoutout = await shoutoutsDao.getShoutout(uuid);
kevinmram marked this conversation as resolved.
Show resolved Hide resolved
if (!shoutout) {
throw new NotFoundError(`Shoutout with uuid: ${uuid} does not exist!`);
}
if (shoutout.giver.email !== user.email && !(await PermissionsManager.isLeadOrAdmin(user))) {
throw new PermissionError(
`User with email: ${user.email} is not authorized to edit this shoutout!`
);
}
const updatedShoutout = { ...shoutout, message: newMessage };
return shoutoutsDao.updateShoutout(updatedShoutout);
};

export const deleteShoutout = async (uuid: string, user: IdolMember): Promise<void> => {
const shoutout = await shoutoutsDao.getShoutout(uuid);
if (!shoutout) {
Expand Down
20 changes: 20 additions & 0 deletions frontend/src/API/ShoutoutsAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,26 @@ export default class ShoutoutsAPI {
return APIWrapper.put(`${backendURL}/shoutout`, { uuid, hide }).then((res) => res.data);
}

public static updateShoutout(
uuid: string,
shoutout: Partial<Shoutout>
kevinmram marked this conversation as resolved.
Show resolved Hide resolved
): Promise<ShoutoutResponseObj> {
return APIWrapper.put(`${backendURL}/shoutout/${uuid}`, shoutout).then((res) => res.data);
}

public static editShoutout(uuid: string, message: string): Promise<ShoutoutResponseObj> {
return APIWrapper.put(`${backendURL}/shoutout/${uuid}`, { message }).then((res) => {
if (res.data.error) {
Emitters.generalError.emit({
headerMsg: "Couldn't edit shoutout",
contentMsg: `Error was: ${res.data.error}`
});
return { error: res.data.error };
}
return res.data;
});
}

public static async deleteShoutout(uuid: string): Promise<void> {
await APIWrapper.delete(`${backendURL}/shoutout/${uuid}`);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,22 @@
display: inline-block;
padding-left: 1.5rem;
padding-bottom: 1rem;
align-self: left;
}

.shoutoutDelete {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 0 !important;
margin-bottom: 0 !important;
}

.shoutoutActions {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 1.5rem;
margin-top: 1.0rem;
margin-right: 1.0rem;
margin-bottom: 1.0rem;
}
86 changes: 71 additions & 15 deletions frontend/src/components/Forms/ShoutoutsPage/ShoutoutCard.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,86 @@
import { Card } from 'semantic-ui-react';
import React, { useState } from 'react';
import { Button, Card, Form, Icon, Modal, TextArea } from 'semantic-ui-react';
import ShoutoutsAPI from '../../../API/ShoutoutsAPI';
import ShoutoutDeleteModal from '../../Modals/ShoutoutDeleteModal';
import { Emitters } from '../../../utils';
import styles from './ShoutoutCard.module.css';

const ShoutoutCard = (props: {
shoutout: Shoutout;
setGivenShoutouts: React.Dispatch<React.SetStateAction<Shoutout[]>>;
}): JSX.Element => {
const { shoutout, setGivenShoutouts } = props;
const ShoutoutCard = ({ shoutout, setGivenShoutouts }) => {
const [isEditing, setIsEditing] = useState(false);
kevinmram marked this conversation as resolved.
Show resolved Hide resolved
const [editedMessage, setEditedMessage] = useState(shoutout.message);

const fromString = shoutout.isAnon
? 'From: Anonymous'
: `From: ${shoutout.giver?.firstName} ${shoutout.giver?.lastName}`;
const dateString = `${new Date(shoutout.timestamp).toDateString()}`;
const handleEditShoutout = () => {
ShoutoutsAPI.editShoutout(shoutout.uuid, editedMessage).then((response) => {
if (!response.error) {
setGivenShoutouts((prevShoutouts) =>
prevShoutouts.map((s) =>
s.uuid === shoutout.uuid ? { ...s, message: editedMessage } : s
)
);
Emitters.generalSuccess.emit({
headerMsg: 'Success!',
contentMsg: 'The shoutout message updated successfully.'
});
setIsEditing(false);
} else {
Emitters.generalError.emit({
headerMsg: 'Error',
contentMsg: `The shoutout message failed to update...: ${response.error}`
});
}
});
};

return (
<Card className={styles.shoutoutCardContainer}>
<Card.Group widths="equal" className={styles.shoutoutCardDetails}>
<Card.Content header={`To: ${shoutout.receiver}`} className={styles.shoutoutTo} />
<Card.Content className={styles.shoutoutDate} content={dateString} />
</Card.Group>
<Card.Group widths="equal" className={styles.shoutoutDelete}>
<Card.Meta className={styles.shoutoutFrom} content={fromString} />
<ShoutoutDeleteModal uuid={shoutout.uuid} setGivenShoutouts={setGivenShoutouts} />
<Card.Content
className={styles.shoutoutDate}
content={new Date(shoutout.timestamp).toDateString()}
/>
</Card.Group>
<div className={styles.shoutoutActions}>
<Card.Meta
className={styles.shoutoutFrom}
content={
shoutout.isAnon
? 'From: Anonymous'
: `From: ${shoutout.giver.firstName} ${shoutout.giver.lastName}`
}
/>
<div>
<ShoutoutDeleteModal uuid={shoutout.uuid} setGivenShoutouts={setGivenShoutouts} />
<Button icon onClick={() => setIsEditing(true)}>
<Icon name="edit" />
</Button>
</div>
</div>
<Card.Content description={shoutout.message} />
<Modal open={isEditing} onClose={() => setIsEditing(false)}>
<Modal.Header>Edit Shoutout</Modal.Header>
<Modal.Content>
<Form>
<Form.Field>
<label>Message</label>
<TextArea
value={editedMessage}
onChange={(e, { value }) => setEditedMessage(value)}
/>
</Form.Field>
</Form>
</Modal.Content>
<Modal.Actions>
<Button onClick={() => setIsEditing(false)} negative>
Cancel
</Button>
<Button onClick={handleEditShoutout} positive>
Save
</Button>
</Modal.Actions>
</Modal>
</Card>
);
};

export default ShoutoutCard;
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.trashIcon {
position: absolute;
right: 1%;
}
margin-top: 2.0rem;
position: relative;
right: 10%;
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,6 @@
"**/*.{ts,js,tsx,scss,css,html,md}": [
"yarn prettier --write"
]
}
},
"dependencies": {}
}
Loading