Even more code styling things
@ -32,5 +32,16 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
'jsx-quotes': [2, 'prefer-single'],
|
'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,
|
lng: data.longtitude,
|
||||||
bestBy: data.best_by,
|
bestBy: data.best_by,
|
||||||
bookedBy: data.booked_by,
|
bookedBy: data.booked_by,
|
||||||
userId: data.user_id
|
userId: data.user_id,
|
||||||
})
|
})
|
||||||
|
|
||||||
export { processAnnouncement }
|
export { processAnnouncement }
|
||||||
|
@ -14,7 +14,7 @@ type AnnouncementResponse = {
|
|||||||
src: string | null,
|
src: string | null,
|
||||||
metro: string,
|
metro: string,
|
||||||
trashId: number | null,
|
trashId: number | null,
|
||||||
booked_by: number
|
booked_by: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
const isAnnouncementResponse = (obj: unknown): obj is AnnouncementResponse => (
|
const isAnnouncementResponse = (obj: unknown): obj is AnnouncementResponse => (
|
||||||
@ -31,7 +31,7 @@ const isAnnouncementResponse = (obj: unknown): obj is AnnouncementResponse => (
|
|||||||
'src': 'string?',
|
'src': 'string?',
|
||||||
'metro': 'string',
|
'metro': 'string',
|
||||||
'trashId': 'number?',
|
'trashId': 'number?',
|
||||||
'booked_by': 'number'
|
'booked_by': 'number',
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ type Announcement = {
|
|||||||
src: string | null,
|
src: string | null,
|
||||||
metro: string,
|
metro: string,
|
||||||
trashId: number | null,
|
trashId: number | null,
|
||||||
bookedBy: number
|
bookedBy: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type {
|
export type {
|
||||||
|
@ -3,13 +3,13 @@ import { AnnouncementResponse, isAnnouncementResponse } from '../announcement/ty
|
|||||||
|
|
||||||
type AnnouncementsResponse = {
|
type AnnouncementsResponse = {
|
||||||
list_of_announcements: AnnouncementResponse[],
|
list_of_announcements: AnnouncementResponse[],
|
||||||
Success: boolean
|
Success: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
const isAnnouncementsResponse = (obj: unknown): obj is AnnouncementsResponse => (
|
const isAnnouncementsResponse = (obj: unknown): obj is AnnouncementsResponse => (
|
||||||
isObject(obj, {
|
isObject(obj, {
|
||||||
'list_of_announcements': obj => isArrayOf<AnnouncementResponse>(obj, isAnnouncementResponse),
|
'list_of_announcements': obj => isArrayOf<AnnouncementResponse>(obj, isAnnouncementResponse),
|
||||||
'Success': 'boolean'
|
'Success': 'boolean',
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { isObject } from '../../utils/types'
|
import { isObject } from '../../utils/types'
|
||||||
|
|
||||||
type BookResponse = {
|
type BookResponse = {
|
||||||
Success: boolean
|
Success: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
const isBookResponse = (obj: unknown): obj is BookResponse => (
|
const isBookResponse = (obj: unknown): obj is BookResponse => (
|
||||||
isObject(obj, {
|
isObject(obj, {
|
||||||
'Success': 'boolean'
|
'Success': 'boolean',
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { isObject } from '../../utils/types'
|
import { isObject } from '../../utils/types'
|
||||||
|
|
||||||
type OsmAddressResponse = {
|
type OsmAddressResponse = {
|
||||||
display_name: string
|
display_name: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
const isOsmAddressResponse = (obj: unknown): obj is OsmAddressResponse => (
|
const isOsmAddressResponse = (obj: unknown): obj is OsmAddressResponse => (
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { isObject } from '../../utils/types'
|
import { isObject } from '../../utils/types'
|
||||||
|
|
||||||
type PutAnnouncementResponse = {
|
type PutAnnouncementResponse = {
|
||||||
Answer: boolean
|
Answer: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
const isPutAnnouncementResponse = (obj: unknown): obj is PutAnnouncementResponse => (
|
const isPutAnnouncementResponse = (obj: unknown): obj is PutAnnouncementResponse => (
|
||||||
isObject(obj, {
|
isObject(obj, {
|
||||||
'Answer': 'boolean'
|
'Answer': 'boolean',
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { isObject } from '../../utils/types'
|
import { isObject } from '../../utils/types'
|
||||||
|
|
||||||
type RemoveAnnouncementResponse = {
|
type RemoveAnnouncementResponse = {
|
||||||
Answer: boolean
|
Answer: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
const isRemoveAnnouncementResponse = (obj: unknown): obj is RemoveAnnouncementResponse => (
|
const isRemoveAnnouncementResponse = (obj: unknown): obj is RemoveAnnouncementResponse => (
|
||||||
isObject(obj, {
|
isObject(obj, {
|
||||||
'Answer': 'boolean'
|
'Answer': 'boolean',
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ type SignUpResponse = {
|
|||||||
Success: true,
|
Success: true,
|
||||||
} | {
|
} | {
|
||||||
Success: false,
|
Success: false,
|
||||||
Message: string
|
Message: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
const isSignUpResponse = (obj: unknown): obj is SignUpResponse => (
|
const isSignUpResponse = (obj: unknown): obj is SignUpResponse => (
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { isObject } from '../../utils/types'
|
import { isObject } from '../../utils/types'
|
||||||
|
|
||||||
type TokenResponse = {
|
type TokenResponse = {
|
||||||
access_token: string
|
access_token: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
const isTokenResponse = (obj: unknown): obj is TokenResponse => (
|
const isTokenResponse = (obj: unknown): obj is TokenResponse => (
|
||||||
isObject(obj, {
|
isObject(obj, {
|
||||||
'access_token': 'string'
|
'access_token': 'string',
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -6,11 +6,12 @@ import { Trashbox, TrashboxResponse } from './types'
|
|||||||
const composeTrashboxURL = (position: LatLng) => (
|
const composeTrashboxURL = (position: LatLng) => (
|
||||||
API_URL + '/trashbox?' + new URLSearchParams({
|
API_URL + '/trashbox?' + new URLSearchParams({
|
||||||
lat: position.lat.toString(),
|
lat: position.lat.toString(),
|
||||||
lng: position.lng.toString()
|
lng: position.lng.toString(),
|
||||||
}).toString()
|
}).toString()
|
||||||
)
|
)
|
||||||
|
|
||||||
const processTrashbox = (data: TrashboxResponse): Trashbox[] =>
|
const processTrashbox = (data: TrashboxResponse): Trashbox[] => (
|
||||||
data
|
data
|
||||||
|
)
|
||||||
|
|
||||||
export { composeTrashboxURL, processTrashbox }
|
export { composeTrashboxURL, processTrashbox }
|
||||||
|
@ -4,7 +4,7 @@ type Trashbox = {
|
|||||||
Lat: number,
|
Lat: number,
|
||||||
Lng: number,
|
Lng: number,
|
||||||
Address: string,
|
Address: string,
|
||||||
Categories: string[]
|
Categories: string[],
|
||||||
}
|
}
|
||||||
|
|
||||||
const isTrashbox = (obj: unknown): obj is Trashbox => (
|
const isTrashbox = (obj: unknown): obj is Trashbox => (
|
||||||
@ -12,7 +12,7 @@ const isTrashbox = (obj: unknown): obj is Trashbox => (
|
|||||||
'Lat': 'number',
|
'Lat': 'number',
|
||||||
'Lng': 'number',
|
'Lng': 'number',
|
||||||
'Address': 'string',
|
'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(),
|
regDate: faker.date.anytime().getTime(),
|
||||||
points: Math.round(Math.random() * 1000),
|
points: Math.round(Math.random() * 1000),
|
||||||
} : {
|
} : {
|
||||||
id: -1,
|
id: 1,
|
||||||
name: '',
|
name: 'Вася пупкин',
|
||||||
regDate: 0,
|
regDate: 0,
|
||||||
points: 0,
|
points: 100,
|
||||||
}
|
}
|
||||||
|
|
||||||
const composeUserURL = () => (
|
const composeUserURL = () => (
|
||||||
|
@ -4,7 +4,7 @@ type User = {
|
|||||||
id: number,
|
id: number,
|
||||||
name: string,
|
name: string,
|
||||||
regDate: number,
|
regDate: number,
|
||||||
points: number
|
points: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
const isUser = (obj: unknown): obj is User => (
|
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([
|
blue: new Set([
|
||||||
'Парнас',
|
'Парнас',
|
||||||
@ -41,7 +41,7 @@ const stations: Record<Lines, Set<string>> = {
|
|||||||
'Парк Победы',
|
'Парк Победы',
|
||||||
'Московская',
|
'Московская',
|
||||||
'Звёздная',
|
'Звёздная',
|
||||||
'Купчино'
|
'Купчино',
|
||||||
]),
|
]),
|
||||||
green: new Set([
|
green: new Set([
|
||||||
'Приморская',
|
'Приморская',
|
||||||
@ -54,7 +54,7 @@ const stations: Record<Lines, Set<string>> = {
|
|||||||
'Ломоносовская',
|
'Ломоносовская',
|
||||||
'Пролетарская',
|
'Пролетарская',
|
||||||
'Обухово',
|
'Обухово',
|
||||||
'Рыбацкое'
|
'Рыбацкое',
|
||||||
]),
|
]),
|
||||||
orange: new Set([
|
orange: new Set([
|
||||||
'Спасская',
|
'Спасская',
|
||||||
@ -64,7 +64,7 @@ const stations: Record<Lines, Set<string>> = {
|
|||||||
'Новочеркасская',
|
'Новочеркасская',
|
||||||
'Ладожская',
|
'Ладожская',
|
||||||
'Проспект Большевиков',
|
'Проспект Большевиков',
|
||||||
'Улица Дыбенко'
|
'Улица Дыбенко',
|
||||||
]),
|
]),
|
||||||
violet: new Set([
|
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: {
|
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) {
|
} }: AnnouncementDetailsProps) {
|
||||||
const { handleBook, bookButton } = useBook()
|
const { handleBook, bookButton } = useBook()
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import { composeSignUpBody } from '../api/signup'
|
|||||||
import { composeSignInBody } from '../api/token'
|
import { composeSignInBody } from '../api/token'
|
||||||
|
|
||||||
type AuthFormProps = {
|
type AuthFormProps = {
|
||||||
register: boolean
|
register: boolean,
|
||||||
goBack: () => void,
|
goBack: () => void,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import { PropsWithChildren } from 'react'
|
|||||||
import BackButton from '../assets/backArrow.svg'
|
import BackButton from '../assets/backArrow.svg'
|
||||||
|
|
||||||
type BackHeaderProps = {
|
type BackHeaderProps = {
|
||||||
text: string
|
text: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
function BackHeader({ text, children }: PropsWithChildren<BackHeaderProps>) {
|
function BackHeader({ text, children }: PropsWithChildren<BackHeaderProps>) {
|
||||||
|
@ -15,22 +15,20 @@ const styles = {
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
margin: 'auto'
|
margin: 'auto',
|
||||||
} as CSSProperties,
|
} as CSSProperties,
|
||||||
navBarElement: {
|
navBarElement: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center'
|
justifyContent: 'center',
|
||||||
} as CSSProperties,
|
} as CSSProperties,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
type BottomNavBarProps = {
|
type BottomNavBarProps = {
|
||||||
width: number,
|
width: number,
|
||||||
toggleFilters: (p: boolean) => void
|
toggleFilters: (state: boolean) => void,
|
||||||
}
|
}
|
||||||
|
|
||||||
function BottomNavBar({ width, toggleFilters }: BottomNavBarProps) {
|
function BottomNavBar({ width, toggleFilters }: BottomNavBarProps) {
|
||||||
@ -38,7 +36,7 @@ function BottomNavBar({ width, toggleFilters }: BottomNavBarProps) {
|
|||||||
<div style={styles.navBar}>
|
<div style={styles.navBar}>
|
||||||
<div style={{ ...styles.navBarGroup, width: width }}>
|
<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='Фильтровать объявления' />
|
<img src={filterIcon} alt='Фильтровать объявления' title='Фильтровать объявления' />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
@ -46,7 +44,7 @@ function BottomNavBar({ width, toggleFilters }: BottomNavBarProps) {
|
|||||||
<img src={addIcon} alt='Опубликовать объявление' title='Опубликовать объявление' />
|
<img src={addIcon} alt='Опубликовать объявление' title='Опубликовать объявление' />
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<Link style={styles.navBarElement} to={'/user'} >
|
<Link style={styles.navBarElement} to='/user' >
|
||||||
<img src={userIcon} alt='Личный кабинет' title='Личный кабинет' />
|
<img src={userIcon} alt='Личный кабинет' title='Личный кабинет' />
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { Card } from 'react-bootstrap'
|
|||||||
import { BackHeader } from '.'
|
import { BackHeader } from '.'
|
||||||
|
|
||||||
type CardLayoutProps = {
|
type CardLayoutProps = {
|
||||||
text: string
|
text: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
const CardLayout = ({ text, children }: PropsWithChildren<CardLayoutProps>) => (
|
const CardLayout = ({ text, children }: PropsWithChildren<CardLayoutProps>) => (
|
||||||
|
@ -4,7 +4,7 @@ import { useAnnouncements } from '../hooks/api'
|
|||||||
import { gotError } from '../hooks/useFetch'
|
import { gotError } from '../hooks/useFetch'
|
||||||
|
|
||||||
type CategoryPreviewProps = {
|
type CategoryPreviewProps = {
|
||||||
category: UserCategory
|
category: UserCategory,
|
||||||
}
|
}
|
||||||
|
|
||||||
function CategoryPreview({ category }: CategoryPreviewProps) {
|
function CategoryPreview({ category }: CategoryPreviewProps) {
|
||||||
|
@ -10,21 +10,21 @@ type FiltersProps = {
|
|||||||
filter: FiltersType,
|
filter: FiltersType,
|
||||||
setFilter: SetState<FiltersType>,
|
setFilter: SetState<FiltersType>,
|
||||||
filterShown: boolean,
|
filterShown: boolean,
|
||||||
setFilterShown: SetState<boolean>
|
setFilterShown: SetState<boolean>,
|
||||||
}
|
}
|
||||||
|
|
||||||
function Filters({ filter, setFilter, filterShown, setFilterShown }: FiltersProps) {
|
function Filters({ filter, setFilter, filterShown, setFilterShown }: FiltersProps) {
|
||||||
|
|
||||||
const handleSubmit: FormEventHandler<HTMLFormElement> = (event) => {
|
const handleSubmit: FormEventHandler<HTMLFormElement> = (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault()
|
||||||
event.stopPropagation();
|
event.stopPropagation()
|
||||||
|
|
||||||
const formData = new FormData(event.currentTarget)
|
const formData = new FormData(event.currentTarget)
|
||||||
|
|
||||||
setFilter(prev => ({
|
setFilter(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
category: (formData.get('category') as (FiltersType['category'] | null)) || undefined,
|
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)
|
setFilterShown(false)
|
||||||
|
@ -3,8 +3,9 @@ import { colors, lineNames, lineByName } from '../assets/metro'
|
|||||||
function LineDot({ station }: { station: string }) {
|
function LineDot({ station }: { station: string }) {
|
||||||
const line = lineByName(station)
|
const line = lineByName(station)
|
||||||
|
|
||||||
if (line == undefined)
|
if (line == undefined) {
|
||||||
return <></>
|
return <></>
|
||||||
|
}
|
||||||
|
|
||||||
const lineTitle = lineNames[line]
|
const lineTitle = lineNames[line]
|
||||||
const color = colors[line]
|
const color = colors[line]
|
||||||
|
@ -7,7 +7,7 @@ import { iconItem } from '../utils/markerIcons'
|
|||||||
type LocationMarkerProps = {
|
type LocationMarkerProps = {
|
||||||
address: string,
|
address: string,
|
||||||
position: LatLng,
|
position: LatLng,
|
||||||
setPosition: SetState<LatLng>
|
setPosition: SetState<LatLng>,
|
||||||
}
|
}
|
||||||
|
|
||||||
function LocationMarker({ address, position, setPosition }: LocationMarkerProps) {
|
function LocationMarker({ address, position, setPosition }: LocationMarkerProps) {
|
||||||
@ -21,7 +21,7 @@ function LocationMarker({ address, position, setPosition }: LocationMarkerProps)
|
|||||||
},
|
},
|
||||||
resize: () => {
|
resize: () => {
|
||||||
setPosition(map.getCenter())
|
setPosition(map.getCenter())
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -3,7 +3,7 @@ import { CSSProperties } from 'react'
|
|||||||
import handStarsIcon from '../assets/handStars.svg'
|
import handStarsIcon from '../assets/handStars.svg'
|
||||||
|
|
||||||
type PointsProps = {
|
type PointsProps = {
|
||||||
points: number
|
points: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
|
@ -9,7 +9,7 @@ import signOutIcon from '../assets/signOut.svg'
|
|||||||
const styles = {
|
const styles = {
|
||||||
rightIcon: {
|
rightIcon: {
|
||||||
marginLeft: '1rem',
|
marginLeft: '1rem',
|
||||||
marginRight: 0
|
marginRight: 0,
|
||||||
} as CSSProperties,
|
} as CSSProperties,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ const styles = {
|
|||||||
} as CSSProperties,
|
} as CSSProperties,
|
||||||
leftScrollButton: {
|
leftScrollButton: {
|
||||||
left: 0,
|
left: 0,
|
||||||
transform: 'scaleX(-1)'
|
transform: 'scaleX(-1)',
|
||||||
} as CSSProperties,
|
} as CSSProperties,
|
||||||
rightScrollButton: {
|
rightScrollButton: {
|
||||||
right: 0,
|
right: 0,
|
||||||
@ -116,7 +116,7 @@ function StoriesPreview({ announcements, category }: StoriesPreviewProps) {
|
|||||||
<li key={`${category}${i}`}>
|
<li key={`${category}${i}`}>
|
||||||
<Link to={'/?' + new URLSearchParams({
|
<Link to={'/?' + new URLSearchParams({
|
||||||
...URLEncodeFilters(composeUserCategoriesFilters[category]()),
|
...URLEncodeFilters(composeUserCategoriesFilters[category]()),
|
||||||
storyIndex: i.toString()
|
storyIndex: i.toString(),
|
||||||
}).toString()} style={styles.link}>
|
}).toString()} style={styles.link}>
|
||||||
{ann.src?.endsWith('mp4') ? (
|
{ann.src?.endsWith('mp4') ? (
|
||||||
<video src={ann.src} style={styles.image} />
|
<video src={ann.src} style={styles.image} />
|
||||||
|
@ -5,7 +5,10 @@ import { iconTrash } from '../utils/markerIcons'
|
|||||||
|
|
||||||
type TrashboxMarkersProps = {
|
type TrashboxMarkersProps = {
|
||||||
trashboxes: Trashbox[],
|
trashboxes: Trashbox[],
|
||||||
selectTrashbox: ({ index, category }: { index: number, category: string }) => void
|
selectTrashbox: ({ index, category }: {
|
||||||
|
index: number,
|
||||||
|
category: string,
|
||||||
|
}) => void,
|
||||||
}
|
}
|
||||||
|
|
||||||
function TrashboxMarkers({ trashboxes, selectTrashbox }: TrashboxMarkersProps) {
|
function TrashboxMarkers({ trashboxes, selectTrashbox }: TrashboxMarkersProps) {
|
||||||
|
@ -16,7 +16,7 @@ function useAddAnnouncement() {
|
|||||||
|
|
||||||
function handleAdd(formData: FormData) {
|
function handleAdd(formData: FormData) {
|
||||||
void doSend({}, {
|
void doSend({}, {
|
||||||
body: formData
|
body: formData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,18 +1,8 @@
|
|||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
|
|
||||||
import { isObject } from '../../utils/types'
|
|
||||||
import { useSendWithButton } from '..'
|
import { useSendWithButton } from '..'
|
||||||
import { composeBookURL, processBook } from '../../api/book'
|
import { composeBookURL, processBook } from '../../api/book'
|
||||||
|
import { isBookResponse } from '../../api/book/types'
|
||||||
type BookResponse = {
|
|
||||||
Success: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
const isBookResponse = (obj: unknown): obj is BookResponse => (
|
|
||||||
isObject(obj, {
|
|
||||||
'Success': 'boolean'
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
function useBook() {
|
function useBook() {
|
||||||
const { doSend, button } = useSendWithButton('Забронировать',
|
const { doSend, button } = useSendWithButton('Забронировать',
|
||||||
@ -22,17 +12,17 @@ function useBook() {
|
|||||||
'POST',
|
'POST',
|
||||||
true,
|
true,
|
||||||
isBookResponse,
|
isBookResponse,
|
||||||
processBook
|
processBook,
|
||||||
)
|
)
|
||||||
|
|
||||||
const handleBook = useCallback((id: number) => {
|
const handleBook = useCallback((id: number) => {
|
||||||
void doSend({}, {
|
void doSend({}, {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
id
|
id,
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json',
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
}, [doSend])
|
}, [doSend])
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ const useOsmAddresses = (addressPosition: LatLng) => (
|
|||||||
false,
|
false,
|
||||||
isOsmAddressResponse,
|
isOsmAddressResponse,
|
||||||
processOsmAddress,
|
processOsmAddress,
|
||||||
''
|
'',
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -13,17 +13,17 @@ const useRemoveAnnouncement = (resolve: () => void) => {
|
|||||||
'DELETE',
|
'DELETE',
|
||||||
true,
|
true,
|
||||||
isRemoveAnnouncementResponse,
|
isRemoveAnnouncementResponse,
|
||||||
processRemoveAnnouncement
|
processRemoveAnnouncement,
|
||||||
)
|
)
|
||||||
|
|
||||||
const doSendWithClose = useCallback(async (id: number) => {
|
const doSendWithClose = useCallback(async (id: number) => {
|
||||||
const res = await doSend({}, {
|
const res = await doSend({}, {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
id
|
id,
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json',
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
|
@ -17,7 +17,7 @@ function useSignIn() {
|
|||||||
|
|
||||||
async function handleSignIn(formData: FormData) {
|
async function handleSignIn(formData: FormData) {
|
||||||
const token = await doSend({}, {
|
const token = await doSend({}, {
|
||||||
body: formData
|
body: formData,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (token !== undefined) {
|
if (token !== undefined) {
|
||||||
|
@ -18,8 +18,8 @@ function useSignUp() {
|
|||||||
const res = await doSend({}, {
|
const res = await doSend({}, {
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json',
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
return res ?? false
|
return res ?? false
|
||||||
|
@ -11,7 +11,7 @@ const useTrashboxes = (position: LatLng) => (
|
|||||||
true,
|
true,
|
||||||
isTrashboxResponse,
|
isTrashboxResponse,
|
||||||
processTrashbox,
|
processTrashbox,
|
||||||
[]
|
[],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ const useUser = (): UseFetchReturn<User> => (
|
|||||||
data: initialUser,
|
data: initialUser,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null,
|
error: null,
|
||||||
refetch: () => { return }
|
refetch: () => { return },
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ type UseFetchSucced<T> = {
|
|||||||
|
|
||||||
type UseFetchErrored = {
|
type UseFetchErrored = {
|
||||||
error: string,
|
error: string,
|
||||||
data: undefined
|
data: undefined,
|
||||||
} & UseFetchShared
|
} & UseFetchShared
|
||||||
|
|
||||||
type UseFetchReturn<T> = UseFetchSucced<T> | UseFetchErrored
|
type UseFetchReturn<T> = UseFetchSucced<T> | UseFetchErrored
|
||||||
@ -35,7 +35,7 @@ function useFetch<R, T extends NonNullable<unknown>>(
|
|||||||
guardResponse: (data: unknown) => data is R,
|
guardResponse: (data: unknown) => data is R,
|
||||||
processResponse: (data: R) => T,
|
processResponse: (data: R) => T,
|
||||||
initialData?: T,
|
initialData?: T,
|
||||||
params?: Omit<RequestInit, 'method'>
|
params?: Omit<RequestInit, 'method'>,
|
||||||
): UseFetchReturn<T> {
|
): UseFetchReturn<T> {
|
||||||
const [data, setData] = useState(initialData)
|
const [data, setData] = useState(initialData)
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ function useFetch<R, T extends NonNullable<unknown>>(
|
|||||||
guardResponse,
|
guardResponse,
|
||||||
processResponse,
|
processResponse,
|
||||||
true,
|
true,
|
||||||
params
|
params,
|
||||||
)
|
)
|
||||||
|
|
||||||
function refetch() {
|
function refetch() {
|
||||||
@ -62,11 +62,11 @@ function useFetch<R, T extends NonNullable<unknown>>(
|
|||||||
return {
|
return {
|
||||||
...(
|
...(
|
||||||
error === null ? ({
|
error === null ? ({
|
||||||
data: data!, error: null
|
data: data!, error: null,
|
||||||
}) : ({ data: undefined, error })
|
}) : ({ data: undefined, error })
|
||||||
),
|
),
|
||||||
loading,
|
loading,
|
||||||
refetch
|
refetch,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ function useFilters(initialFilters: FiltersType = defaultFilters): [FiltersType,
|
|||||||
const appendFiltersSearchParams = (filters: FiltersType, replace = false) => (
|
const appendFiltersSearchParams = (filters: FiltersType, replace = false) => (
|
||||||
setSearchParams(params => ({
|
setSearchParams(params => ({
|
||||||
...Object.fromEntries(params),
|
...Object.fromEntries(params),
|
||||||
...URLEncodeFilters(filters)
|
...URLEncodeFilters(filters),
|
||||||
}), { replace })
|
}), { replace })
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ function useSend<R, T extends NonNullable<unknown>>(
|
|||||||
guardResponse: (data: unknown) => data is R,
|
guardResponse: (data: unknown) => data is R,
|
||||||
processResponse: (data: R) => T,
|
processResponse: (data: R) => T,
|
||||||
startWithLoading = false,
|
startWithLoading = false,
|
||||||
defaultParams?: Omit<RequestInit, 'method'>
|
defaultParams?: Omit<RequestInit, 'method'>,
|
||||||
) {
|
) {
|
||||||
const [loading, setLoading] = useState(startWithLoading)
|
const [loading, setLoading] = useState(startWithLoading)
|
||||||
const [error, setError] = useState<string | null>(null)
|
const [error, setError] = useState<string | null>(null)
|
||||||
@ -36,7 +36,7 @@ function useSend<R, T extends NonNullable<unknown>>(
|
|||||||
|
|
||||||
const headers = new Headers({
|
const headers = new Headers({
|
||||||
...defaultParams?.headers,
|
...defaultParams?.headers,
|
||||||
...params?.headers
|
...params?.headers,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (needAuth) {
|
if (needAuth) {
|
||||||
@ -93,7 +93,7 @@ function useSend<R, T extends NonNullable<unknown>>(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
doSend, loading, error,
|
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,
|
loading: boolean,
|
||||||
error: string | null,
|
error: string | null,
|
||||||
result = initial,
|
result = initial,
|
||||||
singular = true
|
singular = true,
|
||||||
) {
|
) {
|
||||||
const [caption, setCaption] = useState(initial)
|
const [caption, setCaption] = useState(initial)
|
||||||
const [disabled, setDisabled] = useState(false)
|
const [disabled, setDisabled] = useState(false)
|
||||||
|
@ -3,7 +3,7 @@ import { useState, useEffect } from 'react';
|
|||||||
const getWindowDimensions = () => (
|
const getWindowDimensions = () => (
|
||||||
{
|
{
|
||||||
width: window.innerWidth,
|
width: window.innerWidth,
|
||||||
height: window.innerHeight
|
height: window.innerHeight,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -12,11 +12,11 @@ function useStoryDimensions(maxRatio = 16 / 9) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function handleResize() {
|
function handleResize() {
|
||||||
setWindowDimensions(getWindowDimensions());
|
setWindowDimensions(getWindowDimensions())
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('resize', handleResize);
|
window.addEventListener('resize', handleResize);
|
||||||
return () => window.removeEventListener('resize', handleResize);
|
return () => window.removeEventListener('resize', handleResize)
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const bottomBarHeight = 56
|
const bottomBarHeight = 56
|
||||||
@ -27,7 +27,7 @@ function useStoryDimensions(maxRatio = 16 / 9) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
height: height,
|
height: height,
|
||||||
width: Math.round(height / ratio)
|
width: Math.round(height / ratio),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ function useStoryIndex(annLength: number | undefined) {
|
|||||||
setIndex(0)
|
setIndex(0)
|
||||||
setSearchParams(prev => ({
|
setSearchParams(prev => ({
|
||||||
...Object.fromEntries(prev),
|
...Object.fromEntries(prev),
|
||||||
storyIndex: '0'
|
storyIndex: '0',
|
||||||
}), { replace: true })
|
}), { replace: true })
|
||||||
f(...args)
|
f(...args)
|
||||||
}
|
}
|
||||||
@ -29,7 +29,7 @@ function useStoryIndex(annLength: number | undefined) {
|
|||||||
const newIndex = (prev + 1) % (annLength || 1)
|
const newIndex = (prev + 1) % (annLength || 1)
|
||||||
setSearchParams(prev => ({
|
setSearchParams(prev => ({
|
||||||
...Object.fromEntries(prev),
|
...Object.fromEntries(prev),
|
||||||
storyIndex: newIndex.toString()
|
storyIndex: newIndex.toString(),
|
||||||
}), { replace: true })
|
}), { replace: true })
|
||||||
|
|
||||||
return newIndex
|
return newIndex
|
||||||
@ -39,7 +39,7 @@ function useStoryIndex(annLength: number | undefined) {
|
|||||||
const newIndex = prev > 0 ? (prev - 1) : 0
|
const newIndex = prev > 0 ? (prev - 1) : 0
|
||||||
setSearchParams(prev => ({
|
setSearchParams(prev => ({
|
||||||
...Object.fromEntries(prev),
|
...Object.fromEntries(prev),
|
||||||
storyIndex: newIndex.toString()
|
storyIndex: newIndex.toString(),
|
||||||
}), { replace: true })
|
}), { replace: true })
|
||||||
|
|
||||||
return newIndex
|
return newIndex
|
||||||
@ -49,7 +49,7 @@ function useStoryIndex(annLength: number | undefined) {
|
|||||||
n: index,
|
n: index,
|
||||||
withReset,
|
withReset,
|
||||||
increment,
|
increment,
|
||||||
decrement
|
decrement,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,9 @@ function generateStories(announcements: Announcement[], refresh: () => void): St
|
|||||||
id: announcement.id,
|
id: announcement.id,
|
||||||
url: announcement.src || categoryGraphics[announcement.category],
|
url: announcement.src || categoryGraphics[announcement.category],
|
||||||
type: announcement.src?.endsWith('mp4') ? 'video' : undefined,
|
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)',
|
backgroundColor: 'rgb(17, 17, 17)',
|
||||||
} as CSSProperties,
|
} as CSSProperties,
|
||||||
center: {
|
center: {
|
||||||
margin: 'auto'
|
margin: 'auto',
|
||||||
} as CSSProperties,
|
} as CSSProperties,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,11 +33,11 @@ function clearToken() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TokenPayload = {
|
type TokenPayload = {
|
||||||
user_id: number
|
user_id: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
const isTokenPayload = (data: unknown): data is TokenPayload => isObject(data, {
|
const isTokenPayload = (data: unknown): data is TokenPayload => isObject(data, {
|
||||||
'user_id': 'number'
|
'user_id': 'number',
|
||||||
})
|
})
|
||||||
|
|
||||||
function getId() {
|
function getId() {
|
||||||
|