From 17cd765336b5a01e9faaa4dd3201e58334837d1b Mon Sep 17 00:00:00 2001 From: Hana Zaraa Date: Tue, 27 Dec 2022 09:06:28 +0100 Subject: [PATCH 1/2] delete room --- hivelvet-backend/app/config/routes.ini | 1 + .../app/src/Actions/Rooms/Delete.php | 34 +++++++++ hivelvet-backend/app/src/Models/Room.php | 44 ++++++++++++ hivelvet-frontend/src/components/Presets.tsx | 3 +- hivelvet-frontend/src/components/Roles.tsx | 1 + hivelvet-frontend/src/components/Rooms.tsx | 71 ++++++++++++------- hivelvet-frontend/src/locale/ar-TN.json | 3 +- hivelvet-frontend/src/locale/en-US.json | 3 +- hivelvet-frontend/src/locale/fr-FR.json | 3 +- .../src/routing/backend-config.tsx | 1 + .../src/services/rooms.service.ts | 3 + 11 files changed, 137 insertions(+), 30 deletions(-) create mode 100644 hivelvet-backend/app/src/Actions/Rooms/Delete.php diff --git a/hivelvet-backend/app/config/routes.ini b/hivelvet-backend/app/config/routes.ini index 928fa374..e25fbd76 100644 --- a/hivelvet-backend/app/config/routes.ini +++ b/hivelvet-backend/app/config/routes.ini @@ -77,3 +77,4 @@ DELETE @label_delete : /labels/@id = Actions\Labels\Delete->execut ; rooms routes GET @rooms_index : /rooms/@user_id = Actions\Rooms\Index->show POST @rooms_add : /rooms = Actions\Rooms\Add->save +DELETE @room_delete : /rooms/@id = Actions\Rooms\Delete->execute \ No newline at end of file diff --git a/hivelvet-backend/app/src/Actions/Rooms/Delete.php b/hivelvet-backend/app/src/Actions/Rooms/Delete.php new file mode 100644 index 00000000..88112225 --- /dev/null +++ b/hivelvet-backend/app/src/Actions/Rooms/Delete.php @@ -0,0 +1,34 @@ +. + */ +namespace Actions\Rooms; + +use Actions\Delete as DeleteAction; +use Actions\RequirePrivilegeTrait; + +/** + * Class Delete. + */ +class Delete extends DeleteAction +{ + use RequirePrivilegeTrait; + + protected $deleteMethodName = 'delete'; +} diff --git a/hivelvet-backend/app/src/Models/Room.php b/hivelvet-backend/app/src/Models/Room.php index 34d3c1fb..43eafdb6 100644 --- a/hivelvet-backend/app/src/Models/Room.php +++ b/hivelvet-backend/app/src/Models/Room.php @@ -22,6 +22,7 @@ namespace Models; +use Enum\ResponseCode; use Models\Base as BaseModel; /** @@ -116,4 +117,47 @@ public function getLabels($room): array return $lbs; } + /** + * Delete a room if it's allowed and removing its associated roomlabels. + * + * @return Array[2](Array[], ResponsCode) + */ + public function delete(): array + { + // delete associated roomslabels + $result = $this->deleteRoomsLabels(); + + if ($result) { + try { + $this->erase(); + $this->logger->info('Room successfully deleted', ['room' => $this->toArray()]); + } catch (\Exception $e) { + $this->logger->error('room could not be deleted', ['room' => $this->toArray(), 'error' => $e->getMessage()]); + + throw $e; + } + + return [['result' => 'success'], ResponseCode::HTTP_OK]; + } + + return [[], ResponseCode::HTTP_FORBIDDEN]; + } + public function deleteRoomsLabels(): bool + { + $this->logger->info('Starting delete rooms labels transaction.'); + $this->db->begin(); + $roomId = $this->id; + + $roomlabel = new RoomLabel(); + $deleteResult = $roomlabel->erase(['room_id = ?', $roomId]); + if ($deleteResult) { + $this->logger->info('All Rooms Labels successfully deleted'); + $this->db->commit(); + $this->logger->info('Delete rooms and its associations transaction successfully commit.'); + + return true; + } + + return false; + } } diff --git a/hivelvet-frontend/src/components/Presets.tsx b/hivelvet-frontend/src/components/Presets.tsx index 918178fb..ee24d2cd 100644 --- a/hivelvet-frontend/src/components/Presets.tsx +++ b/hivelvet-frontend/src/components/Presets.tsx @@ -488,7 +488,8 @@ const Presets = () => { //delete const deletePreset = (id) => { PresetsService.delete_preset(id) - .then(() => { + .then((response) => { + console.log(response); setMyPresets(myPresets.filter((p) => p.id != id)); const indexPreset = dataContext.dataPresets.findIndex((item) => id === item.id); if (indexPreset !== -1) { diff --git a/hivelvet-frontend/src/components/Roles.tsx b/hivelvet-frontend/src/components/Roles.tsx index 05a02610..795972c5 100644 --- a/hivelvet-frontend/src/components/Roles.tsx +++ b/hivelvet-frontend/src/components/Roles.tsx @@ -84,6 +84,7 @@ const Roles = () => { const getPrivileges = () => { RolesService.list_permissions() .then((response) => { + console.log(response); const privileges = response.data; if (privileges instanceof Object) { setAllPrivileges(privileges); diff --git a/hivelvet-frontend/src/components/Rooms.tsx b/hivelvet-frontend/src/components/Rooms.tsx index 2eb3d0c4..3818cadc 100644 --- a/hivelvet-frontend/src/components/Rooms.tsx +++ b/hivelvet-frontend/src/components/Rooms.tsx @@ -27,52 +27,57 @@ import Home from './Home'; import { Link, useNavigate } from 'react-router-dom'; import { Trans } from 'react-i18next'; -import { Avatar, Badge, Card, Col, Dropdown, Row, Space, Tag, Typography } from 'antd'; +import { Avatar, Badge, Card, Col, Dropdown, Row, Space, Tag, Typography,Menu } from 'antd'; import { RoomType } from 'types/RoomType'; import { ClockCircleOutlined, MoreOutlined, TeamOutlined } from '@ant-design/icons'; import LocaleService from '../services/locale.service'; import { MenuProps } from 'antd/lib/menu'; - +import { axiosInstance } from 'lib/AxiosInstance'; +import roomsService from 'services/rooms.service'; +import Notifications from './Notifications'; + +import { t } from 'i18next'; const { Title } = Typography; interface RoomsColProps { index: number; room: RoomType; - clickHandler: (room: RoomType) => void; + rooms:RoomType[]; + deleteClickHandler: () => void; + // clickHandler: (room: RoomType) => void; } -const RoomsCol: React.FC = ({ index, room, clickHandler }) => { +const RoomsCol: React.FC = ({ index, room,rooms,deleteClickHandler }) => { const labels = []; + const navigate = useNavigate(); room.labels.map((item) => { labels.push(item); }); - const actions: MenuProps['items'] = [ - { - key: '1', - label: ( - - - - ), - }, - { - type: 'divider', - }, - { - key: '2', - danger: true, - label: , - }, - ]; + //delete + const handleDelete = () => { + deleteClickHandler(); +}; + const actions = + + navigate('/rooms/details', { state: { room: room } })}> + + + + handleDelete()}> + + + + + return ( clickHandler(room)} + //onClick={() => clickHandler(room)} title={ = ({ index, room, clickHandler }) => { extra={ @@ -134,8 +139,20 @@ const RoomsCol: React.FC = ({ index, room, clickHandler }) => { const Rooms = () => { const dataContext = React.useContext(DataContext); + const [rooms,setRooms]=React.useState(dataContext.dataRooms); const navigate = useNavigate(); - + const deleteRoom=(id,index)=>{ + console.log("delete room"); + roomsService.delete_room(id) + .then((result)=>{ + console.log(result); + rooms.splice(index,1); + Notifications.openNotificationWithIcon('success', t('delete_room_success')); + }) + .catch((error)=>{ + console.log(error); + }) + } const showRoomDetails = (room: RoomType) => { navigate('/rooms/details', { state: { room: room } }); }; @@ -151,7 +168,9 @@ const Rooms = () => { key={index + '-' + singleRoom.name} index={index} room={singleRoom} - clickHandler={showRoomDetails} + rooms={rooms} + deleteClickHandler={deleteRoom.bind(this, singleRoom.id)} + //clickHandler={showRoomDetails} /> ))} diff --git a/hivelvet-frontend/src/locale/ar-TN.json b/hivelvet-frontend/src/locale/ar-TN.json index 41e84573..37f2f790 100644 --- a/hivelvet-frontend/src/locale/ar-TN.json +++ b/hivelvet-frontend/src/locale/ar-TN.json @@ -286,5 +286,6 @@ "attendees": "الحاضرون", "publish": "نشر", "replay": "إعادة", - "mb": "م.ب" + "mb": "م.ب", + "delete_room_success": "تم حذف القاعة بنجاح" } diff --git a/hivelvet-frontend/src/locale/en-US.json b/hivelvet-frontend/src/locale/en-US.json index 00143159..18355201 100644 --- a/hivelvet-frontend/src/locale/en-US.json +++ b/hivelvet-frontend/src/locale/en-US.json @@ -286,5 +286,6 @@ "attendees": "Attendees", "publish": "Publish", "replay": "Replay", - "mb": "MB" + "mb": "MB", + "delete_room_success": "Room successfully deleted" } diff --git a/hivelvet-frontend/src/locale/fr-FR.json b/hivelvet-frontend/src/locale/fr-FR.json index 5d7eb1ae..472bec46 100644 --- a/hivelvet-frontend/src/locale/fr-FR.json +++ b/hivelvet-frontend/src/locale/fr-FR.json @@ -286,5 +286,6 @@ "attendees": "Participants", "publish": "Publier", "replay": "Rejouer", - "mb": "Mo" + "mb": "Mo", + "delete_room_success": "Salle a été supprimée avec succés" } diff --git a/hivelvet-frontend/src/routing/backend-config.tsx b/hivelvet-frontend/src/routing/backend-config.tsx index 89c659c9..ea76e97f 100644 --- a/hivelvet-frontend/src/routing/backend-config.tsx +++ b/hivelvet-frontend/src/routing/backend-config.tsx @@ -62,4 +62,5 @@ export const apiRoutes = { LIST_ROOMS_URL: API_URL + '/rooms/', ADD_ROOM_URL: API_URL + '/rooms', + DELETE_ROOM_URL: API_URL + '/rooms/' }; diff --git a/hivelvet-frontend/src/services/rooms.service.ts b/hivelvet-frontend/src/services/rooms.service.ts index ec71ce41..68618f5e 100644 --- a/hivelvet-frontend/src/services/rooms.service.ts +++ b/hivelvet-frontend/src/services/rooms.service.ts @@ -30,6 +30,9 @@ class RoomsService { user_id, }); } + delete_room(id: number) { + return axiosInstance.delete(apiRoutes.DELETE_ROOM_URL + id); + } } export default new RoomsService(); From 28420e801fa08e56bff33853d111de8a06c944eb Mon Sep 17 00:00:00 2001 From: Hana Zaraa Date: Tue, 27 Dec 2022 15:29:30 +0100 Subject: [PATCH 2/2] edit room --- hivelvet-backend/app/config/routes.ini | 1 + .../app/src/Actions/Rooms/Edit.php | 84 + hivelvet-backend/app/src/Models/Room.php | 10 + .../src/components/RoomDetails.tsx | 125 +- hivelvet-frontend/src/components/Rooms.tsx | 91 +- hivelvet-frontend/src/locale/ar-TN.json | 3 +- hivelvet-frontend/src/locale/en-US.json | 3 +- hivelvet-frontend/src/locale/fr-FR.json | 3 +- .../src/routing/backend-config.tsx | 3 +- .../src/services/rooms.service.ts | 5 + hivelvet-frontend/yarn.lock | 33458 +++++++++------- 11 files changed, 19741 insertions(+), 14045 deletions(-) create mode 100644 hivelvet-backend/app/src/Actions/Rooms/Edit.php diff --git a/hivelvet-backend/app/config/routes.ini b/hivelvet-backend/app/config/routes.ini index e25fbd76..5d809da0 100644 --- a/hivelvet-backend/app/config/routes.ini +++ b/hivelvet-backend/app/config/routes.ini @@ -77,4 +77,5 @@ DELETE @label_delete : /labels/@id = Actions\Labels\Delete->execut ; rooms routes GET @rooms_index : /rooms/@user_id = Actions\Rooms\Index->show POST @rooms_add : /rooms = Actions\Rooms\Add->save +PUT @rooms_edit : /rooms/@id = Actions\Rooms\Edit->rename DELETE @room_delete : /rooms/@id = Actions\Rooms\Delete->execute \ No newline at end of file diff --git a/hivelvet-backend/app/src/Actions/Rooms/Edit.php b/hivelvet-backend/app/src/Actions/Rooms/Edit.php new file mode 100644 index 00000000..ee250885 --- /dev/null +++ b/hivelvet-backend/app/src/Actions/Rooms/Edit.php @@ -0,0 +1,84 @@ +. + */ + +namespace Actions\Rooms; + +use Actions\Base as BaseAction; +use Actions\RequirePrivilegeTrait; +use Enum\ResponseCode; +use Models\Preset; +use Models\Room; +use Respect\Validation\Validator; +use Validation\DataChecker; + +class Edit extends BaseAction +{ + use RequirePrivilegeTrait; + + /** + * @param \Base $f3 + * @param array $params + */ + public function rename($f3, $params): void + { + $body = $this->getDecodedBody(); + $form = $body['data']; + + $id = $params['id']; + $dataChecker = new DataChecker(); + + $dataChecker->verify($form['name'], Validator::notEmpty()->setName('name')); + $dataChecker->verify($id, Validator::notEmpty()->setName('id')); + + $errorMessage = 'Room could not be updated'; + + $room= new Room(); + $room = $room->getById($id); + if ($room->valid()) { + if ($dataChecker->allValid()) { + $checkRoom = new Room(); + $room->name = $form['name']; + + if ($checkRoom->nameExists($room->name, $room->user_id, $room->id)) { + $this->logger->error($errorMessage, ['error' => 'Name already exists']); + $this->renderJson(['errors' => ['name' => 'Name already exists']], ResponseCode::HTTP_PRECONDITION_FAILED); + } else { + try { + $room->save(); + } catch (\Exception $e) { + $this->logger->error($errorMessage, ['error' => $e->getMessage()]); + $this->renderJson(['errors' => $e->getMessage()], ResponseCode::HTTP_INTERNAL_SERVER_ERROR); + + return; + } + $this->logger->info('room successfully updated', ['room' => $room->toArray()]); + $this->renderJson(['result' => 'success', 'room' => $room->getRoomInfos($room->id)]); + } + } else { + $this->logger->error($errorMessage, ['errors' => $dataChecker->getErrors()]); + $this->renderJson(['errors' => $dataChecker->getErrors()], ResponseCode::HTTP_UNPROCESSABLE_ENTITY); + } + } else { + $this->logger->error($errorMessage); + $this->renderJson([], ResponseCode::HTTP_NOT_FOUND); + } + } +} \ No newline at end of file diff --git a/hivelvet-backend/app/src/Models/Room.php b/hivelvet-backend/app/src/Models/Room.php index 43eafdb6..5ca64ced 100644 --- a/hivelvet-backend/app/src/Models/Room.php +++ b/hivelvet-backend/app/src/Models/Room.php @@ -51,7 +51,17 @@ public function nameExists($name, $userId, $id = null) { return $this->load(['lower(name) = ? and user_id = ? and id != ?', mb_strtolower($name), $userId, $id]); } + /** + * Get room record by id value. + * + * @return $this + */ + public function getById( $id): self + { + $this->load(['id = ?', $id]); + return $this; + } public function collectAllByUserId($userId): array { return $this->db->exec('SELECT id, name, short_link, preset_id FROM rooms where user_id =?', $userId); diff --git a/hivelvet-frontend/src/components/RoomDetails.tsx b/hivelvet-frontend/src/components/RoomDetails.tsx index b677046d..f33098ea 100644 --- a/hivelvet-frontend/src/components/RoomDetails.tsx +++ b/hivelvet-frontend/src/components/RoomDetails.tsx @@ -20,8 +20,10 @@ import React, { useState } from 'react'; import { Trans, withTranslation } from 'react-i18next'; import { useLocation } from 'react-router-dom'; import { t } from 'i18next'; - +import { Form } from 'antd'; import { CopyToClipboard } from 'react-copy-to-clipboard'; +import { PageHeader, Popconfirm, Popover, Switch, message, InputNumber, Empty, Spin } from 'antd'; +import { CloseOutlined, DeleteOutlined, QuestionCircleOutlined, UploadOutlined } from '@ant-design/icons'; import { CalendarOutlined, @@ -48,12 +50,18 @@ import { RecordingType } from '../types/RecordingType'; import DynamicIcon from './DynamicIcon'; import { MenuProps } from 'antd/lib/menu'; import LocaleService from '../services/locale.service'; - +import EN_US from '../locale/en-US.json'; +import roomsService from 'services/rooms.service'; +import Notifications from './Notifications'; const { Title } = Typography; - +type formType = { + name: string; +}; const RoomDetails = () => { const { state } = useLocation(); const currentRoom: RoomType = state.room; + const [room, setRoom] = React.useState(state.room); + const recordings: RecordingType[] = [ { id: 1, @@ -99,9 +107,11 @@ const RoomDetails = () => { }, ]; const [copied, setCopied] = useState(false); + const [errorsEdit, setErrorsEdit] = React.useState({}); const [previewOpen, setPreviewOpen] = useState(false); const [previewImage, setPreviewImage] = useState(''); + const [isEditing, setIsEditing] = React.useState(false); const [fileList, setFileList] = useState([ { uid: '-1', @@ -184,21 +194,122 @@ const RoomDetails = () => { ); + const [editForm] = Form.useForm(); + const toggleEdit = () => { + setIsEditing(true); + editForm.setFieldsValue({ name: room ? room.name : currentRoom.name }); + }; + const cancelEdit = () => { + setErrorsEdit({}); + setIsEditing(false); + }; + const handleSaveEdit = async () => { + setErrorsEdit({}); + try { + const values = (await editForm.validateFields()) as formType; + + roomsService + .edit_room(values, currentRoom.id) + .then((response) => { + setRoom(response.data.room); + Notifications.openNotificationWithIcon('success', t('edit_room_success')); + + cancelEdit(); + }) + .catch((error) => { + const responseData = error.response.data; + if (responseData.errors) { + setErrorsEdit(responseData.errors); + } + console.log(error); + }); + } catch (errInfo) { + console.log('Save failed:', errInfo); + } + }; return (
- + {!isEditing ? ( + + ) : ( + <> + )} - {currentRoom.name} + {!isEditing ? ( + <> + {room ? room.name : currentRoom.name} + + ) : ( + <> +
+ EN_US[elem] == errorsEdit['name'] + )} + /> + ), + validateStatus: 'error', + })} + rules={[ + { + required: true, + message: , + }, + ]} + > + + cancelEdit()} + > +