Even more code styling things
@ -32,5 +32,16 @@ module.exports = {
|
||||
}
|
||||
],
|
||||
'jsx-quotes': [2, 'prefer-single'],
|
||||
'comma-dangle': 'off',
|
||||
'@typescript-eslint/comma-dangle': ['warn', {
|
||||
'arrays': 'always-multiline',
|
||||
'objects': 'always-multiline',
|
||||
'imports': 'always-multiline',
|
||||
'exports': 'always-multiline',
|
||||
'functions': 'only-multiline',
|
||||
'enums': 'always-multiline',
|
||||
'generics': 'always-multiline',
|
||||
'tuples': 'always-multiline',
|
||||
}],
|
||||
},
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ const processAnnouncement = (data: AnnouncementResponse): Announcement => ({
|
||||
lng: data.longtitude,
|
||||
bestBy: data.best_by,
|
||||
bookedBy: data.booked_by,
|
||||
userId: data.user_id
|
||||
userId: data.user_id,
|
||||
})
|
||||
|
||||
export { processAnnouncement }
|
||||
|
@ -14,7 +14,7 @@ type AnnouncementResponse = {
|
||||
src: string | null,
|
||||
metro: string,
|
||||
trashId: number | null,
|
||||
booked_by: number
|
||||
booked_by: number,
|
||||
}
|
||||
|
||||
const isAnnouncementResponse = (obj: unknown): obj is AnnouncementResponse => (
|
||||
@ -31,7 +31,7 @@ const isAnnouncementResponse = (obj: unknown): obj is AnnouncementResponse => (
|
||||
'src': 'string?',
|
||||
'metro': 'string',
|
||||
'trashId': 'number?',
|
||||
'booked_by': 'number'
|
||||
'booked_by': 'number',
|
||||
})
|
||||
)
|
||||
|
||||
@ -48,7 +48,7 @@ type Announcement = {
|
||||
src: string | null,
|
||||
metro: string,
|
||||
trashId: number | null,
|
||||
bookedBy: number
|
||||
bookedBy: number,
|
||||
}
|
||||
|
||||
export type {
|
||||
|
@ -3,13 +3,13 @@ import { AnnouncementResponse, isAnnouncementResponse } from '../announcement/ty
|
||||
|
||||
type AnnouncementsResponse = {
|
||||
list_of_announcements: AnnouncementResponse[],
|
||||
Success: boolean
|
||||
Success: boolean,
|
||||
}
|
||||
|
||||
const isAnnouncementsResponse = (obj: unknown): obj is AnnouncementsResponse => (
|
||||
isObject(obj, {
|
||||
'list_of_announcements': obj => isArrayOf<AnnouncementResponse>(obj, isAnnouncementResponse),
|
||||
'Success': 'boolean'
|
||||
'Success': 'boolean',
|
||||
})
|
||||
)
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { isObject } from '../../utils/types'
|
||||
|
||||
type BookResponse = {
|
||||
Success: boolean
|
||||
Success: boolean,
|
||||
}
|
||||
|
||||
const isBookResponse = (obj: unknown): obj is BookResponse => (
|
||||
isObject(obj, {
|
||||
'Success': 'boolean'
|
||||
'Success': 'boolean',
|
||||
})
|
||||
)
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { isObject } from '../../utils/types'
|
||||
|
||||
type OsmAddressResponse = {
|
||||
display_name: string
|
||||
display_name: string,
|
||||
}
|
||||
|
||||
const isOsmAddressResponse = (obj: unknown): obj is OsmAddressResponse => (
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { isObject } from '../../utils/types'
|
||||
|
||||
type PutAnnouncementResponse = {
|
||||
Answer: boolean
|
||||
Answer: boolean,
|
||||
}
|
||||
|
||||
const isPutAnnouncementResponse = (obj: unknown): obj is PutAnnouncementResponse => (
|
||||
isObject(obj, {
|
||||
'Answer': 'boolean'
|
||||
'Answer': 'boolean',
|
||||
})
|
||||
)
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { isObject } from '../../utils/types'
|
||||
|
||||
type RemoveAnnouncementResponse = {
|
||||
Answer: boolean
|
||||
Answer: boolean,
|
||||
}
|
||||
|
||||
const isRemoveAnnouncementResponse = (obj: unknown): obj is RemoveAnnouncementResponse => (
|
||||
isObject(obj, {
|
||||
'Answer': 'boolean'
|
||||
'Answer': 'boolean',
|
||||
})
|
||||
)
|
||||
|
||||
|
@ -11,7 +11,7 @@ type SignUpResponse = {
|
||||
Success: true,
|
||||
} | {
|
||||
Success: false,
|
||||
Message: string
|
||||
Message: string,
|
||||
}
|
||||
|
||||
const isSignUpResponse = (obj: unknown): obj is SignUpResponse => (
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { isObject } from '../../utils/types'
|
||||
|
||||
type TokenResponse = {
|
||||
access_token: string
|
||||
access_token: string,
|
||||
}
|
||||
|
||||
const isTokenResponse = (obj: unknown): obj is TokenResponse => (
|
||||
isObject(obj, {
|
||||
'access_token': 'string'
|
||||
'access_token': 'string',
|
||||
})
|
||||
)
|
||||
|
||||
|
@ -6,11 +6,12 @@ import { Trashbox, TrashboxResponse } from './types'
|
||||
const composeTrashboxURL = (position: LatLng) => (
|
||||
API_URL + '/trashbox?' + new URLSearchParams({
|
||||
lat: position.lat.toString(),
|
||||
lng: position.lng.toString()
|
||||
lng: position.lng.toString(),
|
||||
}).toString()
|
||||
)
|
||||
|
||||
const processTrashbox = (data: TrashboxResponse): Trashbox[] =>
|
||||
const processTrashbox = (data: TrashboxResponse): Trashbox[] => (
|
||||
data
|
||||
)
|
||||
|
||||
export { composeTrashboxURL, processTrashbox }
|
||||
|
@ -4,7 +4,7 @@ type Trashbox = {
|
||||
Lat: number,
|
||||
Lng: number,
|
||||
Address: string,
|
||||
Categories: string[]
|
||||
Categories: string[],
|
||||
}
|
||||
|
||||
const isTrashbox = (obj: unknown): obj is Trashbox => (
|
||||
@ -12,7 +12,7 @@ const isTrashbox = (obj: unknown): obj is Trashbox => (
|
||||
'Lat': 'number',
|
||||
'Lng': 'number',
|
||||
'Address': 'string',
|
||||
'Categories': obj => isArrayOf<string>(obj, isString)
|
||||
'Categories': obj => isArrayOf<string>(obj, isString),
|
||||
})
|
||||
)
|
||||
|
||||
|
@ -10,10 +10,10 @@ const initialUser: User = import.meta.env.DEV ? { // Temporary, until api is rea
|
||||
regDate: faker.date.anytime().getTime(),
|
||||
points: Math.round(Math.random() * 1000),
|
||||
} : {
|
||||
id: -1,
|
||||
name: '',
|
||||
id: 1,
|
||||
name: 'Вася пупкин',
|
||||
regDate: 0,
|
||||
points: 0,
|
||||
points: 100,
|
||||
}
|
||||
|
||||
const composeUserURL = () => (
|
||||
|
@ -4,7 +4,7 @@ type User = {
|
||||
id: number,
|
||||
name: string,
|
||||
regDate: number,
|
||||
points: number
|
||||
points: number,
|
||||
}
|
||||
|
||||
const isUser = (obj: unknown): obj is User => (
|
||||
|
@ -1 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" style="fill: rgb(17, 17, 17); --darkreader-inline-fill: #e8e6e3;" data-darkreader-inline-fill=""><path d="M20 2H4c-1.103 0-2 .897-2 2v18l4-4h14c1.103 0 2-.897 2-2V4c0-1.103-.897-2-2-2zm-3 9h-4v4h-2v-4H7V9h4V5h2v4h4v2z"></path></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" style="fill: rgb(17, 17, 17); --darkreader-inline-fill: #e8e6e3;" data-darkreader-inline-fill="">
|
||||
<path d="M20 2H4c-1.103 0-2 .897-2 2v18l4-4h14c1.103 0 2-.897 2-2V4c0-1.103-.897-2-2-2zm-3 9h-4v4h-2v-4H7V9h4V5h2v4h4v2z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 315 B After Width: | Height: | Size: 317 B |
@ -1 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" style="fill: rgb(17, 17, 17); --darkreader-inline-fill: #e8e6e3;" data-darkreader-inline-fill=""><path d="M13 20v-4.586L20.414 8c.375-.375.586-.884.586-1.415V4a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v2.585c0 .531.211 1.04.586 1.415L11 15.414V22l2-2z"></path></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" style="fill: rgb(17, 17, 17); --darkreader-inline-fill: #e8e6e3;" data-darkreader-inline-fill="">
|
||||
<path d="M13 20v-4.586L20.414 8c.375-.375.586-.884.586-1.415V4a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v2.585c0 .531.211 1.04.586 1.415L11 15.414V22l2-2z" />
|
||||
</svg>
|
Before Width: | Height: | Size: 337 B After Width: | Height: | Size: 338 B |
@ -1 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" style="fill: rgb(17, 17, 17); --darkreader-inline-fill: #e8e6e3;" data-darkreader-inline-fill=""><path d="M20.5 5A1.5 1.5 0 0 0 19 6.5V11h-1V4.5a1.5 1.5 0 0 0-3 0V11h-1V3.5a1.5 1.5 0 0 0-3 0V11h-1V5.5a1.5 1.5 0 0 0-3 0v10.81l-2.22-3.6a1.5 1.5 0 0 0-2.56 1.58l3.31 5.34A5 5 0 0 0 9.78 22H17a5 5 0 0 0 5-5V6.5A1.5 1.5 0 0 0 20.5 5z"></path></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" style="fill: rgb(17, 17, 17); --darkreader-inline-fill: #e8e6e3;" data-darkreader-inline-fill="">
|
||||
<path d="M20.5 5A1.5 1.5 0 0 0 19 6.5V11h-1V4.5a1.5 1.5 0 0 0-3 0V11h-1V3.5a1.5 1.5 0 0 0-3 0V11h-1V5.5a1.5 1.5 0 0 0-3 0v10.81l-2.22-3.6a1.5 1.5 0 0 0-2.56 1.58l3.31 5.34A5 5 0 0 0 9.78 22H17a5 5 0 0 0 5-5V6.5A1.5 1.5 0 0 0 20.5 5z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 427 B After Width: | Height: | Size: 429 B |
@ -21,7 +21,7 @@ const stations: Record<Lines, Set<string>> = {
|
||||
'Кировский завод',
|
||||
'Автово',
|
||||
'Ленинский проспект',
|
||||
'Проспект Ветеранов'
|
||||
'Проспект Ветеранов',
|
||||
]),
|
||||
blue: new Set([
|
||||
'Парнас',
|
||||
@ -41,7 +41,7 @@ const stations: Record<Lines, Set<string>> = {
|
||||
'Парк Победы',
|
||||
'Московская',
|
||||
'Звёздная',
|
||||
'Купчино'
|
||||
'Купчино',
|
||||
]),
|
||||
green: new Set([
|
||||
'Приморская',
|
||||
@ -54,7 +54,7 @@ const stations: Record<Lines, Set<string>> = {
|
||||
'Ломоносовская',
|
||||
'Пролетарская',
|
||||
'Обухово',
|
||||
'Рыбацкое'
|
||||
'Рыбацкое',
|
||||
]),
|
||||
orange: new Set([
|
||||
'Спасская',
|
||||
@ -64,7 +64,7 @@ const stations: Record<Lines, Set<string>> = {
|
||||
'Новочеркасская',
|
||||
'Ладожская',
|
||||
'Проспект Большевиков',
|
||||
'Улица Дыбенко'
|
||||
'Улица Дыбенко',
|
||||
]),
|
||||
violet: new Set([
|
||||
'Комендантский проспект',
|
||||
@ -81,7 +81,7 @@ const stations: Record<Lines, Set<string>> = {
|
||||
'Международная',
|
||||
'Проспект славы',
|
||||
'Дунайскай',
|
||||
'Шушары'
|
||||
'Шушары',
|
||||
]),
|
||||
}
|
||||
|
||||
|
@ -1 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" style="fill: rgb(17, 17, 17); --darkreader-inline-fill: #e8e6e3;" data-darkreader-inline-fill=""><path d="M7.5 6.5C7.5 8.981 9.519 11 12 11s4.5-2.019 4.5-4.5S14.481 2 12 2 7.5 4.019 7.5 6.5zM20 21h1v-1c0-3.859-3.141-7-7-7h-4c-3.86 0-7 3.141-7 7v1h17z"></path></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" style="fill: rgb(17, 17, 17); --darkreader-inline-fill: #e8e6e3;" data-darkreader-inline-fill="">
|
||||
<path d="M7.5 6.5C7.5 8.981 9.519 11 12 11s4.5-2.019 4.5-4.5S14.481 2 12 2 7.5 4.019 7.5 6.5zM20 21h1v-1c0-3.859-3.141-7-7-7h-4c-3.86 0-7 3.141-7 7v1h17z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 348 B After Width: | Height: | Size: 350 B |
@ -28,7 +28,7 @@ const styles = {
|
||||
}
|
||||
|
||||
function AnnouncementDetails({ close, refresh, announcement: {
|
||||
id, name, category, bestBy, description, lat, lng, address, metro, bookedBy, userId
|
||||
id, name, category, bestBy, description, lat, lng, address, metro, bookedBy, userId,
|
||||
} }: AnnouncementDetailsProps) {
|
||||
const { handleBook, bookButton } = useBook()
|
||||
|
||||
|
@ -6,7 +6,7 @@ import { composeSignUpBody } from '../api/signup'
|
||||
import { composeSignInBody } from '../api/token'
|
||||
|
||||
type AuthFormProps = {
|
||||
register: boolean
|
||||
register: boolean,
|
||||
goBack: () => void,
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ import { PropsWithChildren } from 'react'
|
||||
import BackButton from '../assets/backArrow.svg'
|
||||
|
||||
type BackHeaderProps = {
|
||||
text: string
|
||||
text: string,
|
||||
}
|
||||
|
||||
function BackHeader({ text, children }: PropsWithChildren<BackHeaderProps>) {
|
||||
|
@ -15,22 +15,20 @@ const styles = {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
height: '100%',
|
||||
margin: 'auto'
|
||||
margin: 'auto',
|
||||
} as CSSProperties,
|
||||
navBarElement: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
justifyContent: 'center',
|
||||
} as CSSProperties,
|
||||
}
|
||||
|
||||
|
||||
|
||||
type BottomNavBarProps = {
|
||||
width: number,
|
||||
toggleFilters: (p: boolean) => void
|
||||
toggleFilters: (state: boolean) => void,
|
||||
}
|
||||
|
||||
function BottomNavBar({ width, toggleFilters }: BottomNavBarProps) {
|
||||
@ -38,7 +36,7 @@ function BottomNavBar({ width, toggleFilters }: BottomNavBarProps) {
|
||||
<div style={styles.navBar}>
|
||||
<div style={{ ...styles.navBarGroup, width: width }}>
|
||||
|
||||
<a style={styles.navBarElement} onClick={() => toggleFilters(true)}>
|
||||
<a href='#' style={styles.navBarElement} onClick={() => toggleFilters(true)}>
|
||||
<img src={filterIcon} alt='Фильтровать объявления' title='Фильтровать объявления' />
|
||||
</a>
|
||||
|
||||
@ -46,7 +44,7 @@ function BottomNavBar({ width, toggleFilters }: BottomNavBarProps) {
|
||||
<img src={addIcon} alt='Опубликовать объявление' title='Опубликовать объявление' />
|
||||
</Link>
|
||||
|
||||
<Link style={styles.navBarElement} to={'/user'} >
|
||||
<Link style={styles.navBarElement} to='/user' >
|
||||
<img src={userIcon} alt='Личный кабинет' title='Личный кабинет' />
|
||||
</Link>
|
||||
|
||||
|
@ -4,7 +4,7 @@ import { Card } from 'react-bootstrap'
|
||||
import { BackHeader } from '.'
|
||||
|
||||
type CardLayoutProps = {
|
||||
text: string
|
||||
text: string,
|
||||
}
|
||||
|
||||
const CardLayout = ({ text, children }: PropsWithChildren<CardLayoutProps>) => (
|
||||
|
@ -4,7 +4,7 @@ import { useAnnouncements } from '../hooks/api'
|
||||
import { gotError } from '../hooks/useFetch'
|
||||
|
||||
type CategoryPreviewProps = {
|
||||
category: UserCategory
|
||||
category: UserCategory,
|
||||
}
|
||||
|
||||
function CategoryPreview({ category }: CategoryPreviewProps) {
|
||||
|
@ -10,21 +10,21 @@ type FiltersProps = {
|
||||
filter: FiltersType,
|
||||
setFilter: SetState<FiltersType>,
|
||||
filterShown: boolean,
|
||||
setFilterShown: SetState<boolean>
|
||||
setFilterShown: SetState<boolean>,
|
||||
}
|
||||
|
||||
function Filters({ filter, setFilter, filterShown, setFilterShown }: FiltersProps) {
|
||||
|
||||
const handleSubmit: FormEventHandler<HTMLFormElement> = (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
const formData = new FormData(event.currentTarget)
|
||||
|
||||
setFilter(prev => ({
|
||||
...prev,
|
||||
category: (formData.get('category') as (FiltersType['category'] | null)) || undefined,
|
||||
metro: (formData.get('metro') as (FiltersType['metro'] | null)) || undefined
|
||||
metro: (formData.get('metro') as (FiltersType['metro'] | null)) || undefined,
|
||||
}))
|
||||
|
||||
setFilterShown(false)
|
||||
|
@ -3,8 +3,9 @@ import { colors, lineNames, lineByName } from '../assets/metro'
|
||||
function LineDot({ station }: { station: string }) {
|
||||
const line = lineByName(station)
|
||||
|
||||
if (line == undefined)
|
||||
if (line == undefined) {
|
||||
return <></>
|
||||
}
|
||||
|
||||
const lineTitle = lineNames[line]
|
||||
const color = colors[line]
|
||||
|
@ -7,7 +7,7 @@ import { iconItem } from '../utils/markerIcons'
|
||||
type LocationMarkerProps = {
|
||||
address: string,
|
||||
position: LatLng,
|
||||
setPosition: SetState<LatLng>
|
||||
setPosition: SetState<LatLng>,
|
||||
}
|
||||
|
||||
function LocationMarker({ address, position, setPosition }: LocationMarkerProps) {
|
||||
@ -21,7 +21,7 @@ function LocationMarker({ address, position, setPosition }: LocationMarkerProps)
|
||||
},
|
||||
resize: () => {
|
||||
setPosition(map.getCenter())
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
return (
|
||||
|
@ -3,7 +3,7 @@ import { CSSProperties } from 'react'
|
||||
import handStarsIcon from '../assets/handStars.svg'
|
||||
|
||||
type PointsProps = {
|
||||
points: number
|
||||
points: number,
|
||||
}
|
||||
|
||||
const styles = {
|
||||
|
@ -9,7 +9,7 @@ import signOutIcon from '../assets/signOut.svg'
|
||||
const styles = {
|
||||
rightIcon: {
|
||||
marginLeft: '1rem',
|
||||
marginRight: 0
|
||||
marginRight: 0,
|
||||
} as CSSProperties,
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ const styles = {
|
||||
} as CSSProperties,
|
||||
leftScrollButton: {
|
||||
left: 0,
|
||||
transform: 'scaleX(-1)'
|
||||
transform: 'scaleX(-1)',
|
||||
} as CSSProperties,
|
||||
rightScrollButton: {
|
||||
right: 0,
|
||||
@ -116,7 +116,7 @@ function StoriesPreview({ announcements, category }: StoriesPreviewProps) {
|
||||
<li key={`${category}${i}`}>
|
||||
<Link to={'/?' + new URLSearchParams({
|
||||
...URLEncodeFilters(composeUserCategoriesFilters[category]()),
|
||||
storyIndex: i.toString()
|
||||
storyIndex: i.toString(),
|
||||
}).toString()} style={styles.link}>
|
||||
{ann.src?.endsWith('mp4') ? (
|
||||
<video src={ann.src} style={styles.image} />
|
||||
|
@ -5,7 +5,10 @@ import { iconTrash } from '../utils/markerIcons'
|
||||
|
||||
type TrashboxMarkersProps = {
|
||||
trashboxes: Trashbox[],
|
||||
selectTrashbox: ({ index, category }: { index: number, category: string }) => void
|
||||
selectTrashbox: ({ index, category }: {
|
||||
index: number,
|
||||
category: string,
|
||||
}) => void,
|
||||
}
|
||||
|
||||
function TrashboxMarkers({ trashboxes, selectTrashbox }: TrashboxMarkersProps) {
|
||||
|
@ -16,7 +16,7 @@ function useAddAnnouncement() {
|
||||
|
||||
function handleAdd(formData: FormData) {
|
||||
void doSend({}, {
|
||||
body: formData
|
||||
body: formData,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,8 @@
|
||||
import { useCallback } from 'react'
|
||||
|
||||
import { isObject } from '../../utils/types'
|
||||
import { useSendWithButton } from '..'
|
||||
import { composeBookURL, processBook } from '../../api/book'
|
||||
|
||||
type BookResponse = {
|
||||
Success: boolean
|
||||
}
|
||||
|
||||
const isBookResponse = (obj: unknown): obj is BookResponse => (
|
||||
isObject(obj, {
|
||||
'Success': 'boolean'
|
||||
})
|
||||
)
|
||||
import { isBookResponse } from '../../api/book/types'
|
||||
|
||||
function useBook() {
|
||||
const { doSend, button } = useSendWithButton('Забронировать',
|
||||
@ -22,17 +12,17 @@ function useBook() {
|
||||
'POST',
|
||||
true,
|
||||
isBookResponse,
|
||||
processBook
|
||||
processBook,
|
||||
)
|
||||
|
||||
const handleBook = useCallback((id: number) => {
|
||||
void doSend({}, {
|
||||
body: JSON.stringify({
|
||||
id
|
||||
id,
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
}, [doSend])
|
||||
|
||||
|
@ -11,7 +11,7 @@ const useOsmAddresses = (addressPosition: LatLng) => (
|
||||
false,
|
||||
isOsmAddressResponse,
|
||||
processOsmAddress,
|
||||
''
|
||||
'',
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -13,17 +13,17 @@ const useRemoveAnnouncement = (resolve: () => void) => {
|
||||
'DELETE',
|
||||
true,
|
||||
isRemoveAnnouncementResponse,
|
||||
processRemoveAnnouncement
|
||||
processRemoveAnnouncement,
|
||||
)
|
||||
|
||||
const doSendWithClose = useCallback(async (id: number) => {
|
||||
const res = await doSend({}, {
|
||||
body: JSON.stringify({
|
||||
id
|
||||
id,
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
|
||||
if (res) {
|
||||
|
@ -17,7 +17,7 @@ function useSignIn() {
|
||||
|
||||
async function handleSignIn(formData: FormData) {
|
||||
const token = await doSend({}, {
|
||||
body: formData
|
||||
body: formData,
|
||||
})
|
||||
|
||||
if (token !== undefined) {
|
||||
|
@ -18,8 +18,8 @@ function useSignUp() {
|
||||
const res = await doSend({}, {
|
||||
body: JSON.stringify(data),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
|
||||
return res ?? false
|
||||
|
@ -11,7 +11,7 @@ const useTrashboxes = (position: LatLng) => (
|
||||
true,
|
||||
isTrashboxResponse,
|
||||
processTrashbox,
|
||||
[]
|
||||
[],
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -16,7 +16,7 @@ const useUser = (): UseFetchReturn<User> => (
|
||||
data: initialUser,
|
||||
loading: false,
|
||||
error: null,
|
||||
refetch: () => { return }
|
||||
refetch: () => { return },
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -15,7 +15,7 @@ type UseFetchSucced<T> = {
|
||||
|
||||
type UseFetchErrored = {
|
||||
error: string,
|
||||
data: undefined
|
||||
data: undefined,
|
||||
} & UseFetchShared
|
||||
|
||||
type UseFetchReturn<T> = UseFetchSucced<T> | UseFetchErrored
|
||||
@ -35,7 +35,7 @@ function useFetch<R, T extends NonNullable<unknown>>(
|
||||
guardResponse: (data: unknown) => data is R,
|
||||
processResponse: (data: R) => T,
|
||||
initialData?: T,
|
||||
params?: Omit<RequestInit, 'method'>
|
||||
params?: Omit<RequestInit, 'method'>,
|
||||
): UseFetchReturn<T> {
|
||||
const [data, setData] = useState(initialData)
|
||||
|
||||
@ -46,7 +46,7 @@ function useFetch<R, T extends NonNullable<unknown>>(
|
||||
guardResponse,
|
||||
processResponse,
|
||||
true,
|
||||
params
|
||||
params,
|
||||
)
|
||||
|
||||
function refetch() {
|
||||
@ -62,11 +62,11 @@ function useFetch<R, T extends NonNullable<unknown>>(
|
||||
return {
|
||||
...(
|
||||
error === null ? ({
|
||||
data: data!, error: null
|
||||
data: data!, error: null,
|
||||
}) : ({ data: undefined, error })
|
||||
),
|
||||
loading,
|
||||
refetch
|
||||
refetch,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ function useFilters(initialFilters: FiltersType = defaultFilters): [FiltersType,
|
||||
const appendFiltersSearchParams = (filters: FiltersType, replace = false) => (
|
||||
setSearchParams(params => ({
|
||||
...Object.fromEntries(params),
|
||||
...URLEncodeFilters(filters)
|
||||
...URLEncodeFilters(filters),
|
||||
}), { replace })
|
||||
)
|
||||
|
||||
|
@ -11,7 +11,7 @@ function useSend<R, T extends NonNullable<unknown>>(
|
||||
guardResponse: (data: unknown) => data is R,
|
||||
processResponse: (data: R) => T,
|
||||
startWithLoading = false,
|
||||
defaultParams?: Omit<RequestInit, 'method'>
|
||||
defaultParams?: Omit<RequestInit, 'method'>,
|
||||
) {
|
||||
const [loading, setLoading] = useState(startWithLoading)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
@ -36,7 +36,7 @@ function useSend<R, T extends NonNullable<unknown>>(
|
||||
|
||||
const headers = new Headers({
|
||||
...defaultParams?.headers,
|
||||
...params?.headers
|
||||
...params?.headers,
|
||||
})
|
||||
|
||||
if (needAuth) {
|
||||
@ -93,7 +93,7 @@ function useSend<R, T extends NonNullable<unknown>>(
|
||||
|
||||
return {
|
||||
doSend, loading, error,
|
||||
abort: abortControllerRef.current?.abort.bind(abortControllerRef.current)
|
||||
abort: abortControllerRef.current?.abort.bind(abortControllerRef.current),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ function useSendButtonCaption(
|
||||
loading: boolean,
|
||||
error: string | null,
|
||||
result = initial,
|
||||
singular = true
|
||||
singular = true,
|
||||
) {
|
||||
const [caption, setCaption] = useState(initial)
|
||||
const [disabled, setDisabled] = useState(false)
|
||||
|
@ -3,7 +3,7 @@ import { useState, useEffect } from 'react';
|
||||
const getWindowDimensions = () => (
|
||||
{
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight
|
||||
height: window.innerHeight,
|
||||
}
|
||||
)
|
||||
|
||||
@ -12,11 +12,11 @@ function useStoryDimensions(maxRatio = 16 / 9) {
|
||||
|
||||
useEffect(() => {
|
||||
function handleResize() {
|
||||
setWindowDimensions(getWindowDimensions());
|
||||
setWindowDimensions(getWindowDimensions())
|
||||
}
|
||||
|
||||
window.addEventListener('resize', handleResize);
|
||||
return () => window.removeEventListener('resize', handleResize);
|
||||
return () => window.removeEventListener('resize', handleResize)
|
||||
}, []);
|
||||
|
||||
const bottomBarHeight = 56
|
||||
@ -27,7 +27,7 @@ function useStoryDimensions(maxRatio = 16 / 9) {
|
||||
|
||||
return {
|
||||
height: height,
|
||||
width: Math.round(height / ratio)
|
||||
width: Math.round(height / ratio),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ function useStoryIndex(annLength: number | undefined) {
|
||||
setIndex(0)
|
||||
setSearchParams(prev => ({
|
||||
...Object.fromEntries(prev),
|
||||
storyIndex: '0'
|
||||
storyIndex: '0',
|
||||
}), { replace: true })
|
||||
f(...args)
|
||||
}
|
||||
@ -29,7 +29,7 @@ function useStoryIndex(annLength: number | undefined) {
|
||||
const newIndex = (prev + 1) % (annLength || 1)
|
||||
setSearchParams(prev => ({
|
||||
...Object.fromEntries(prev),
|
||||
storyIndex: newIndex.toString()
|
||||
storyIndex: newIndex.toString(),
|
||||
}), { replace: true })
|
||||
|
||||
return newIndex
|
||||
@ -39,7 +39,7 @@ function useStoryIndex(annLength: number | undefined) {
|
||||
const newIndex = prev > 0 ? (prev - 1) : 0
|
||||
setSearchParams(prev => ({
|
||||
...Object.fromEntries(prev),
|
||||
storyIndex: newIndex.toString()
|
||||
storyIndex: newIndex.toString(),
|
||||
}), { replace: true })
|
||||
|
||||
return newIndex
|
||||
@ -49,7 +49,7 @@ function useStoryIndex(annLength: number | undefined) {
|
||||
n: index,
|
||||
withReset,
|
||||
increment,
|
||||
decrement
|
||||
decrement,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,9 @@ function generateStories(announcements: Announcement[], refresh: () => void): St
|
||||
id: announcement.id,
|
||||
url: announcement.src || categoryGraphics[announcement.category],
|
||||
type: announcement.src?.endsWith('mp4') ? 'video' : undefined,
|
||||
seeMore: ({ close }: { close: () => void }) => <AnnouncementDetails close={close} refresh={refresh} announcement={announcement} />
|
||||
seeMore: ({ close }: { close: () => void }) => (
|
||||
<AnnouncementDetails close={close} refresh={refresh} announcement={announcement} />
|
||||
),
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -58,7 +60,7 @@ const styles = {
|
||||
backgroundColor: 'rgb(17, 17, 17)',
|
||||
} as CSSProperties,
|
||||
center: {
|
||||
margin: 'auto'
|
||||
margin: 'auto',
|
||||
} as CSSProperties,
|
||||
}
|
||||
|
||||
|
@ -33,11 +33,11 @@ function clearToken() {
|
||||
}
|
||||
|
||||
type TokenPayload = {
|
||||
user_id: number
|
||||
user_id: number,
|
||||
}
|
||||
|
||||
const isTokenPayload = (data: unknown): data is TokenPayload => isObject(data, {
|
||||
'user_id': 'number'
|
||||
'user_id': 'number',
|
||||
})
|
||||
|
||||
function getId() {
|
||||
|