diff --git a/src/components/Addbar.jsx b/src/components/Addbar.jsx index 23f3ed1..0013eff 100644 --- a/src/components/Addbar.jsx +++ b/src/components/Addbar.jsx @@ -284,7 +284,7 @@ function AddBar(props) { id="item-target-page" value={pageIndex} className="form-select rounded-4 text-center text-white bg-steel-blue fs-6 fw-medium border-0" - onChange={(e) => setItemTarget((prev) => ({ group: '', page: e.target.value }))} + onChange={(e) => setItemTarget(() => ({ group: '', page: e.target.value }))} > {protocol.pages.map((page, index) => ( diff --git a/src/components/CreateProcotolProperties.jsx b/src/components/CreateProcotolProperties.jsx index e8438a3..67b3084 100644 --- a/src/components/CreateProcotolProperties.jsx +++ b/src/components/CreateProcotolProperties.jsx @@ -79,7 +79,7 @@ function CreateProtocolProperties(props) { setSearchedOptions((prev) => ({ ...prev, appliers: newUsers })); } }) - .catch((error) => showAlert({ headerText: 'Erro ao buscar usuários.', bodyText: error.response?.data.message })); + .catch((error) => showAlert({ headerText: 'Erro ao buscar usuários', bodyText: error.response?.data.message })); }; const searchClassrooms = (term, target) => { @@ -118,7 +118,7 @@ function CreateProtocolProperties(props) { setSearchedOptions((prev) => ({ ...prev, answersViewersClassroom: concatenedClassrooms })); } }) - .catch((error) => showAlert({ headerText: 'Erro ao buscar grupos.', bodyText: error.response?.data.message })); + .catch((error) => showAlert({ headerText: 'Erro ao buscar grupos', bodyText: error.response?.data.message })); }; const unselectUser = (id, target) => { diff --git a/src/pages/ApplicationAnswersPage.jsx b/src/pages/ApplicationAnswersPage.jsx index eec74bb..388b248 100644 --- a/src/pages/ApplicationAnswersPage.jsx +++ b/src/pages/ApplicationAnswersPage.jsx @@ -90,27 +90,21 @@ function AnswerPage(props) { if (isLoading && user.status !== 'loading') { axios .get(`${process.env.REACT_APP_API_URL}api/application/getApplicationWithAnswers/${applicationId}`, { - headers: { - Authorization: `Bearer ${user.token}`, - }, + headers: { Authorization: `Bearer ${user.token}` }, }) .then((response) => { setAnswer(response.data.data); setIsLoading(false); }) - .catch((error) => { - setError({ text: 'Erro ao carregar respostas de aplicação', description: error.response?.data.message || '' }); - }); + .catch((error) => + setError({ text: 'Erro ao obter respostas da aplicação', description: error.response?.data.message || '' }) + ); } }, [applicationId, isLoading, user.status, user.token]); - if (error) { - return ; - } + if (error) return ; - if (isLoading) { - return ; - } + if (isLoading) return ; // Função de exportar csv const createFile = (modalRef) => { @@ -321,11 +315,7 @@ function AnswerPage(props) { .put( `${process.env.REACT_APP_API_URL}api/applicationAnswer/approveApplicationAnswer/${applicationAnswerId}`, {}, - { - headers: { - Authorization: `Bearer ${user.token}`, - }, - } + { headers: { Authorization: `Bearer ${user.token}` } } ) .then((response) => { showAlert({ headerText: 'Resposta aprovada com sucesso', message: response.data.message }); @@ -399,7 +389,7 @@ function AnswerPage(props) { {value.user.username + ' - ' + new Date(value.date).toLocaleDateString()} - {value.approved !== true && ( + {value.approved !== true && answer.actions.toApproveAnswers === true && (
{ for (const group in itemAnswerGroups) { let res = undefined; - if (itemAnswerGroups[group].itemAnswers[id] !== undefined) { - res = itemAnswerGroups[group].itemAnswers[id]; - } - if (itemAnswerGroups[group].optionAnswers[id] !== undefined) { - res = itemAnswerGroups[group].optionAnswers[id]; - } - if (itemAnswerGroups[group].tableAnswers[id] !== undefined) { - res = itemAnswerGroups[group].tableAnswers[id]; - } + if (itemAnswerGroups[group].itemAnswers[id] !== undefined) res = itemAnswerGroups[group].itemAnswers[id]; + if (itemAnswerGroups[group].optionAnswers[id] !== undefined) res = itemAnswerGroups[group].optionAnswers[id]; + if (itemAnswerGroups[group].tableAnswers[id] !== undefined) res = itemAnswerGroups[group].tableAnswers[id]; if (res !== undefined) { // Drop group and files from res let { group, files, ...answer } = res; @@ -105,15 +99,9 @@ function ApplicationPage(props) { }; const findItem = (id) => { - for (const page of application.protocol.pages) { - for (const group of page.itemGroups) { - for (const item of group.items) { - if (item.id === id) { - return item; - } - } - } - } + for (const page of application.protocol.pages) + for (const group of page.itemGroups) for (const item of group.items) if (item.id === id) return item; + return undefined; }; @@ -125,9 +113,7 @@ function ApplicationPage(props) { switch (dependency.type) { case 'EXACT_ANSWER': if (item.type === 'TEXTBOX' || item.type === 'NUMBERBOX') { - if (!answer || answer.text !== dependency.argument) { - dependencyAttended = false; - } + if (!answer || answer.text !== dependency.argument) dependencyAttended = false; } else if (item.type === 'CHECKBOX' || item.type === 'RADIO' || item.type === 'SELECT') { if ( !answer || @@ -135,9 +121,8 @@ function ApplicationPage(props) { .filter((o) => Object.keys(answer).includes(o.id.toString())) .map((o) => o.text) .includes(dependency.argument) === false - ) { + ) dependencyAttended = false; - } } break; case 'OPTION_SELECTED': @@ -148,39 +133,26 @@ function ApplicationPage(props) { .filter((o) => Object.keys(answer).includes(o.id.toString())) .map((o) => o.text) .includes(dependency.argument) === false - ) { + ) dependencyAttended = false; - } } break; case 'MIN': if (item.type === 'CHECKBOX') { - if (!answer || Object.keys(answer).length < dependency.argument) { - dependencyAttended = false; - } + if (!answer || Object.keys(answer).length < dependency.argument) dependencyAttended = false; } else if (item.type === 'RANGE' || item.type === 'NUMBERBOX') { - if (!answer || Number(answer.text) < dependency.argument) { - dependencyAttended = false; - } + if (!answer || Number(answer.text) < dependency.argument) dependencyAttended = false; } else if (item.type === 'TEXTBOX') { - if (!answer || answer.text.length < dependency.argument) { - dependencyAttended = false; - } + if (!answer || answer.text.length < dependency.argument) dependencyAttended = false; } break; case 'MAX': if (item.type === 'CHECKBOX') { - if (!answer || Object.keys(answer).length > dependency.argument) { - dependencyAttended = false; - } + if (!answer || Object.keys(answer).length > dependency.argument) dependencyAttended = false; } else if (item.type === 'RANGE' || item.type === 'NUMBERBOX') { - if (!answer || Number(answer.text) > dependency.argument) { - dependencyAttended = false; - } + if (!answer || Number(answer.text) > dependency.argument) dependencyAttended = false; } else if (item.type === 'TEXTBOX') { - if (!answer || answer.text.length > dependency.argument) { - dependencyAttended = false; - } + if (!answer || answer.text.length > dependency.argument) dependencyAttended = false; } break; default: @@ -193,47 +165,33 @@ function ApplicationPage(props) { const getNextPage = () => { const nextPageIndex = currentPageIndex + 1; for (let i = nextPageIndex; i < application.protocol.pages.length; i++) { - if (application.protocol.pages[i].dependencies.length === 0) { - return i; - } else { + if (application.protocol.pages[i].dependencies.length === 0) return i; + else { let dependencyAttended = isDependenciesAttended(application.protocol.pages[i].dependencies); - if (dependencyAttended === true) { - return i; - } + if (dependencyAttended === true) return i; } return undefined; } }; - const isPreviousPage = () => { - return currentPageIndex > 0; - }; + const hasPreviousPage = () => currentPageIndex > 0; - const isNextPage = () => { - return getNextPage() !== undefined; - }; + const hasNextPage = () => getNextPage() !== undefined; - const nextPage = () => { - if (isNextPage()) { - const nextPageIndex = getNextPage(); - setCurrentPageIndex(nextPageIndex); - } + const goToNextPage = () => { + if (hasNextPage()) setCurrentPageIndex(getNextPage()); }; - const previousPage = () => { - if (isPreviousPage()) { - const previousPageIndex = currentPageIndex - 1; - setCurrentPageIndex(previousPageIndex); - } + const goToPreviousPage = () => { + if (hasPreviousPage()) setCurrentPageIndex(currentPageIndex - 1); }; const handleAnswerChange = useCallback((groupToUpdate, itemToUpdate, itemType, updatedAnswer) => { setItemAnswerGroups((prevItemAnswerGroups) => { const newItemAnswerGroups = { ...prevItemAnswerGroups }; - if (newItemAnswerGroups[groupToUpdate] === undefined) { + if (newItemAnswerGroups[groupToUpdate] === undefined) newItemAnswerGroups[groupToUpdate] = { itemAnswers: {}, optionAnswers: {}, tableAnswers: {} }; - } switch (itemType) { case 'ITEM': @@ -261,7 +219,8 @@ function ApplicationPage(props) { coordinate: answerLocation, itemAnswerGroups: [], }; - for (const group in itemAnswerGroups) { + + for (const group in itemAnswerGroups) if ( application.protocol.pages .flatMap((page) => @@ -272,85 +231,66 @@ function ApplicationPage(props) { groupDependencies: group.dependencies, })) ) - .filter( - (dependency) => - dependency.groupId === Number(group) && - !isDependenciesAttended(dependency.pageDependencies.concat(dependency.groupDependencies)) - ).length === 0 + .filter((d) => d.groupId === Number(group) && !isDependenciesAttended(d.pageDependencies.concat(d.groupDependencies))) + .length === 0 ) { - const itemAnswerGroup = { - itemAnswers: [], - optionAnswers: [], - tableAnswers: [], - }; + const itemAnswerGroup = { itemAnswers: [], optionAnswers: [], tableAnswers: [] }; - for (const item in itemAnswerGroups[group].itemAnswers) { + for (const item in itemAnswerGroups[group].itemAnswers) itemAnswerGroup.itemAnswers.push({ itemId: item, text: itemAnswerGroups[group].itemAnswers[item].text, files: itemAnswerGroups[group].itemAnswers[item].files, }); - } - for (const item in itemAnswerGroups[group].optionAnswers) { - for (const option in itemAnswerGroups[group].optionAnswers[item]) { - if (option !== 'group') { + + for (const item in itemAnswerGroups[group].optionAnswers) + for (const option in itemAnswerGroups[group].optionAnswers[item]) + if (option !== 'group') itemAnswerGroup.optionAnswers.push({ itemId: item, optionId: option, text: itemAnswerGroups[group].optionAnswers[item][option], }); - } - } - } - for (const item in itemAnswerGroups[group].tableAnswers) { - for (const column in itemAnswerGroups[group].tableAnswers[item]) { - if (column !== 'group') { + + for (const item in itemAnswerGroups[group].tableAnswers) + for (const column in itemAnswerGroups[group].tableAnswers[item]) + if (column !== 'group') itemAnswerGroup.tableAnswers.push({ itemId: item, columnId: column, text: itemAnswerGroups[group].tableAnswers[item][column], }); - } - } - } + applicationAnswer.itemAnswerGroups.push(itemAnswerGroup); } - } const formData = serialize(applicationAnswer, { indices: true }); - if (connected === true) { + if (connected === true) axios .post(process.env.REACT_APP_API_URL + `api/applicationAnswer/createApplicationAnswer`, formData, { - headers: { - 'Content-Type': 'multipart/form-data', - Authorization: `Bearer ${user.token}`, - }, + headers: { 'Content-Type': 'multipart/form-data', Authorization: `Bearer ${user.token}` }, }) - .then((response) => { + .then((response) => showAlert({ headerText: 'Muito obrigado por sua participação no projeto.', onPrimaryBtnClick: () => navigate(isDashboard ? '/dash/applications' : '/applications'), - }); - }) - .catch((error) => { + }) + ) + .catch((error) => showAlert({ headerText: 'Não foi possível submeter a resposta. Tente novamente mais tarde.', bodyText: error.response?.data.message, - }); - }); - } else { + }) + ); + else { storePendingRequest({ id: applicationId, userId: user.id, title: 'Resposta da aplicação ' + applicationId + ' referente ao protocolo ' + application.protocol.title, url: process.env.REACT_APP_API_URL + `api/applicationAnswer/createApplicationAnswer`, data: formData, - config: { - headers: { - 'Content-Type': 'multipart/form-data', - }, - }, + config: { headers: { 'Content-Type': 'multipart/form-data' } }, }); showAlert({ headerText: 'Você está offline. A resposta será armazenada localmente e submetida quando houver conexão.' }); } @@ -366,37 +306,30 @@ function ApplicationPage(props) { } else if (user.id !== null && user.token !== null) { axios .get(process.env.REACT_APP_API_URL + `api/application/getApplicationWithProtocol/${applicationId}`, { - headers: { - Authorization: `Bearer ${user.token}`, - }, + headers: { Authorization: `Bearer ${user.token}` }, }) .then((response) => { setApplication(response.data.data); storeLocalApplication(response.data.data); setIsLoading(false); }) - .catch((error) => { - setError({ text: 'Erro ao carregar aplicação', description: error.response?.data.message || '' }); - }); + .catch((error) => + setError({ text: 'Erro ao obter informações da aplicação', description: error.response?.data.message || '' }) + ); } } }, [applicationId, user, logout, navigate, localApplications, storeLocalApplication, application, isDashboard, connected]); useEffect(() => { - if (connected === false && application?.id) { + if (connected === false && application?.id) showAlert({ headerText: 'Você está offline. A aplicação ' + applicationId + ' está armazenada localmente e continuará acessível.', }); - } }, [connected, application, applicationId, showAlert]); - if (error) { - return ; - } + if (error) return ; - if (isLoading) { - return ; - } + if (isLoading) return ; return (
@@ -456,11 +389,7 @@ function ApplicationPage(props) { {application.protocol.pages[currentPageIndex].itemGroups .filter((group) => isDependenciesAttended(group.dependencies)) .map((itemGroup, itemGroupIndex) => { - if ( - itemGroup.type !== 'TEXTBOX_TABLE' && - itemGroup.type !== 'RADIO_TABLE' && - itemGroup.type !== 'CHECKBOX_TABLE' - ) { + if (itemGroup.type === 'ONE_DIMENSIONAL') return (
{itemGroup.items.map((item) => { @@ -591,7 +520,7 @@ function ApplicationPage(props) { })}
); - } else { + else return (
); - } })}
- { - Identificador do protocolo: ' + - application.protocol.id + - '
Versão do protocolo: ' + - application.protocol.updatedAt.replace(/\D/g, ''), - files: [], - }} - galleryModalRef={galleryModalRef} - /> - } + Identificador do protocolo: ' + + application.protocol.id + + '
Versão do protocolo: ' + + application.protocol.updatedAt.replace(/\D/g, ''), + files: [], + }} + galleryModalRef={galleryModalRef} + />
- {!isNextPage() && ( + {!hasNextPage() && (
)} - {isPreviousPage() && ( + {hasPreviousPage() && (
- +
)} - {isNextPage() && ( + {hasNextPage() && (
- +
)}
diff --git a/src/pages/ApplicationsPage.jsx b/src/pages/ApplicationsPage.jsx index b0ce953..401d25f 100644 --- a/src/pages/ApplicationsPage.jsx +++ b/src/pages/ApplicationsPage.jsx @@ -89,35 +89,29 @@ function ApplicationsPage(props) { setVisibleApplications(response.data.data); setIsLoading(false); }) - .catch((error) => { - setError({ text: 'Erro ao carregar aplicações', description: error.response?.data.message || '' }); - }); + .catch((error) => + setError({ text: 'Erro ao obter informações de aplicações', description: error.response?.data.message || '' }) + ); } }, [user.token, logout, navigate, connected, localApplications, isDashboard, isLoading, user.status]); const deleteApplication = (applicationId) => { axios .delete(`${process.env.REACT_APP_API_URL}api/application/deleteApplication/${applicationId}`, { - headers: { - Authorization: `Bearer ${user.token}`, - }, + headers: { Authorization: `Bearer ${user.token}` }, }) .then((response) => { clearLocalApplications(); - showAlert({ headerText: 'Aplicação excluída com sucesso.' }); + showAlert({ headerText: 'Aplicação excluída com sucesso' }); const newVisibleApplications = [...visibleApplications]; setVisibleApplications(newVisibleApplications.filter((a) => a.id !== applicationId)); }) - .catch((error) => showAlert({ headerText: 'Erro ao excluir aplicação.', bodyText: error.response?.data.message })); + .catch((error) => showAlert({ headerText: 'Erro ao excluir aplicação', bodyText: error.response?.data.message })); }; - if (error) { - return ; - } + if (error) return ; - if (isLoading) { - return ; - } + if (isLoading) return ; return (
@@ -140,24 +134,27 @@ function ApplicationsPage(props) { {isDashboard ? (
{user.role !== 'USER' && user.role !== 'APPLIER' && ( -
+

Minhas aplicações

a.applier.id === user.id) - .map((a) => ({ id: a.id, title: a.protocol.title }))} + .map((a) => ({ + id: a.id, + title: a.protocol.title, + allowEdit: a.actions.toUpdate, + allowDelete: a.actions.toDelete, + }))} hsl={[36, 98, 83]} - allowEdit={true} - allowDelete={true} viewFunction={(id) => navigate(`${id}`)} editFunction={(id) => navigate(`${id}/manage`)} deleteFunction={(id) => deleteApplication(id)} />
)} -
+

Aplicações disponíveis

diff --git a/src/pages/CreateApplicationPage.jsx b/src/pages/CreateApplicationPage.jsx index 0eee213..512690d 100644 --- a/src/pages/CreateApplicationPage.jsx +++ b/src/pages/CreateApplicationPage.jsx @@ -140,15 +140,12 @@ function CreateApplicationPage(props) { useEffect(() => { if (isLoading && user.status !== 'loading') { - if (!isEditing && user.role === 'USER') { + if (user.role === 'USER') { setError({ text: 'Operação não permitida', - description: 'Você não tem permissão para criar aplicações', + description: `Você não tem permissão para ${isEditing ? 'editar' : 'criar'} aplicações`, }); return; - } else if (isEditing && user.role === 'USER') { - setError({ text: 'Operação não permitida', description: 'Você não tem permissão para editar esta aplicação' }); - return; } const promises = []; let reqProtocolId = protocolId; @@ -156,50 +153,47 @@ function CreateApplicationPage(props) { promises.push( axios .get(`${process.env.REACT_APP_API_URL}api/application/getApplication/${applicationId}`, { - headers: { - Authorization: `Bearer ${user.token}`, - }, + headers: { Authorization: `Bearer ${user.token}` }, }) .then((response) => { const d = response.data.data; reqProtocolId = d.protocol.id; - if (d.applier.id !== user.id && user.role !== 'ADMIN') { + if (d.actions.toUpdate !== true) return Promise.reject({ text: 'Operação não permitida', description: 'Você não tem permissão para editar esta aplicação', }); - } setApplication({ visibility: d.visibility, answersVisibility: d.answersVisibility, - viewersUser: d.viewersUser.map((v) => v.id), - viewersClassroom: d.viewersClassroom.map((v) => v.id), - answersViewersUser: d.answersViewersUser.map((v) => v.id), - answersViewersClassroom: d.answersViewersClassroom.map((v) => v.id), + viewersUser: d.viewersUser.map(({ id }) => id), + viewersClassroom: d.viewersClassroom.map(({ id }) => id), + answersViewersUser: d.answersViewersUser.map(({ id }) => id), + answersViewersClassroom: d.answersViewersClassroom.map(({ id }) => id), keepLocation: d.keepLocation, + actions: d.actions, }); - setSearchedClassrooms(d.viewersClassroom.map((c) => ({ id: c.id, name: c.name, users: c.users }))); - setSearchedUsers(d.viewersUser.map((u) => ({ id: u.id, username: u.username, classrooms: u.classrooms }))); - setSearchedAnswerClassrooms(d.answersViewersClassroom.map((c) => ({ id: c.id, name: c.name, users: c.users }))); + setSearchedClassrooms(d.viewersClassroom.map(({ id, name, users }) => ({ id, name, users }))); + setSearchedUsers(d.viewersUser.map(({ id, username, classrooms }) => ({ id, username, classrooms }))); + setSearchedAnswerClassrooms(d.answersViewersClassroom.map(({ id, name, users }) => ({ id, name, users }))); setSearchedAnswerUsers( - d.answersViewersUser.map((u) => ({ id: u.id, username: u.username, classrooms: u.classrooms })) + d.answersViewersUser.map(({ id, username, classrooms }) => ({ id, username, classrooms })) ); }) - .catch((error) => { - return Promise.reject({ - text: 'Erro ao buscar aplicação.', - description: error.response?.data.message, - }); - }) + .catch((error) => + Promise.reject( + error.text + ? error + : { text: 'Erro ao obter informações da aplicação', description: error.response?.data.message } + ) + ) ); } Promise.all(promises) .then(() => { axios .get(`${process.env.REACT_APP_API_URL}api/protocol/getProtocol/${reqProtocolId}`, { - headers: { - Authorization: `Bearer ${user.token}`, - }, + headers: { Authorization: `Bearer ${user.token}` }, }) .then((response) => { const d = response.data.data; @@ -218,10 +212,8 @@ function CreateApplicationPage(props) { viewersUser: d.viewersUser.map((u) => u.id), viewersClassroom: d.viewersClassroom.map((c) => c.id), })); - setSearchedUsers( - d.viewersUser.map((u) => ({ id: u.id, username: u.username, classrooms: u.classrooms })) - ); - setSearchedClassrooms(d.viewersClassroom.map((c) => ({ id: c.id, name: c.name, users: c.users }))); + setSearchedUsers(d.viewersUser.map(({ id, username, classrooms }) => ({ id, username, classrooms }))); + setSearchedClassrooms(d.viewersClassroom.map(({ id, name, users }) => ({ id, name, users }))); } if (d.answersVisibility === 'RESTRICT') { setApplication((prev) => ({ @@ -230,21 +222,21 @@ function CreateApplicationPage(props) { answersViewersClassroom: d.answersViewersClassroom.map((c) => c.id), })); setSearchedAnswerUsers( - d.answersViewersUser.map((u) => ({ id: u.id, username: u.username, classrooms: u.classrooms })) + d.answersViewersUser.map(({ id, username, classrooms }) => ({ id, username, classrooms })) ); setSearchedAnswerClassrooms( - d.answersViewersClassroom.map((c) => ({ id: c.id, name: c.name, users: c.users })) + d.answersViewersClassroom.map(({ id, name, users }) => ({ id, name, users })) ); } } setIsLoading(false); }) - .catch((error) => { - showAlert({ - headerText: 'Erro ao buscar visualizadores do protocolo.', - bodyText: error.response?.data.message, - }); - }); + .catch((error) => + Promise.reject({ + text: 'Erro ao obter informações do protocolo', + description: error.response?.data.message, + }) + ); }) .catch((error) => setError(error)); } @@ -256,59 +248,48 @@ function CreateApplicationPage(props) { if (isEditing) { axios .put(`${process.env.REACT_APP_API_URL}api/application/updateApplication/${applicationId}`, formData, { - headers: { - 'Content-Type': 'multipart/form-data', - Authorization: `Bearer ${user.token}`, - }, + headers: { 'Content-Type': 'multipart/form-data', Authorization: `Bearer ${user.token}` }, }) .then((response) => { clearLocalApplications(); showAlert({ - headerText: 'Aplicação atualizada com sucesso.', + headerText: 'Aplicação atualizada com sucesso', onPrimaryBtnClick: () => navigate(`/dash/applications/${response.data.data.id}`), }); }) - .catch((error) => showAlert({ headerText: 'Erro ao atualizar aplicação.', description: error.response?.data.message })); + .catch((error) => showAlert({ headerText: 'Erro ao atualizar aplicação', description: error.response?.data.message })); } else { axios .post(`${process.env.REACT_APP_API_URL}api/application/createApplication`, formData, { - headers: { - 'Content-Type': 'multipart/form-data', - Authorization: `Bearer ${user.token}`, - }, + headers: { 'Content-Type': 'multipart/form-data', Authorization: `Bearer ${user.token}` }, }) .then((response) => { showAlert({ - headerText: 'Aplicação criada com sucesso.', + headerText: 'Aplicação criada com sucesso', onPrimaryBtnClick: () => navigate(`/dash/applications/${response.data.data.id}`), }); }) - .catch((error) => showAlert({ headerText: 'Erro ao criar aplicação.', bodyText: error.response?.data.message })); + .catch((error) => showAlert({ headerText: 'Erro ao criar aplicação', bodyText: error.response?.data.message })); } }; const deleteApplication = () => { axios .delete(`${process.env.REACT_APP_API_URL}api/application/deleteApplication/${applicationId}`, { - headers: { - Authorization: `Bearer ${user.token}`, - }, + headers: { Authorization: `Bearer ${user.token}` }, }) .then((response) => { clearLocalApplications(); - showAlert({ headerText: 'Aplicação excluída com sucesso.', onPrimaryBtnClick: () => navigate(`/dash/applications/`) }); + showAlert({ headerText: 'Aplicação excluída com sucesso', onPrimaryBtnClick: () => navigate(`/dash/applications/`) }); }) - .catch((error) => showAlert({ headerText: 'Erro ao excluir aplicação.', bodyText: error.response?.data.message })); + .catch((error) => showAlert({ headerText: 'Erro ao excluir aplicação', bodyText: error.response?.data.message })); }; const searchUsers = (term) => { const formData = serialize({ term }, { indices: true }); axios .post(`${process.env.REACT_APP_API_URL}api/user/searchUserByUsername`, formData, { - headers: { - 'Content-Type': 'multipart/form-data', - Authorization: `Bearer ${user.token}`, - }, + headers: { 'Content-Type': 'multipart/form-data', Authorization: `Bearer ${user.token}` }, }) .then((response) => { const d = response.data.data; @@ -326,17 +307,14 @@ function CreateApplicationPage(props) { ]; setSearchedUsers(newUsers); }) - .catch((error) => showAlert({ headerText: 'Erro ao buscar usuários.', bodyText: error.response?.data.message })); + .catch((error) => showAlert({ headerText: 'Erro ao buscar usuários', bodyText: error.response?.data.message })); }; const searchAnswerUsers = (term) => { const formData = serialize({ term }, { indices: true }); axios .post(`${process.env.REACT_APP_API_URL}api/user/searchUserByUsername`, formData, { - headers: { - 'Content-Type': 'multipart/form-data', - Authorization: `Bearer ${user.token}`, - }, + headers: { 'Content-Type': 'multipart/form-data', Authorization: `Bearer ${user.token}` }, }) .then((response) => { const d = response.data.data; @@ -354,17 +332,14 @@ function CreateApplicationPage(props) { ]; setSearchedAnswerUsers(newUsers); }) - .catch((error) => showAlert({ headerText: 'Erro ao buscar usuários.', bodyText: error.response?.data.message })); + .catch((error) => showAlert({ headerText: 'Erro ao buscar usuários', bodyText: error.response?.data.message })); }; const searchClassrooms = (term) => { const formData = serialize({ term }, { indices: true }); axios .post(`${process.env.REACT_APP_API_URL}api/classroom/searchClassroomByName`, formData, { - headers: { - 'Content-Type': 'multipart/form-data', - Authorization: `Bearer ${user.token}`, - }, + headers: { 'Content-Type': 'multipart/form-data', Authorization: `Bearer ${user.token}` }, }) .then((response) => { const d = response.data.data; @@ -399,17 +374,14 @@ function CreateApplicationPage(props) { // } setSearchedClassrooms(concatenedClassrooms); }) - .catch((error) => showAlert({ headerText: 'Erro ao buscar grupos.', bodyText: error.response?.data.message })); + .catch((error) => showAlert({ headerText: 'Erro ao buscar grupos', bodyText: error.response?.data.message })); }; const searchAnswerClassrooms = (term) => { const formData = serialize({ term }, { indices: true }); axios .post(`${process.env.REACT_APP_API_URL}api/classroom/searchClassroomByName`, formData, { - headers: { - 'Content-Type': 'multipart/form-data', - Authorization: `Bearer ${user.token}`, - }, + headers: { 'Content-Type': 'multipart/form-data', Authorization: `Bearer ${user.token}` }, }) .then((response) => { const d = response.data.data; @@ -444,7 +416,7 @@ function CreateApplicationPage(props) { // } setSearchedAnswerClassrooms(concatenedClassrooms); }) - .catch((error) => showAlert({ headerText: 'Erro ao buscar grupos.', bodyText: error.response?.data.message })); + .catch((error) => showAlert({ headerText: 'Erro ao buscar grupos', bodyText: error.response?.data.message })); }; const unselectUser = (id) => { @@ -465,9 +437,7 @@ function CreateApplicationPage(props) { setSearchedUsers((prev) => [ ...prev.map((u) => { - if (newUsers.includes(u.id)) { - return { ...u, classrooms: [...u.classrooms, c.id] }; - } + if (newUsers.includes(u.id)) return { ...u, classrooms: [...u.classrooms, c.id] }; return u; }), ...newUsers.filter((u) => !prev.map((u) => u.id).includes(u.id)), @@ -504,9 +474,7 @@ function CreateApplicationPage(props) { setSearchedAnswerUsers((prev) => [ ...prev.map((u) => { - if (newUsers.includes(u.id)) { - return { ...u, classrooms: [...u.classrooms, c.id] }; - } + if (newUsers.includes(u.id)) return { ...u, classrooms: [...u.classrooms, c.id] }; return u; }), ...newUsers.filter((u) => !prev.map((u) => u.id).includes(u.id)), @@ -525,13 +493,9 @@ function CreateApplicationPage(props) { })); }; - if (error) { - return ; - } + if (error) return ; - if (isLoading) { - return ; - } + if (isLoading) return ; return (
@@ -562,9 +526,7 @@ function CreateApplicationPage(props) { role="switch" id="enabled" checked={application.keepLocation || false} - onChange={(event) => - setApplication((prev) => ({ ...prev, keepLocation: event.target.checked })) - } + onChange={(e) => setApplication((prev) => ({ ...prev, keepLocation: e.target.checked }))} />
@@ -635,7 +595,7 @@ function CreateApplicationPage(props) { className="form-check-input bg-grey" checked={application.viewersUser.includes(u.id)} onChange={(e) => { - if (e.target.checked) { + if (e.target.checked) setApplication((prev) => ({ ...prev, viewersUser: [ @@ -643,9 +603,7 @@ function CreateApplicationPage(props) { parseInt(e.target.value), ], })); - } else { - unselectUser(parseInt(e.target.value)); - } + else unselectUser(parseInt(e.target.value)); }} />
@@ -709,16 +665,14 @@ function CreateApplicationPage(props) { className="form-check-input bg-grey" checked={application.viewersClassroom.includes(c.id)} onChange={(e) => { - if (e.target.checked) { - selectClassroom(parseInt(e.target.value)); - } else { + if (e.target.checked) selectClassroom(parseInt(e.target.value)); + else setApplication((prev) => ({ ...prev, viewersClassroom: prev.viewersClassroom.filter( (id) => id !== parseInt(e.target.value) ), })); - } }} />
@@ -802,7 +754,7 @@ function CreateApplicationPage(props) { className="form-check-input bg-grey" checked={application.answersViewersUser.includes(u.id)} onChange={(e) => { - if (e.target.checked) { + if (e.target.checked) setApplication((prev) => ({ ...prev, answersViewersUser: [ @@ -810,9 +762,7 @@ function CreateApplicationPage(props) { parseInt(e.target.value), ], })); - } else { - unselectAnswerUser(parseInt(e.target.value)); - } + else unselectAnswerUser(parseInt(e.target.value)); }} />
@@ -876,9 +824,9 @@ function CreateApplicationPage(props) { className="form-check-input bg-grey" checked={application.answersViewersClassroom.includes(c.id)} onChange={(e) => { - if (e.target.checked) { + if (e.target.checked) selectAnswerClassroom(parseInt(e.target.value)); - } else { + else setApplication((prev) => ({ ...prev, answersViewersClassroom: @@ -886,7 +834,6 @@ function CreateApplicationPage(props) { (id) => id !== parseInt(e.target.value) ), })); - } }} />
- {isEditing && ( + {isEditing && application.actions.toDelete === true && (
{ if (isLoading && user.status !== 'loading') { - if (!isEditing && user.role === 'USER') { - setError({ text: 'Operação não permitida', description: 'Você não tem permissão para criar grupos' }); - return; - } else if ( - isEditing && - user.role !== 'ADMIN' && - (user.role === 'USER' || - user.role === 'APPLIER' || - (classroom.institutionId && user.institutionId !== classroom.institutionId)) - ) { - setError({ text: 'Operação não permitida', description: 'Você não tem permissão para editar este grupo' }); - return; - } + if (!isEditing && (user.role === 'USER' || user.role === 'GUEST')) + return setError({ text: 'Operação não permitida', description: 'Você não tem permissão para criar grupos' }); + const promises = []; if (isEditing) { promises.push( @@ -143,15 +133,28 @@ function CreateClassroomPage(props) { headers: { Authorization: `Bearer ${user.token}` }, }) .then((response) => { - const { name, users, institutionId } = response.data.data; + const { name, users, institution, actions } = response.data.data; + if (actions.toUpdate !== true) + return Promise.reject({ + text: 'Operação não permitida', + description: 'Você não tem permissão para editar este grupo', + }); const usersIds = users.map(({ id }) => id); - setClassroom({ name, users: usersIds, institutionId }); + setClassroom({ name, users: usersIds, institutionId: institution?.id, actions }); setSearchedUsers(users.map(({ id, username, classrooms }) => ({ id, username, classrooms }))); }) - .catch((error) => showAlert({ headerText: 'Erro ao buscar sala de aula.', bodyText: error.response?.data.message })) + .catch((error) => + Promise.reject( + error.text + ? error + : { text: 'Erro ao obter informações do grupo', description: error.response?.data.message } + ) + ) ); } - Promise.all(promises).then(() => setIsLoading(false)); + Promise.all(promises) + .then(() => setIsLoading(false)) + .catch((error) => setError(error)); } }, [classroomId, isEditing, isLoading, user.token, user.status, user.role, user.institutionId, showAlert, classroom.institutionId]); @@ -161,7 +164,11 @@ function CreateClassroomPage(props) { .post(`${process.env.REACT_APP_API_URL}api/user/searchUserByUsername`, formData, { headers: { 'Content-Type': 'multipart/form-data', Authorization: `Bearer ${user.token}` }, }) - .then((response) => concatenateUsers(response.data.data.map(({ id, username, classrooms }) => ({ id, username, classrooms })))) + .then((response) => + concatenateUsers( + response.data.data.map(({ id, username, classrooms, institution }) => ({ id, username, classrooms, institution })) + ) + ) .catch((error) => showAlert({ headerText: 'Erro ao buscar usuários.', bodyText: error.response?.data.message })); }; @@ -173,18 +180,36 @@ function CreateClassroomPage(props) { headers: { Authorization: `Bearer ${user.token}` }, }) .then((response) => { - const users = response.data.data.users.map(({ id, username, classrooms }) => ({ id, username, classrooms })); + const users = response.data.data.users.map(({ id, username, classrooms }) => ({ + id, + username, + classrooms, + institution: { id: classroom.institutionId || user.institutionId }, + })); setInstitutionUsers(users); concatenateUsers(users); }) .catch((error) => - showAlert({ headerText: 'Erro ao buscar usuários da instituição.', bodyText: error.response?.data.message }) + showAlert({ + headerText: 'Houve um problema ao buscar os usuários da sua instituição', + bodyText: `Você ainda poderá ${ + isEditing ? 'editar' : 'criar' + } o grupo, mas alguns usuários podem estar inacessíveis. Deseja continuar?`, + primaryBtnLabel: 'Sim', + primaryBtnHsl: [97, 43, 70], + secondaryBtnLabel: 'Não', + secondaryBtnHsl: [355, 78, 66], + onSecondaryBtnClick: () => navigate('/dash/applications'), + }) ); else concatenateUsers(institutionUsers); }; const concatenateUsers = (users) => { - const newUsers = users.filter((c) => !classroom.users.includes(c.id)); + const newUsers = users.filter( + (u) => + !classroom.users.includes(u.id) && (classroom.institutionId === undefined || u.institution?.id === classroom.institutionId) + ); const concatenedUsers = [ ...newUsers, ...searchedUsers.filter((c) => classroom.users.includes(c.id)).sort((a, b) => a.username.localeCompare(b.username)), @@ -205,14 +230,14 @@ function CreateClassroomPage(props) { .then(() => showAlert({ headerText: 'Grupo atualizado com sucesso!', onPrimaryBtnClick: () => navigate(`/dash/users`) }) ) - .catch((error) => showAlert({ headerText: 'Erro ao atualizar grupo.', bodyText: error.response?.data.message })); + .catch((error) => showAlert({ headerText: 'Erro ao atualizar grupo', bodyText: error.response?.data.message })); } else { axios .post(`${process.env.REACT_APP_API_URL}api/classroom/createClassroom`, formData, { headers: { 'Content-Type': 'multipart/form-data', Authorization: `Bearer ${user.token}` }, }) - .then(() => showAlert({ headerText: 'Grupo criado com sucesso.', onPrimaryBtnClick: () => navigate(`/dash/users`) })) - .catch((error) => showAlert({ headerText: 'Erro ao criar grupo.', bodyText: error.response?.data.message })); + .then(() => showAlert({ headerText: 'Grupo criado com sucesso', onPrimaryBtnClick: () => navigate(`/dash/users`) })) + .catch((error) => showAlert({ headerText: 'Erro ao criar grupo', bodyText: error.response?.data.message })); } } else showAlert({ headerText: 'Adicione pelo menos dois usuários no grupo!' }); }; @@ -222,13 +247,13 @@ function CreateClassroomPage(props) { .delete(`${process.env.REACT_APP_API_URL}api/classroom/deleteClassroom/${classroomId}`, { headers: { Authorization: `Bearer ${user.token}` }, }) - .then(() => showAlert({ headerText: 'Grupo excluído com sucesso.', onPrimaryBtnClick: () => navigate(`/dash/users`) })) - .catch((error) => showAlert({ headerText: 'Erro ao excluir grupo.', bodyText: error.response?.data.message })); + .then(() => showAlert({ headerText: 'Grupo excluído com sucesso', onPrimaryBtnClick: () => navigate(`/dash/users`) })) + .catch((error) => showAlert({ headerText: 'Erro ao excluir grupo', bodyText: error.response?.data.message })); }; if (error) return ; - if (isLoading) return ; + if (isLoading) return ; return (
@@ -278,12 +303,20 @@ function CreateClassroomPage(props) { name="institution" id="institution" checked={classroom.institutionId !== undefined} - onChange={(event) => + onChange={(event) => { setClassroom((prev) => ({ ...prev, institutionId: event.target.checked ? user.institutionId : undefined, - })) - } + users: event.target.checked + ? prev.users.filter((u) => institutionUsers.map(({ id }) => id).includes(u)) + : prev.users, + })); + setSearchedUsers((prev) => + event.target.checked + ? prev.filter((u) => institutionUsers.map(({ id }) => id).includes(u.id)) + : prev + ); + }} />