From 6996a217d16b060daf41de4ea2a6e1fb95bd76ef Mon Sep 17 00:00:00 2001 From: Ivar Nakken Date: Sat, 26 Aug 2023 16:34:25 +0200 Subject: [PATCH] Type announcement, article, comment and company actions --- app/actions/AnnouncementsActions.ts | 29 ++-- app/actions/ArticleActions.ts | 34 +++-- app/actions/CommentActions.ts | 16 +- app/actions/CompanyActions.ts | 143 ++++++++++-------- app/actions/ContactActions.ts | 5 +- app/actions/UserActions.ts | 21 ++- app/components/CommentForm/index.tsx | 13 +- .../components/AnnouncementItem.tsx | 11 +- .../components/AnnouncementsList.css | 4 - app/routes/userValidator/ValidatorRoute.tsx | 13 +- app/store/models/Comment.d.ts | 4 +- 11 files changed, 153 insertions(+), 140 deletions(-) diff --git a/app/actions/AnnouncementsActions.ts b/app/actions/AnnouncementsActions.ts index a2c99e2b56..eb463e6f07 100644 --- a/app/actions/AnnouncementsActions.ts +++ b/app/actions/AnnouncementsActions.ts @@ -1,11 +1,16 @@ import { stopSubmit } from 'redux-form'; import callAPI from 'app/actions/callAPI'; import { announcementsSchema } from 'app/reducers'; -import type { Thunk } from 'app/types'; +import type { AppDispatch } from 'app/store/createStore'; +import type { ID } from 'app/store/models'; +import type { + DetailedAnnouncement, + ListAnnouncement, +} from 'app/store/models/Announcement'; import { Announcements } from './ActionTypes'; -export function fetchAll(): Thunk { - return callAPI({ +export function fetchAll() { + return callAPI({ types: Announcements.FETCH_ALL, endpoint: '/announcements/', schema: [announcementsSchema], @@ -15,6 +20,7 @@ export function fetchAll(): Thunk { propagateError: true, }); } + export function createAnnouncement({ message, users, @@ -23,11 +29,10 @@ export function createAnnouncement({ meetings, fromGroup, send, -}: Record): /*AnnouncementModel*/ -Thunk { - return (dispatch) => +}: Record) { + return (dispatch: AppDispatch) => dispatch( - callAPI({ + callAPI({ types: Announcements.CREATE, endpoint: '/announcements/', method: 'POST', @@ -46,7 +51,7 @@ Thunk { }) ) .then((action) => { - if (send && action && action.payload) { + if (send && action?.payload?.result) { dispatch(sendAnnouncement(action.payload.result)); } }) @@ -55,8 +60,9 @@ Thunk { dispatch(stopSubmit('AnnouncementsCreate', errors)); }); } -export function sendAnnouncement(announcementId: number): Thunk { - return callAPI({ + +export function sendAnnouncement(announcementId: ID) { + return callAPI<{ status: string }>({ types: Announcements.SEND, endpoint: `/announcements/${announcementId}/send/`, method: 'POST', @@ -66,7 +72,8 @@ export function sendAnnouncement(announcementId: number): Thunk { }, }); } -export function deleteAnnouncement(id: number): Thunk { + +export function deleteAnnouncement(id: ID) { return callAPI({ types: Announcements.DELETE, endpoint: `/announcements/${id}/`, diff --git a/app/actions/ArticleActions.ts b/app/actions/ArticleActions.ts index 05af0f32ee..868c00b3ac 100644 --- a/app/actions/ArticleActions.ts +++ b/app/actions/ArticleActions.ts @@ -1,12 +1,14 @@ import { push } from 'connected-react-router'; import callAPI from 'app/actions/callAPI'; import { articleSchema } from 'app/reducers'; +import type { AppDispatch } from 'app/store/createStore'; import type { ID } from 'app/store/models'; -import type { ArticleEntity, Thunk } from 'app/types'; +import type { DetailedArticle } from 'app/store/models/Article'; +import type { ArticleEntity } from 'app/types'; import { Article } from './ActionTypes'; -export function fetchArticle(articleId: ID): Thunk> { - return callAPI({ +export function fetchArticle(articleId: ID) { + return callAPI({ types: Article.FETCH, endpoint: `/articles/${articleId}/`, schema: articleSchema, @@ -16,10 +18,11 @@ export function fetchArticle(articleId: ID): Thunk> { propagateError: true, }); } -export function createArticle({ id, ...data }: ArticleEntity): Thunk { - return (dispatch) => + +export function createArticle({ id, ...data }: ArticleEntity) { + return (dispatch: AppDispatch) => dispatch( - callAPI({ + callAPI({ types: Article.CREATE, endpoint: '/articles/', method: 'POST', @@ -29,11 +32,10 @@ export function createArticle({ id, ...data }: ArticleEntity): Thunk { errorMessage: 'Opprettelse av artikkel feilet', }, }) - ).then((res) => - dispatch(push(`/articles/${(res as any).payload.result}/`)) - ); + ).then((res) => dispatch(push(`/articles/${res?.payload?.result}/`))); } -export function deleteArticle(id: number): Thunk { + +export function deleteArticle(id: ID) { return callAPI({ types: Article.DELETE, endpoint: `/articles/${id}/`, @@ -44,8 +46,9 @@ export function deleteArticle(id: number): Thunk { }, }); } -export function editArticle({ id, ...data }: ArticleEntity): Thunk { - return (dispatch) => + +export function editArticle({ id, ...data }: ArticleEntity) { + return (dispatch: AppDispatch) => dispatch( callAPI({ types: Article.EDIT, @@ -57,16 +60,17 @@ export function editArticle({ id, ...data }: ArticleEntity): Thunk { errorMessage: 'Endring av artikkel feilet', }, }) - ).then((res) => dispatch(push(`/articles/${id}/`))); + ).then(() => dispatch(push(`/articles/${id}/`))); } + export function fetchAll({ query, next = false, }: { query?: Record; next?: boolean; -} = {}): Thunk { - return callAPI({ +} = {}) { + return callAPI({ types: Article.FETCH, endpoint: '/articles/', schema: [articleSchema], diff --git a/app/actions/CommentActions.ts b/app/actions/CommentActions.ts index e51c203d43..9741c723f8 100644 --- a/app/actions/CommentActions.ts +++ b/app/actions/CommentActions.ts @@ -2,15 +2,19 @@ import callAPI from 'app/actions/callAPI'; import { commentSchema } from 'app/reducers'; import type { ID } from 'app/store/models'; import type CommentType from 'app/store/models/Comment'; -import type { Thunk } from 'app/types'; +import type { ContentTarget } from 'app/store/utils/contentTarget'; import { Comment } from './ActionTypes'; export function addComment({ text, contentTarget, parent, -}: CommentType): Thunk | null | undefined>> { - return callAPI({ +}: { + text: string; + contentTarget: ContentTarget; + parent?: ID; +}) { + return callAPI({ types: Comment.ADD, endpoint: '/comments/', method: 'POST', @@ -30,10 +34,8 @@ export function addComment({ schema: commentSchema, }); } -export function deleteComment( - commentId: ID, - contentTarget: string -): Thunk { + +export function deleteComment(commentId: ID, contentTarget: ContentTarget) { return callAPI({ types: Comment.DELETE, endpoint: `/comments/${commentId}/`, diff --git a/app/actions/CompanyActions.ts b/app/actions/CompanyActions.ts index 9651889cd8..f6832c4a36 100644 --- a/app/actions/CompanyActions.ts +++ b/app/actions/CompanyActions.ts @@ -9,13 +9,23 @@ import { joblistingsSchema, } from 'app/reducers'; import type { CompanySemesterEntity } from 'app/reducers/companySemesters'; -import type { Thunk } from 'app/types'; +import type { AppDispatch } from 'app/store/createStore'; +import type { ID } from 'app/store/models'; +import type { + AdminListCompany, + CompanyContact, + DetailedCompany, + DetailedSemesterStatus, + ListCompany, +} from 'app/store/models/Company'; +import type { ListJoblisting } from 'app/store/models/Joblisting'; +import type { GetState } from 'app/types'; import createQueryString from 'app/utils/createQueryString'; import { semesterToText } from '../routes/companyInterest/utils'; import { Company, Event, Joblistings } from './ActionTypes'; -export const fetchAll = ({ fetchMore }: { fetchMore: boolean }): Thunk => { - return callAPI({ +export const fetchAll = ({ fetchMore }: { fetchMore: boolean }) => { + return callAPI({ types: Company.FETCH, endpoint: '/companies/', schema: [companySchema], @@ -29,8 +39,9 @@ export const fetchAll = ({ fetchMore }: { fetchMore: boolean }): Thunk => { propagateError: true, }); }; -export function fetchAllAdmin(): Thunk { - return callAPI({ + +export function fetchAllAdmin() { + return callAPI({ types: Company.FETCH, endpoint: '/bdb/', schema: [companySchema], @@ -40,10 +51,11 @@ export function fetchAllAdmin(): Thunk { propagateError: true, }); } -export function fetch(companyId: number): Thunk { - return (dispatch) => + +export function fetch(companyId: ID) { + return (dispatch: AppDispatch) => dispatch( - callAPI({ + callAPI({ types: Company.FETCH, endpoint: `/companies/${companyId}/`, schema: companySchema, @@ -54,8 +66,9 @@ export function fetch(companyId: number): Thunk { }) ); } -export function fetchAdmin(companyId: number): Thunk { - return (dispatch) => + +export function fetchAdmin(companyId: ID) { + return (dispatch: AppDispatch) => dispatch( callAPI({ types: Company.FETCH, @@ -68,6 +81,7 @@ export function fetchAdmin(companyId: number): Thunk { }) ); } + export const fetchEventsForCompany = ({ queryString, @@ -75,11 +89,12 @@ export const fetchEventsForCompany = }: { queryString: string; loadNextPage: boolean; - }): Thunk => - (dispatch, getState) => { + }) => + (dispatch: AppDispatch, getState: GetState) => { const endpoint = loadNextPage ? getState().events.pagination[queryString].nextPage : `/events/${queryString}`; + return dispatch( callAPI({ types: Event.FETCH, @@ -92,10 +107,11 @@ export const fetchEventsForCompany = }) ); }; -export function fetchJoblistingsForCompany(companyId: string): Thunk { - return (dispatch) => + +export function fetchJoblistingsForCompany(companyId: ID) { + return (dispatch: AppDispatch) => dispatch( - callAPI({ + callAPI({ types: Joblistings.FETCH, endpoint: `/joblistings/?company=${companyId}`, schema: [joblistingsSchema], @@ -105,11 +121,12 @@ export function fetchJoblistingsForCompany(companyId: string): Thunk { }) ); } -export function addCompany(data: Record): Thunk { - return (dispatch) => { + +export function addCompany(data: Record) { + return (dispatch: AppDispatch) => { dispatch(startSubmit('company')); return dispatch( - callAPI({ + callAPI({ types: Company.ADD, endpoint: '/bdb/', method: 'POST', @@ -134,14 +151,12 @@ export function addCompany(data: Record): Thunk { .catch(); }; } -export function editCompany({ - companyId, - ...data -}: Record): Thunk { - return (dispatch) => { + +export function editCompany({ companyId, ...data }: Record) { + return (dispatch: AppDispatch) => { dispatch(startSubmit('company')); return dispatch( - callAPI({ + callAPI({ types: Company.EDIT, endpoint: `/bdb/${companyId}/`, method: 'PATCH', @@ -162,8 +177,9 @@ export function editCompany({ }); }; } -export function deleteCompany(companyId: number): Thunk { - return (dispatch) => { + +export function deleteCompany(companyId: ID) { + return (dispatch: AppDispatch) => { return dispatch( callAPI({ types: Company.DELETE, @@ -184,15 +200,16 @@ export function deleteCompany(companyId: number): Thunk { }); }; } + export function addSemesterStatus( { companyId, ...data }: Record, options: Record = { detail: false, } -): Thunk { - return (dispatch) => { +) { + return (dispatch: AppDispatch) => { return dispatch( - callAPI({ + callAPI({ types: Company.ADD_SEMESTER_STATUS, endpoint: `/companies/${companyId}/semester-statuses/`, method: 'POST', @@ -217,15 +234,16 @@ export function addSemesterStatus( }); }; } + export function editSemesterStatus( { companyId, semesterStatusId, ...data }: Record, options: Record = { detail: false, } -): Thunk { - return (dispatch) => { +) { + return (dispatch: AppDispatch) => { return dispatch( - callAPI({ + callAPI({ types: Company.EDIT_SEMESTER_STATUS, endpoint: `/companies/${companyId}/semester-statuses/${semesterStatusId}/`, method: 'PATCH', @@ -251,10 +269,8 @@ export function editSemesterStatus( }); }; } -export function deleteSemesterStatus( - companyId: number, - semesterStatusId: number -): Thunk { + +export function deleteSemesterStatus(companyId: ID, semesterStatusId: ID) { return callAPI({ types: Company.DELETE_SEMESTER_STATUS, endpoint: `/companies/${companyId}/semester-statuses/${semesterStatusId}/`, @@ -267,12 +283,9 @@ export function deleteSemesterStatus( }, }); } -export function fetchCompanyContacts({ - companyId, -}: { - companyId: number; -}): Thunk { - return callAPI({ + +export function fetchCompanyContacts({ companyId }: { companyId: ID }) { + return callAPI({ types: Company.FETCH_COMPANY_CONTACT, endpoint: `/companies/${companyId}/company-contacts/`, method: 'GET', @@ -281,16 +294,17 @@ export function fetchCompanyContacts({ }, }); } + export function addCompanyContact({ companyId, name, role, mail, phone, -}: Record): Thunk { - return (dispatch) => { +}: Record) { + return (dispatch: AppDispatch) => { return dispatch( - callAPI({ + callAPI({ types: Company.ADD_COMPANY_CONTACT, endpoint: `/companies/${companyId}/company-contacts/`, method: 'POST', @@ -315,6 +329,7 @@ export function addCompanyContact({ }); }; } + export function editCompanyContact({ companyId, companyContactId, @@ -322,10 +337,10 @@ export function editCompanyContact({ role, mail, phone, -}: Record): Thunk { - return (dispatch) => { +}: Record) { + return (dispatch: AppDispatch) => { return dispatch( - callAPI({ + callAPI({ types: Company.EDIT_COMPANY_CONTACT, endpoint: `/companies/${companyId}/company-contacts/${companyContactId}/`, method: 'PATCH', @@ -350,10 +365,7 @@ export function editCompanyContact({ }); }; } -export function deleteCompanyContact( - companyId: number, - companyContactId: number -): Thunk { +export function deleteCompanyContact(companyId: ID, companyContactId: ID) { return callAPI({ types: Company.DELETE_COMPANY_CONTACT, endpoint: `/companies/${companyId}/company-contacts/${companyContactId}/`, @@ -366,18 +378,20 @@ export function deleteCompanyContact( }, }); } -export function fetchSemestersForInterestform(): Thunk { + +export function fetchSemestersForInterestform() { return fetchSemesters({ company_interest: 'True', }); } + export function fetchSemesters( queries: Record< string, (string | null | undefined) | (number | null | undefined) > = {} -): Thunk { - return callAPI({ +) { + return callAPI({ types: Company.FETCH_SEMESTERS, endpoint: `/company-semesters/${createQueryString(queries)}`, schema: [companySemesterSchema], @@ -387,13 +401,11 @@ export function fetchSemesters( propagateError: true, }); } -export function addSemester({ - year, - semester, -}: CompanySemesterEntity): Thunk { - return (dispatch) => { + +export function addSemester({ year, semester }: CompanySemesterEntity) { + return (dispatch: AppDispatch) => { return dispatch( - callAPI({ + callAPI({ types: Company.ADD_SEMESTER, endpoint: `/company-semesters/`, method: 'POST', @@ -410,20 +422,21 @@ export function addSemester({ ); }; } + export function editSemester({ id, year, semester, activeInterestForm, }: { - id: number; + id: ID; year: string; semester: string; activeInterestForm: boolean; -}): Thunk { - return (dispatch) => { +}) { + return (dispatch: AppDispatch) => { return dispatch( - callAPI({ + callAPI({ types: Company.EDIT_SEMESTER, endpoint: `/company-semesters/${id}/`, method: 'PATCH', diff --git a/app/actions/ContactActions.ts b/app/actions/ContactActions.ts index da21ea06b7..049596120d 100644 --- a/app/actions/ContactActions.ts +++ b/app/actions/ContactActions.ts @@ -1,10 +1,9 @@ import type { ContactForm } from 'app/reducers/contact'; -import type { Thunk } from 'app/types'; import { Contact } from './ActionTypes'; import callAPI from './callAPI'; -export function sendContactMessage(contactForm: ContactForm): Thunk { - return callAPI({ +export function sendContactMessage(contactForm: ContactForm) { + return callAPI({ types: Contact.SEND_MESSAGE, method: 'POST', endpoint: '/contact-form/', diff --git a/app/actions/UserActions.ts b/app/actions/UserActions.ts index 43530e18f5..43cda77df8 100644 --- a/app/actions/UserActions.ts +++ b/app/actions/UserActions.ts @@ -7,7 +7,7 @@ import callAPI from 'app/actions/callAPI'; import config from 'app/config'; import type { AddPenalty, ID, PhotoConsent } from 'app/models'; import { userSchema, penaltySchema } from 'app/reducers'; -import type { UpdateUser } from 'app/store/models/User'; +import type { CurrentUser, UpdateUser } from 'app/store/models/User'; import type { Thunk, Action, Token, EncodedToken, GetCookie } from 'app/types'; import { User, Penalty } from './ActionTypes'; import { uploadFile } from './FileActions'; @@ -79,12 +79,14 @@ export function login( }); }); } + export function logoutWithRedirect(): Thunk { return (dispatch) => { dispatch(logout()); dispatch(push('/')); }; } + export function logout(): Thunk { return (dispatch) => { removeToken(); @@ -94,6 +96,7 @@ export function logout(): Thunk { dispatch(fetchMeta()); }; } + export function updateUser( user: UpdateUser, options: { @@ -154,6 +157,7 @@ export function updateUser( } }); } + type PasswordPayload = { password: string; newPassword: string; @@ -275,8 +279,8 @@ const defaultOptions = { export function fetchUser( username = 'me', { propagateError } = defaultOptions -): Thunk { - return callAPI({ +) { + return callAPI({ types: User.FETCH, endpoint: `/users/${username}/`, schema: userSchema, @@ -287,7 +291,8 @@ export function fetchUser( propagateError, }); } -export function refreshToken(token: EncodedToken): Thunk { + +export function refreshToken(token: EncodedToken) { return callAPI({ types: User.REFRESH_TOKEN, endpoint: '//authorization/token-auth/refresh/', @@ -297,7 +302,8 @@ export function refreshToken(token: EncodedToken): Thunk { }, }); } -export function loginWithExistingToken(token: Token): Thunk { + +export function loginWithExistingToken(token: Token) { return (dispatch) => { const now = moment(); const expirationTime = moment.unix(token.exp); @@ -415,10 +421,11 @@ export function createUser(token: string, user: string): Thunk { }); }); } -export function deleteUser(password: string): Thunk> { + +export function deleteUser(password: string) { return (dispatch) => dispatch( - callAPI({ + callAPI({ types: User.DELETE, endpoint: '/user-delete/', method: 'POST', diff --git a/app/components/CommentForm/index.tsx b/app/components/CommentForm/index.tsx index a1e0081d4d..33d08acb1e 100644 --- a/app/components/CommentForm/index.tsx +++ b/app/components/CommentForm/index.tsx @@ -11,12 +11,13 @@ import Flex from 'app/components/Layout/Flex'; import { useAppDispatch } from 'app/store/hooks'; import type { ID } from 'app/store/models'; import type { CurrentUser } from 'app/store/models/User'; +import type { ContentTarget } from 'app/store/utils/contentTarget'; import { spySubmittable } from 'app/utils/formSpyUtils'; import { createValidator, legoEditorRequired } from 'app/utils/validation'; import styles from './CommentForm.css'; type Props = { - contentTarget: string; + contentTarget: ContentTarget; user: CurrentUser; loggedIn: boolean; submitText?: string; @@ -53,16 +54,10 @@ const CommentForm = ({ }} validate={validate} onSubmit={({ text }) => - dispatch( - addComment({ - contentTarget, - text, - parent, - }) - ) + dispatch(addComment({ contentTarget, text, parent })) } > - {({ handleSubmit, pristine, submitting, form, values }) => { + {({ handleSubmit, values }) => { return (
diff --git a/app/routes/announcements/components/AnnouncementItem.tsx b/app/routes/announcements/components/AnnouncementItem.tsx index ed7cda07c2..a53d03062d 100644 --- a/app/routes/announcements/components/AnnouncementItem.tsx +++ b/app/routes/announcements/components/AnnouncementItem.tsx @@ -98,17 +98,10 @@ const AnnouncementItem = ({ actionGrant.includes('send') && actionGrant.includes('delete') && ( - - diff --git a/app/routes/announcements/components/AnnouncementsList.css b/app/routes/announcements/components/AnnouncementsList.css index ba2add8ac5..4e13d2353b 100644 --- a/app/routes/announcements/components/AnnouncementsList.css +++ b/app/routes/announcements/components/AnnouncementsList.css @@ -45,10 +45,6 @@ margin-top: 8px; } -.sendButton { - height: 50px; -} - .wrapperSendButton { justify-content: space-around; align-items: center; diff --git a/app/routes/userValidator/ValidatorRoute.tsx b/app/routes/userValidator/ValidatorRoute.tsx index 5e336056e6..89de77a61b 100644 --- a/app/routes/userValidator/ValidatorRoute.tsx +++ b/app/routes/userValidator/ValidatorRoute.tsx @@ -7,9 +7,9 @@ import { autocomplete } from 'app/actions/SearchActions'; import { fetchUser } from 'app/actions/UserActions'; import { Content } from 'app/components/Content'; import Validator from 'app/components/UserValidator'; -import type { User } from 'app/models'; import { selectAutocompleteRedux as selectAutocomplete } from 'app/reducers/search'; import type { UserSearchResult } from 'app/reducers/search'; +import type { AppDispatch } from 'app/store/createStore'; import withPreparedDispatch from 'app/utils/withPreparedDispatch'; import type { ComponentProps } from 'react'; @@ -38,7 +38,7 @@ const mapStateToProps = (state, props) => { }; }; -const mapDispatchToProps = (dispatch, { location }) => { +const mapDispatchToProps = (dispatch: AppDispatch, { location }) => { const search = qs.parse(location.search, { ignoreQueryPrefix: true, }); @@ -47,13 +47,10 @@ const mapDispatchToProps = (dispatch, { location }) => { clearSearch: () => dispatch(push(`/validator?${qs.stringify({ ...search, q: '' })}`)), - handleSelect: async (result: UserSearchResult): Promise => { - const fetchRes = await dispatch( - fetchUser(result.username, { propagateError: false }) - ); - - return Object.values(fetchRes.payload?.entities?.users)[0] as User; + handleSelect: async (result: UserSearchResult) => { + return dispatch(fetchUser(result.username, { propagateError: false })); }, + onQueryChanged: debounce((query) => { dispatch(push(`/validator?${qs.stringify({ ...search, q: query })}`)); diff --git a/app/store/models/Comment.d.ts b/app/store/models/Comment.d.ts index b3a05806b1..26ae5b9092 100644 --- a/app/store/models/Comment.d.ts +++ b/app/store/models/Comment.d.ts @@ -1,12 +1,12 @@ import type { Dateish } from 'app/models'; -import type User from 'app/store/models/User'; +import type { PublicUser } from 'app/store/models/User'; import type { ID } from 'app/store/models/index'; import type { ContentTarget } from 'app/store/utils/contentTarget'; export interface Comment { id: ID; text: string | null; - author: User | null; + author: PublicUser | null; contentTarget: ContentTarget; createdAt: Dateish; updatedAt: Dateish;