diff --git a/src/api/Message.ts b/src/api/Message.ts index 9c92f412..06c2589b 100644 --- a/src/api/Message.ts +++ b/src/api/Message.ts @@ -1,7 +1,4 @@ import { ApiUrl, Response } from './Api' -import AuthSingleton from '../components/AuthService' - -const Auth = AuthSingleton.getInstance() interface MessagesResponseData { messages: Array @@ -23,34 +20,48 @@ export interface Message { attachments: any[] } -export function getMessages( - ticker: number -): Promise> { - return Auth.fetch(`${ApiUrl}/admin/tickers/${ticker}/messages`) -} +export function useMessageApi(token: string) { + const headers = { + Accept: 'application/json', + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + } -// TODO: any -export function postMessage( - ticker: string, - text: string, - geoInformation: any, - attachments: any[] -): Promise> { - return Auth.fetch(`${ApiUrl}/admin/tickers/${ticker}/messages`, { - body: JSON.stringify({ - text: text, - geo_information: geoInformation, - attachments: attachments, - }), - method: 'POST', - }) -} + const getMessages = ( + ticker: number + ): Promise> => { + return fetch(`${ApiUrl}/admin/tickers/${ticker}/messages`, { + headers: headers, + }).then(response => response.json()) + } + + // TODO: any + const postMessage = ( + ticker: string, + text: string, + geoInformation: any, + attachments: any[] + ): Promise> => { + return fetch(`${ApiUrl}/admin/tickers/${ticker}/messages`, { + headers: headers, + body: JSON.stringify({ + text: text, + geo_information: geoInformation, + attachments: attachments, + }), + method: 'post', + }).then(response => response.json()) + } + + const deleteMessage = ( + ticker: string, + message: string + ): Promise> => { + return fetch(`${ApiUrl}/admin/tickers/${ticker}/messages/${message}`, { + headers: headers, + method: 'delete', + }).then(response => response.json()) + } -export function deleteMessage( - ticker: string, - message: string -): Promise> { - return Auth.fetch(`${ApiUrl}/admin/tickers/${ticker}/messages/${message}`, { - method: 'DELETE', - }) + return { deleteMessage, getMessages, postMessage } } diff --git a/src/api/Settings.ts b/src/api/Settings.ts index 82440f8d..b1fe5f1a 100644 --- a/src/api/Settings.ts +++ b/src/api/Settings.ts @@ -1,7 +1,4 @@ import { ApiUrl, Response } from './Api' -import AuthSingleton from '../components/AuthService' - -const Auth = AuthSingleton.getInstance() interface InactiveSettingsResponseData { setting: Setting @@ -33,30 +30,53 @@ export interface RefreshInterval { value: string } -export function getInactiveSettings(): Promise< - Response -> { - return Auth.fetch(`${ApiUrl}/admin/settings/inactive_settings`) -} +export function useSettingsApi(token: string) { + const headers = { + Accept: 'application/json', + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + } -export function getRefreshInterval(): Promise< - Response -> { - return Auth.fetch(`${ApiUrl}/admin/settings/refresh_interval`) -} + const getInactiveSettings = (): Promise< + Response + > => { + return fetch(`${ApiUrl}/admin/settings/inactive_settings`, { + headers: headers, + }).then(response => response.json()) + } -export function putInactiveSettings(data: InactiveSetting) { - return Auth.fetch(`${ApiUrl}/admin/settings/inactive_settings`, { - body: JSON.stringify(data), - method: 'PUT', - }) -} + const getRefreshInterval = (): Promise< + Response + > => { + return fetch(`${ApiUrl}/admin/settings/refresh_interval`, { + headers: headers, + }).then(response => response.json()) + } + + const putRefreshInterval = ( + refreshInterval: number + ): Promise> => { + return fetch(`${ApiUrl}/admin/settings/refresh_interval`, { + headers: headers, + body: JSON.stringify({ refresh_interval: refreshInterval }), + method: 'put', + }).then(response => response.json()) + } + + const putInactiveSettings = ( + data: InactiveSetting + ): Promise> => { + return fetch(`${ApiUrl}/admin/settings/inactive_settings`, { + headers: headers, + body: JSON.stringify(data), + method: 'put', + }).then(response => response.json()) + } -export function putRefreshInterval( - refreshInterval: number -): Promise> { - return Auth.fetch(`${ApiUrl}/admin/settings/refresh_interval`, { - body: JSON.stringify({ refresh_interval: refreshInterval }), - method: 'PUT', - }) + return { + getInactiveSettings, + getRefreshInterval, + putInactiveSettings, + putRefreshInterval, + } } diff --git a/src/api/Ticker.ts b/src/api/Ticker.ts index ad149ba1..bc40f25c 100644 --- a/src/api/Ticker.ts +++ b/src/api/Ticker.ts @@ -1,19 +1,12 @@ import { ApiUrl, Response } from './Api' -import AuthSingleton from '../components/AuthService' import { User } from './User' -const Auth = AuthSingleton.getInstance() - -interface TickersResponse { - data: { - tickers: Array - } +interface TickersResponseData { + tickers: Array } -interface TickerResponse { - data: { - ticker: Ticker - } +interface TickerResponseData { + ticker: Ticker } interface TickerUsersResponseData { @@ -50,78 +43,14 @@ export interface TickerLocation { lon: number } -export function getTickers(): Promise { - return Auth.fetch(`${ApiUrl}/admin/tickers`) -} - -export function getTicker(id: number): Promise { - return Auth.fetch(`${ApiUrl}/admin/tickers/${id}`) -} - -export function postTicker(data: any): Promise { - return Auth.fetch(`${ApiUrl}/admin/tickers`, { - body: JSON.stringify(data), - method: 'POST', - }) -} - -export function putTicker(data: any, id: number): Promise { - return Auth.fetch(`${ApiUrl}/admin/tickers/${id}`, { - body: JSON.stringify(data), - method: 'PUT', - }) -} - -/** - * - * @param data - * @param id - * @returns {Promise} - */ +/* export function putTickerTwitter(data: any, id: number) { return Auth.fetch(`${ApiUrl}/admin/tickers/${id}/twitter`, { body: JSON.stringify(data), method: 'PUT', }) } - -export function deleteTicker(id: number) { - return Auth.fetch(`${ApiUrl}/admin/tickers/${id}`, { - method: 'DELETE', - }) -} - -/** - * - * @param {string|number} id - * @returns {Promise} - */ -export function getTickerUsers(id: number) { - return Auth.fetch(`${ApiUrl}/admin/tickers/${id}/users`) -} - -/** - * @param id - * @param users - * @returns {Promise} - */ -export function putTickerUser(id: number, ...users: any) { - return Auth.fetch(`${ApiUrl}/admin/tickers/${id}/users`, { - body: JSON.stringify({ users: users }), - method: 'PUT', - }) -} - -/** - * @param id - * @param userId - * @returns {Promise} - */ -export function deleteTickerUser(id: number, userId: number) { - return Auth.fetch(`${ApiUrl}/admin/tickers/${id}/users/${userId}`, { - method: 'DELETE', - }) -} +*/ export function useTickerApi(token: string) { const headers = { @@ -130,6 +59,13 @@ export function useTickerApi(token: string) { 'Content-Type': 'application/json', } + const deleteTicker = (ticker: Ticker): Promise> => { + return fetch(`${ApiUrl}/admin/tickers/${ticker.id}`, { + headers: headers, + method: 'delete', + }).then(response => response.json()) + } + const getTickerUsers = ( ticker: Ticker ): Promise> => { @@ -148,6 +84,37 @@ export function useTickerApi(token: string) { }).then(response => response.json()) } + const getTickers = (): Promise> => { + return fetch(`${ApiUrl}/admin/tickers`, { headers: headers }).then( + response => response.json() + ) + } + + const getTicker = (id: number): Promise> => { + return fetch(`${ApiUrl}/admin/tickers/${id}`, { headers: headers }).then( + response => response.json() + ) + } + + const postTicker = (data: any): Promise> => { + return fetch(`${ApiUrl}/admin/tickers`, { + headers: headers, + body: JSON.stringify(data), + method: 'post', + }).then(response => response.json()) + } + + const putTicker = ( + data: any, + id: number + ): Promise> => { + return fetch(`${ApiUrl}/admin/tickers/${id}`, { + headers: headers, + body: JSON.stringify(data), + method: 'put', + }).then(response => response.json()) + } + const putTickerUsers = ( ticker: Ticker, users: number[] @@ -161,12 +128,22 @@ export function useTickerApi(token: string) { const putTickerReset = ( ticker: Ticker - ): Promise> => { + ): Promise> => { return fetch(`${ApiUrl}/admin/tickers/${ticker.id}/reset`, { headers: headers, method: 'put', }).then(response => response.json()) } - return { deleteTickerUser, getTickerUsers, putTickerUsers, putTickerReset } + return { + deleteTicker, + deleteTickerUser, + getTickers, + getTicker, + getTickerUsers, + postTicker, + putTicker, + putTickerUsers, + putTickerReset, + } } diff --git a/src/api/Upload.js b/src/api/Upload.js deleted file mode 100644 index 70450358..00000000 --- a/src/api/Upload.js +++ /dev/null @@ -1,16 +0,0 @@ -import { ApiUrl } from './Api' -import AuthSingleton from '../components/AuthService' - -const Auth = AuthSingleton.getInstance() - -/** - * - * @param {FormData} formData - * @returns {Promise} - */ -export function postUpload(formData) { - return Auth.fetch(`${ApiUrl}/admin/upload`, { - body: formData, - method: 'POST', - }) -} diff --git a/src/api/Upload.ts b/src/api/Upload.ts new file mode 100644 index 00000000..1f3313f1 --- /dev/null +++ b/src/api/Upload.ts @@ -0,0 +1,33 @@ +import { ApiUrl, Response } from './Api' + +interface UploadeResponseData { + uploads: Array +} + +interface Upload { + id: number + uuid: string + creation_date: Date + url: string + content_type: string +} + +export function useMessageApi(token: string) { + const headers = { + Accept: 'application/json', + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + } + + const postUpload = ( + formData: any + ): Promise> => { + return fetch(`${ApiUrl}/admin/upload`, { + headers: headers, + body: formData, + method: 'post', + }).then(response => response.json()) + } + + return { postUpload } +} diff --git a/src/components/AuthService.js b/src/components/AuthService.js deleted file mode 100644 index 984776f5..00000000 --- a/src/components/AuthService.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @type {{getInstance}} - */ -let AuthSingleton = (function () { - let instance - - /** - * @returns {AuthService} - */ - function createInstance() { - return new AuthService() - } - - return { - /** - * @returns {AuthService} - */ - getInstance: function () { - if (!instance) { - instance = createInstance() - } - - return instance - }, - } -})() - -class AuthService { - constructor() { - this.fetch = this.fetch.bind(this) - this.checkResponse = this.checkResponse.bind(this) - } - - /** - * @param {Request|string} url - * @param {object} options - * @returns {Promise} - */ - fetch(url, options) { - let headers = { - Accept: 'application/json', - 'Content-Type': 'application/json', - } - - //With formData the Content-Type will be set automatically - if (options !== undefined && options.body instanceof FormData) { - headers = {} - } - - headers['Authorization'] = 'Bearer ' + localStorage.getItem('token') - - return fetch(url, { headers, ...options }) - .then(this.checkResponse) - .then(response => response.json()) - } - - /** - * @param {Response} response - * @returns {Response} - * @throws Error - */ - checkResponse(response) { - if (response.status >= 200 && response.status < 300) { - return response - } else { - return response.json().then(data => { - let error = new Error() - - error.message = data.error.message - ? data.error.message - : 'Unknown error' - error.code = data.error.code - error.response = response - - throw error - }) - } - } -} - -export default AuthSingleton diff --git a/src/components/InactiveSettingsCard.tsx b/src/components/InactiveSettingsCard.tsx index 42b3f306..55c708b8 100644 --- a/src/components/InactiveSettingsCard.tsx +++ b/src/components/InactiveSettingsCard.tsx @@ -10,10 +10,13 @@ import { List, Loader, } from 'semantic-ui-react' -import { getInactiveSettings } from '../api/Settings' +import { useSettingsApi } from '../api/Settings' import InactiveSettingsModalForm from './InactiveSettingsModalForm' +import useAuth from './useAuth' const InactiveSettingsCard: FC = () => { + const { token } = useAuth() + const { getInactiveSettings } = useSettingsApi(token) const { isLoading, error, data } = useQuery( 'inactive_settings', getInactiveSettings, diff --git a/src/components/InactiveSettingsForm.tsx b/src/components/InactiveSettingsForm.tsx index 61d130c1..e5674c01 100644 --- a/src/components/InactiveSettingsForm.tsx +++ b/src/components/InactiveSettingsForm.tsx @@ -13,7 +13,8 @@ import { InputOnChangeData, TextAreaProps, } from 'semantic-ui-react' -import { InactiveSetting, putInactiveSettings, Setting } from '../api/Settings' +import { InactiveSetting, Setting, useSettingsApi } from '../api/Settings' +import useAuth from './useAuth' interface Props { setting: Setting @@ -43,6 +44,8 @@ const InactiveSettingsForm: FC = props => { twitter: setting.value.twitter, }, }) + const { token } = useAuth() + const { putInactiveSettings } = useSettingsApi(token) const queryClient = useQueryClient() const onChange = useCallback( diff --git a/src/components/MessageForm.tsx b/src/components/MessageForm.tsx index 643c4e37..dba6b7c7 100644 --- a/src/components/MessageForm.tsx +++ b/src/components/MessageForm.tsx @@ -6,7 +6,7 @@ import React, { useEffect, useState, } from 'react' -import { postMessage } from '../api/Message' +import { useMessageApi } from '../api/Message' import { Button, Form, @@ -17,6 +17,7 @@ import { Ticker } from '../api/Ticker' import { SubmitHandler, useForm } from 'react-hook-form' import { useQueryClient } from 'react-query' import MessageFormCounter from './MessageFormCounter' +import useAuth from './useAuth' interface Props { ticker: Ticker @@ -37,6 +38,8 @@ const MessageForm: FC = ({ ticker }) => { setValue, watch, } = useForm() + const { token } = useAuth() + const { postMessage } = useMessageApi(token) const queryClient = useQueryClient() const watchMessage = watch('message', '') diff --git a/src/components/MessageList.tsx b/src/components/MessageList.tsx index 118aac8c..91a0ac48 100644 --- a/src/components/MessageList.tsx +++ b/src/components/MessageList.tsx @@ -1,15 +1,18 @@ import React, { FC } from 'react' import { Dimmer, Feed, Loader } from 'semantic-ui-react' import { Ticker } from '../api/Ticker' -import { getMessages } from '../api/Message' +import { useMessageApi } from '../api/Message' import Message from '../components/Message' import { useQuery } from 'react-query' +import useAuth from './useAuth' interface Props { ticker: Ticker } const MessageList: FC = ({ ticker }) => { + const { token } = useAuth() + const { getMessages } = useMessageApi(token) const { isLoading, error, data } = useQuery( ['messages', ticker.id], () => getMessages(ticker.id), diff --git a/src/components/MessageModalDelete.tsx b/src/components/MessageModalDelete.tsx index 699e89f7..33b1645a 100644 --- a/src/components/MessageModalDelete.tsx +++ b/src/components/MessageModalDelete.tsx @@ -1,7 +1,8 @@ import React, { FC, useCallback, useState } from 'react' import { useQueryClient } from 'react-query' import { Confirm } from 'semantic-ui-react' -import { deleteMessage, Message } from '../api/Message' +import { Message, useMessageApi } from '../api/Message' +import useAuth from './useAuth' interface Props { message: Message @@ -9,6 +10,8 @@ interface Props { } const MessageModalDelete: FC = props => { + const { token } = useAuth() + const { deleteMessage } = useMessageApi(token) const [open, setOpen] = useState(false) const queryClient = useQueryClient() const tickerId = props.message.ticker.toString() @@ -22,7 +25,7 @@ const MessageModalDelete: FC = props => { deleteMessage(tickerId, messageId).finally(() => { queryClient.invalidateQueries(['messages', tickerId]) }) - }, [tickerId, messageId, queryClient]) + }, [deleteMessage, tickerId, messageId, queryClient]) const handleOpen = useCallback(() => { setOpen(true) diff --git a/src/components/RefreshIntervalCard.tsx b/src/components/RefreshIntervalCard.tsx index 5f91705f..b41ad9c8 100644 --- a/src/components/RefreshIntervalCard.tsx +++ b/src/components/RefreshIntervalCard.tsx @@ -1,10 +1,13 @@ import React, { FC } from 'react' import { useQuery } from 'react-query' import { Button, Card, Dimmer, Icon, List, Loader } from 'semantic-ui-react' -import { getRefreshInterval } from '../api/Settings' +import { useSettingsApi } from '../api/Settings' import RefreshIntervalModalForm from './RefreshIntervalModalForm' +import useAuth from './useAuth' const RefreshIntervalCard: FC = () => { + const { token } = useAuth() + const { getRefreshInterval } = useSettingsApi(token) const { isLoading, error, data } = useQuery( 'refresh_interval_setting', getRefreshInterval, diff --git a/src/components/RefreshIntervalForm.tsx b/src/components/RefreshIntervalForm.tsx index 57b70f94..57c4c6fb 100644 --- a/src/components/RefreshIntervalForm.tsx +++ b/src/components/RefreshIntervalForm.tsx @@ -2,7 +2,8 @@ import React, { FC, FormEvent, useCallback, useEffect } from 'react' import { SubmitHandler, useForm } from 'react-hook-form' import { useQueryClient } from 'react-query' import { Form, InputOnChangeData } from 'semantic-ui-react' -import { putRefreshInterval, Setting } from '../api/Settings' +import { Setting, useSettingsApi } from '../api/Settings' +import useAuth from './useAuth' interface Props { setting: Setting @@ -20,6 +21,8 @@ const RefreshIntervalForm: FC = props => { refresh_interval: parseInt(setting.value, 10), }, }) + const { token } = useAuth() + const { putRefreshInterval } = useSettingsApi(token) const queryClient = useQueryClient() const onChange = useCallback( diff --git a/src/components/TickerForm.tsx b/src/components/TickerForm.tsx index 385c95db..dfd81783 100644 --- a/src/components/TickerForm.tsx +++ b/src/components/TickerForm.tsx @@ -14,9 +14,10 @@ import { InputOnChangeData, TextAreaProps, } from 'semantic-ui-react' -import { postTicker, putTicker, Ticker } from '../api/Ticker' +import { Ticker, useTickerApi } from '../api/Ticker' import { SubmitHandler, useForm } from 'react-hook-form' import { useQueryClient } from 'react-query' +import useAuth from './useAuth' interface Props { ticker?: Ticker @@ -54,6 +55,8 @@ const TickerForm: FC = props => { }, }, }) + const { token } = useAuth() + const { postTicker, putTicker } = useTickerApi(token) const queryClient = useQueryClient() const onChange = useCallback( diff --git a/src/components/TickerList.tsx b/src/components/TickerList.tsx index 1a979c30..4f5cdb63 100644 --- a/src/components/TickerList.tsx +++ b/src/components/TickerList.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react' -import { getTickers } from '../api/Ticker' +import { useTickerApi } from '../api/Ticker' import { Button, Dimmer, Loader, Table } from 'semantic-ui-react' import TickerModalForm from './TickerModalForm' import { useQuery } from 'react-query' @@ -7,7 +7,8 @@ import TickerListItems from './TickerListItems' import useAuth from './useAuth' const TickerList: FC = () => { - const { user } = useAuth() + const { token, user } = useAuth() + const { getTickers } = useTickerApi(token) const { isLoading, error, data } = useQuery('tickers', getTickers, { refetchInterval: false, }) diff --git a/src/components/TickerModalDelete.tsx b/src/components/TickerModalDelete.tsx index 7e599a44..b07014e1 100644 --- a/src/components/TickerModalDelete.tsx +++ b/src/components/TickerModalDelete.tsx @@ -1,7 +1,8 @@ import React, { FC, useCallback, useState } from 'react' import { useQueryClient } from 'react-query' import { Confirm } from 'semantic-ui-react' -import { deleteTicker, Ticker } from '../api/Ticker' +import { Ticker, useTickerApi } from '../api/Ticker' +import useAuth from './useAuth' interface Props { ticker: Ticker @@ -10,6 +11,8 @@ interface Props { const TickerModalDelete: FC = props => { const [open, setOpen] = useState(false) + const { token } = useAuth() + const { deleteTicker } = useTickerApi(token) const queryClient = useQueryClient() const ticker = props.ticker @@ -18,10 +21,10 @@ const TickerModalDelete: FC = props => { }, []) const handleConfirm = useCallback(() => { - deleteTicker(ticker.id).finally(() => { + deleteTicker(ticker).finally(() => { queryClient.invalidateQueries('tickers') }) - }, [ticker, queryClient]) + }, [deleteTicker, ticker, queryClient]) const handleOpen = useCallback(() => { setOpen(true) diff --git a/src/components/TickersDropdown.tsx b/src/components/TickersDropdown.tsx index cf83170f..619bc254 100644 --- a/src/components/TickersDropdown.tsx +++ b/src/components/TickersDropdown.tsx @@ -6,7 +6,8 @@ import React, { useState, } from 'react' import { Dropdown, DropdownItemProps, DropdownProps } from 'semantic-ui-react' -import { getTickers } from '../api/Ticker' +import { useTickerApi } from '../api/Ticker' +import useAuth from './useAuth' interface Props { name: string @@ -16,6 +17,8 @@ interface Props { const TickersDropdown: FC = props => { const [options, setOptions] = useState([]) + const { token } = useAuth() + const { getTickers } = useTickerApi(token) const onChange = useCallback( (event: SyntheticEvent, input: DropdownProps) => { @@ -38,7 +41,7 @@ const TickersDropdown: FC = props => { }) setOptions(availableOptions) }) - }, []) + }, [getTickers]) return ( { + const { token } = useAuth() + const { getTicker } = useTickerApi(token) const { tickerId } = useParams() as TickerViewParams const { user } = useAuth() const tickerIdNum = parseInt(tickerId)