feat: add api provider
This commit is contained in:
parent
9bfd15819e
commit
3e9cb7f233
24
src/api/ApiContext.ts
Normal file
24
src/api/ApiContext.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { createContext } from 'react'
|
||||
import { createMethod } from './utils'
|
||||
import {
|
||||
User,
|
||||
Auras,
|
||||
Elements,
|
||||
AuthTokens,
|
||||
Assets,
|
||||
AssetCategories,
|
||||
DailyForecasts,
|
||||
} from './resources'
|
||||
|
||||
export interface ApiContextValue {
|
||||
auth: ReturnType<typeof createMethod<AuthTokens.Payload, AuthTokens.Response>>
|
||||
getElements: ReturnType<typeof createMethod<Elements.Payload, Elements.Response>>
|
||||
getUser: ReturnType<typeof createMethod<User.GetPayload, User.Response>>
|
||||
updateUser: ReturnType<typeof createMethod<User.PatchPayload, User.Response>>
|
||||
getAssets: ReturnType<typeof createMethod<Assets.Payload, Assets.Response>>
|
||||
getAssetCategories: ReturnType<typeof createMethod<AssetCategories.Payload, AssetCategories.Response>>
|
||||
getDailyForecasts: ReturnType<typeof createMethod<DailyForecasts.Payload, DailyForecasts.Response>>
|
||||
getAuras: ReturnType<typeof createMethod<Auras.Payload, Auras.Response>>
|
||||
}
|
||||
|
||||
export const ApiContext = createContext<ApiContextValue>({} as ApiContextValue)
|
||||
24
src/api/api.ts
Normal file
24
src/api/api.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { ApiContextValue } from './ApiContext'
|
||||
import { createMethod } from './utils'
|
||||
import {
|
||||
User,
|
||||
Auras,
|
||||
Elements,
|
||||
AuthTokens,
|
||||
Assets,
|
||||
AssetCategories,
|
||||
DailyForecasts,
|
||||
} from './resources'
|
||||
|
||||
export function createApi(): ApiContextValue {
|
||||
return {
|
||||
auth: createMethod<AuthTokens.Payload, AuthTokens.Response>(AuthTokens.createRequest),
|
||||
getElements: createMethod<Elements.Payload, Elements.Response>(Elements.createRequest),
|
||||
getUser: createMethod<User.GetPayload, User.Response>(User.createGetRequest),
|
||||
updateUser: createMethod<User.PatchPayload, User.Response>(User.createPatchRequest),
|
||||
getAssets: createMethod<Assets.Payload, Assets.Response>(Assets.createRequest),
|
||||
getAssetCategories: createMethod<AssetCategories.Payload, AssetCategories.Response>(AssetCategories.createRequest),
|
||||
getDailyForecasts: createMethod<DailyForecasts.Payload, DailyForecasts.Response>(DailyForecasts.createRequest),
|
||||
getAuras: createMethod<Auras.Payload, Auras.Response>(Auras.createRequest),
|
||||
}
|
||||
}
|
||||
6
src/api/index.ts
Normal file
6
src/api/index.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export * from './useApi'
|
||||
export * from './ApiContext'
|
||||
export * from './api'
|
||||
export * from './types'
|
||||
export type { User } from './resources/User'
|
||||
export type { Payload as SignUpPayload } from './resources/AuthTokens'
|
||||
28
src/api/resources/AssetCategories.ts
Normal file
28
src/api/resources/AssetCategories.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import routes from "../../routes"
|
||||
import { AuthToken } from "../types"
|
||||
import { getAuthHeaders } from "../utils"
|
||||
|
||||
export interface Payload {
|
||||
locale: string
|
||||
token: AuthToken
|
||||
}
|
||||
|
||||
export interface Response {
|
||||
asset_categories: AssetCategory[]
|
||||
}
|
||||
|
||||
export interface AssetCategory {
|
||||
id: number
|
||||
name: string
|
||||
slug: string
|
||||
path: string
|
||||
}
|
||||
|
||||
export const createRequest = ({ locale, token }: Payload): Request => {
|
||||
const url = new URL(routes.server.assetCategories())
|
||||
const query = new URLSearchParams({ locale })
|
||||
|
||||
url.search = query.toString()
|
||||
|
||||
return new Request(url, { method: 'GET', headers: getAuthHeaders(token) })
|
||||
}
|
||||
50
src/api/resources/Assets.ts
Normal file
50
src/api/resources/Assets.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import routes from "../../routes"
|
||||
import { AuthToken } from "../types"
|
||||
import { AssetCategory } from "./AssetCategories"
|
||||
import { getAuthHeaders } from "../utils"
|
||||
|
||||
export interface Payload {
|
||||
token: AuthToken
|
||||
category: string
|
||||
page?: number
|
||||
perPage?: number
|
||||
}
|
||||
|
||||
export interface Response {
|
||||
asset_category: AssetCategory
|
||||
assets: Asset[]
|
||||
}
|
||||
|
||||
export interface Asset {
|
||||
id: string
|
||||
url: string
|
||||
asset_data: AssetData
|
||||
}
|
||||
|
||||
export interface AssetData {
|
||||
id: string
|
||||
storage: string
|
||||
metadata: AssetMetadata
|
||||
}
|
||||
|
||||
export interface AssetMetadata {
|
||||
size: number
|
||||
width: number
|
||||
height: number
|
||||
filename: string
|
||||
mime_type: string
|
||||
}
|
||||
|
||||
export const createRequest = ({ token, category, page, perPage }: Payload): Request => {
|
||||
const url = new URL(routes.server.assets(category))
|
||||
const query = new URLSearchParams()
|
||||
|
||||
if (page && perPage) {
|
||||
query.append('page', page.toString())
|
||||
query.append('per_page', perPage.toString())
|
||||
}
|
||||
|
||||
url.search = query.toString()
|
||||
|
||||
return new Request(url, { method: 'GET', headers: getAuthHeaders(token) })
|
||||
}
|
||||
54
src/api/resources/Auras.ts
Normal file
54
src/api/resources/Auras.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import routes from "../../routes"
|
||||
import { AuthToken } from "../types"
|
||||
import { getAuthHeaders } from "../utils"
|
||||
|
||||
export interface Payload {
|
||||
token: AuthToken
|
||||
}
|
||||
|
||||
export interface Response {
|
||||
user_aura: UserAura
|
||||
}
|
||||
|
||||
export interface UserAura {
|
||||
updated_at: string
|
||||
viewed_at: string | null
|
||||
aurapic: string | null
|
||||
stats: UserAuraStat[]
|
||||
config: UserAuraConfig
|
||||
}
|
||||
|
||||
export interface UserAuraStat {
|
||||
stat: string
|
||||
value: number
|
||||
label: string
|
||||
}
|
||||
|
||||
export interface UserAuraConfig {
|
||||
birthRate: number
|
||||
imageURL: string
|
||||
particleIntensity: number
|
||||
particleIntensityVariation: number
|
||||
particleLifeSpan: number
|
||||
particleSize: number
|
||||
particleSizeVariation: number
|
||||
particleVelocity: number
|
||||
speedFactor: number
|
||||
spreadingAngle: number
|
||||
stretchFactor: number
|
||||
holes: [{
|
||||
from: number
|
||||
to: number
|
||||
}]
|
||||
animations: {
|
||||
[key: string]: {
|
||||
keyTimes: number[]
|
||||
values: number[]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const createRequest = ({ token }: Payload): Request => {
|
||||
const url = new URL(routes.server.auras())
|
||||
return new Request(url, { method: 'GET', headers: getAuthHeaders(token) })
|
||||
}
|
||||
37
src/api/resources/AuthTokens.ts
Normal file
37
src/api/resources/AuthTokens.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import routes from "../../routes"
|
||||
import { AuthToken } from "../types"
|
||||
import { User } from "./User"
|
||||
import { getBaseHeaders } from "../utils"
|
||||
|
||||
export interface Payload {
|
||||
email: string
|
||||
timezone: string
|
||||
locale: string
|
||||
}
|
||||
|
||||
export interface Response {
|
||||
auth: {
|
||||
token: AuthToken
|
||||
payload: JwtPayload
|
||||
user: User
|
||||
}
|
||||
}
|
||||
|
||||
export interface JwtPayload {
|
||||
sub: number
|
||||
email: string
|
||||
loc: string
|
||||
tz: number
|
||||
state: string
|
||||
iat: number
|
||||
exp: number
|
||||
jti: string
|
||||
type: string
|
||||
iss: string
|
||||
}
|
||||
|
||||
export const createRequest = ({ locale, timezone, email }: Payload): Request => {
|
||||
const url = new URL(routes.server.token())
|
||||
const body = JSON.stringify({ auth: { locale, timezone, email }})
|
||||
return new Request(url, { method: 'POST', headers: getBaseHeaders(), body })
|
||||
}
|
||||
35
src/api/resources/Elements.ts
Normal file
35
src/api/resources/Elements.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import routes from "../../routes"
|
||||
import { getBaseHeaders } from "../utils"
|
||||
|
||||
export interface Payload {
|
||||
locale: string
|
||||
}
|
||||
|
||||
export interface Response {
|
||||
data: {
|
||||
variant: string
|
||||
groups: ElementGroup[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface ElementGroup {
|
||||
name: string
|
||||
items: ElementGroupItem[]
|
||||
}
|
||||
|
||||
export interface ElementGroupItem {
|
||||
type: string
|
||||
href: string
|
||||
title: string
|
||||
url_slug: string
|
||||
[key: string]: string
|
||||
}
|
||||
|
||||
export const createRequest = ({ locale }: Payload): Request => {
|
||||
const url = new URL(routes.server.elements())
|
||||
const query = new URLSearchParams({ locale })
|
||||
|
||||
url.search = query.toString()
|
||||
|
||||
return new Request(url, { method: 'GET', headers: getBaseHeaders() })
|
||||
}
|
||||
123
src/api/resources/User.ts
Normal file
123
src/api/resources/User.ts
Normal file
@ -0,0 +1,123 @@
|
||||
import routes from "../../routes"
|
||||
import { AuthToken } from "../types"
|
||||
import { getAuthHeaders } from "../utils"
|
||||
|
||||
export interface GetPayload {
|
||||
token: AuthToken
|
||||
}
|
||||
|
||||
export interface PatchPayload extends GetPayload {
|
||||
user: Partial<UserPatch>
|
||||
}
|
||||
|
||||
export interface Response {
|
||||
user: User
|
||||
meta?: {
|
||||
links: {
|
||||
self: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface UserPatch {
|
||||
locale: string
|
||||
timezone: string
|
||||
profile_attributes: Partial<Pick<UserProfile, 'gender' | 'full_name' | 'relationship_status' | 'birthday'> & {
|
||||
birthplace_id: null
|
||||
birthplace_attributes: {
|
||||
address?: string
|
||||
coords?: string
|
||||
},
|
||||
remote_userpic_url: string
|
||||
}>
|
||||
daily_push_subs_attributes: [{
|
||||
time: string
|
||||
daily_push_id: string
|
||||
}]
|
||||
}
|
||||
|
||||
export interface User {
|
||||
id: string | null | undefined
|
||||
username: string | null
|
||||
email: string
|
||||
locale: string
|
||||
state: string
|
||||
timezone: string
|
||||
new_registration: boolean
|
||||
stat: {
|
||||
last_online_at: string | null
|
||||
prev_online_at: string | null
|
||||
}
|
||||
profile: UserProfile
|
||||
daily_push_subs: Subscription[]
|
||||
}
|
||||
|
||||
export interface UserProfile {
|
||||
full_name: string | null
|
||||
gender: string | null
|
||||
birthday: string | null
|
||||
birthplace: UserBirhplace | null
|
||||
age: UserAge | null
|
||||
sign: UserSign | null
|
||||
userpic: UserPic | null
|
||||
userpic_mime_type: string | undefined
|
||||
relationship_status: string
|
||||
human_relationship_status: string
|
||||
}
|
||||
|
||||
export interface UserAge {
|
||||
years: number
|
||||
days: number
|
||||
}
|
||||
|
||||
export interface UserSign {
|
||||
house: number
|
||||
ruler: string
|
||||
dates: {
|
||||
start: {
|
||||
month: number
|
||||
day: number
|
||||
}
|
||||
end: {
|
||||
month: number
|
||||
day: number
|
||||
}
|
||||
}
|
||||
sign: string
|
||||
char: string
|
||||
polarity: string
|
||||
modality: string
|
||||
triplicity: string
|
||||
}
|
||||
|
||||
export interface UserPic {
|
||||
th: string
|
||||
th2x: string
|
||||
lg: string
|
||||
}
|
||||
|
||||
export interface UserBirhplace {
|
||||
id: string
|
||||
address: string
|
||||
coords: string
|
||||
}
|
||||
|
||||
export interface Subscription {
|
||||
id: string
|
||||
daily_push_id: string
|
||||
time: string
|
||||
updated_at: string
|
||||
created_at: string
|
||||
last_sent_at: string | null
|
||||
}
|
||||
|
||||
export const createGetRequest = ({ token }: GetPayload): Request => {
|
||||
const url = new URL(routes.server.user())
|
||||
return new Request(url, { method: 'GET', headers: getAuthHeaders(token) })
|
||||
}
|
||||
|
||||
export const createPatchRequest = ({ token, user }: PatchPayload): Request => {
|
||||
const url = new URL(routes.server.user())
|
||||
const body = JSON.stringify({ user })
|
||||
return new Request(url, { method: 'PATCH', headers: getAuthHeaders(token), body })
|
||||
}
|
||||
30
src/api/resources/UserDailyForecasts.ts
Normal file
30
src/api/resources/UserDailyForecasts.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import routes from "../../routes"
|
||||
import { AuthToken } from "../types"
|
||||
import { getAuthHeaders } from "../utils"
|
||||
|
||||
export interface Payload {
|
||||
token: AuthToken
|
||||
}
|
||||
|
||||
export interface Response {
|
||||
user_daily_forecast: UserDailyForecast
|
||||
}
|
||||
|
||||
export interface UserDailyForecast {
|
||||
day: string
|
||||
updated_at: string
|
||||
viewed_at: string | null
|
||||
sign_id: number
|
||||
forecasts: Forecast[]
|
||||
}
|
||||
|
||||
export interface Forecast {
|
||||
category_name: string
|
||||
category: string
|
||||
body: string
|
||||
}
|
||||
|
||||
export const createRequest = ({ token }: Payload): Request => {
|
||||
const url = new URL(routes.server.dailyForecasts())
|
||||
return new Request(url, { method: 'GET', headers: getAuthHeaders(token) })
|
||||
}
|
||||
7
src/api/resources/index.ts
Normal file
7
src/api/resources/index.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export * as Assets from './Assets'
|
||||
export * as AssetCategories from './AssetCategories'
|
||||
export * as User from './User'
|
||||
export * as DailyForecasts from './UserDailyForecasts'
|
||||
export * as Auras from './Auras'
|
||||
export * as Elements from './Elements'
|
||||
export * as AuthTokens from './AuthTokens'
|
||||
18
src/api/types.ts
Normal file
18
src/api/types.ts
Normal file
@ -0,0 +1,18 @@
|
||||
export interface AuthError {
|
||||
title: string
|
||||
detail: string
|
||||
source: {
|
||||
pointer: string
|
||||
parameter: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface ApiError {
|
||||
base: string[]
|
||||
}
|
||||
|
||||
export interface ErrorResponse {
|
||||
errors: AuthError[] | ApiError
|
||||
}
|
||||
|
||||
export type AuthToken = string
|
||||
4
src/api/useApi.ts
Normal file
4
src/api/useApi.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { useContext } from 'react'
|
||||
import { ApiContext } from './ApiContext'
|
||||
|
||||
export const useApi = () => useContext(ApiContext)
|
||||
28
src/api/utils.ts
Normal file
28
src/api/utils.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { AuthToken } from "./types"
|
||||
import { ErrorResponse } from "./types"
|
||||
|
||||
export function createMethod<P, R>(createRequest: (payload: P) => Request) {
|
||||
return async (payload: P): Promise<R> => {
|
||||
const request = createRequest(payload)
|
||||
const response = await fetch(request)
|
||||
const data: R & ErrorResponse = await response.json()
|
||||
|
||||
if (response.ok) return data
|
||||
|
||||
const error = Array.isArray(data.errors) ? data.errors[0]?.title : data.errors.base[0]
|
||||
|
||||
throw new Error(error)
|
||||
}
|
||||
}
|
||||
|
||||
export function getBaseHeaders(): Headers {
|
||||
return new Headers({
|
||||
'Content-Type': 'application/json',
|
||||
})
|
||||
}
|
||||
|
||||
export function getAuthHeaders(token: AuthToken): Headers {
|
||||
const headers = getBaseHeaders()
|
||||
headers.append('Authorization', `Bearer ${token}`)
|
||||
return headers
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
import { createContext } from 'react'
|
||||
import { AuthToken, User } from '../types'
|
||||
import { AuthToken, User, SignUpPayload } from '../api'
|
||||
|
||||
export interface AuthContextValue {
|
||||
user: User | null
|
||||
@ -9,18 +9,4 @@ export interface AuthContextValue {
|
||||
addBirthday: (birthday: string, token: AuthToken) => Promise<void>
|
||||
}
|
||||
|
||||
export interface SignUpPayload {
|
||||
email: string
|
||||
timezone: string
|
||||
locale: string
|
||||
}
|
||||
|
||||
const initialContext: AuthContextValue = {
|
||||
token: '',
|
||||
user: null,
|
||||
logout: () => undefined,
|
||||
signUp: () => Promise.resolve(''),
|
||||
addBirthday: () => Promise.resolve(),
|
||||
}
|
||||
|
||||
export const AuthContext = createContext<AuthContextValue>(initialContext)
|
||||
export const AuthContext = createContext<AuthContextValue>({} as AuthContextValue)
|
||||
|
||||
@ -1,57 +1,23 @@
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { AuthContext, SignUpPayload } from './AuthContext'
|
||||
import { RootState, actions } from '../store'
|
||||
import { AuthToken } from '../types'
|
||||
import routes from '../routes'
|
||||
import { useApi, AuthToken, SignUpPayload } from '../api'
|
||||
import { AuthContext } from './AuthContext'
|
||||
|
||||
export function AuthProvider({ children }: React.PropsWithChildren<unknown>): JSX.Element {
|
||||
const api = useApi()
|
||||
const dispatch = useDispatch()
|
||||
const token = useSelector((state: RootState) => state.token)
|
||||
const user = useSelector((state: RootState) => state.user)
|
||||
const signUp = async ({ email, timezone, locale }: SignUpPayload): Promise<AuthToken> => {
|
||||
const response = await fetch(routes.server.token(), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ auth: { email, timezone, locale } })
|
||||
})
|
||||
if (response.ok) {
|
||||
const { auth: { token, user } } = await response.json()
|
||||
const signUp = async (payload: SignUpPayload): Promise<AuthToken> => {
|
||||
const { auth: { token, user } } = await api.auth(payload)
|
||||
dispatch(actions.token.update(token))
|
||||
dispatch(actions.user.update(user))
|
||||
return token
|
||||
} else {
|
||||
const { errors } = await response.json()
|
||||
if (Array.isArray(errors)) {
|
||||
const [error] = errors
|
||||
throw new Error(error.title)
|
||||
} else {
|
||||
const { base: [error] } = errors
|
||||
throw new Error(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
const addBirthday = async (birthday: string, token: AuthToken): Promise<void> => {
|
||||
const response = await fetch(routes.server.user(), {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${token}`,
|
||||
},
|
||||
body: JSON.stringify({ user: { profile_attributes: { birthday } } })
|
||||
})
|
||||
if (response.ok) {
|
||||
const { user } = await response.json()
|
||||
const payload = { user: { profile_attributes: { birthday } }, token }
|
||||
const { user } = await api.updateUser(payload)
|
||||
dispatch(actions.user.update(user))
|
||||
} else {
|
||||
const { errors } = await response.json()
|
||||
if (Array.isArray(errors)) {
|
||||
const [error] = errors
|
||||
throw new Error(error.title)
|
||||
} else {
|
||||
const { base: [error] } = errors
|
||||
throw new Error(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
const logout = () => dispatch(actions.reset())
|
||||
const auth = { signUp, logout, addBirthday, token, user: user.id ? user : null }
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
import './styles.css'
|
||||
|
||||
type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement>;
|
||||
type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
|
||||
color?: 'black' | 'blue'
|
||||
};
|
||||
|
||||
|
||||
function MainButton({ className, children, ...props}: ButtonProps): JSX.Element {
|
||||
const combinedClassNames = ['main-btn', className].filter(Boolean).join(' ')
|
||||
function MainButton({ className, children, color, ...props}: ButtonProps): JSX.Element {
|
||||
const colorClass = color ? `main-btn--${color}` : 'main-btn--black'
|
||||
const combinedClassNames = ['main-btn', colorClass, className].filter(Boolean).join(' ')
|
||||
return <button className={combinedClassNames} {...props}>{children}</button>
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
.main-btn {
|
||||
align-items: center;
|
||||
background: #000;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
font-size: 18px;
|
||||
@ -22,3 +20,13 @@
|
||||
.main-btn:disabled {
|
||||
opacity: 50%;
|
||||
}
|
||||
|
||||
.main-btn--black {
|
||||
background: #000;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.main-btn--blue {
|
||||
background: #306ed7;
|
||||
color: #fff;
|
||||
}
|
||||
16
src/init.tsx
16
src/init.tsx
@ -1,30 +1,30 @@
|
||||
import React from 'react'
|
||||
import { BrowserRouter } from 'react-router-dom'
|
||||
import i18next from 'i18next'
|
||||
import { BrowserRouter } from 'react-router-dom'
|
||||
import { I18nextProvider, initReactI18next } from 'react-i18next'
|
||||
import { Provider } from 'react-redux'
|
||||
import { store } from './store'
|
||||
import resources from './locales'
|
||||
import routes from './routes'
|
||||
import { AuthProvider } from './auth'
|
||||
import { ApiContext, createApi } from './api'
|
||||
import resources, { getClientLocale } from './locales'
|
||||
import App from './components/App'
|
||||
|
||||
const init = async () => {
|
||||
const response = await fetch(routes.server.translations())
|
||||
const data = await response.json()
|
||||
const defaultLanguage = data.meta.locale
|
||||
// TODO: add translations from data.translations
|
||||
const api = createApi()
|
||||
const lng = getClientLocale()
|
||||
const i18nextInstance = i18next.createInstance()
|
||||
const options = { lng: defaultLanguage, resources }
|
||||
const options = { lng, resources }
|
||||
await i18nextInstance.use(initReactI18next).init(options)
|
||||
return (
|
||||
<React.StrictMode>
|
||||
<I18nextProvider i18n={i18nextInstance}>
|
||||
<Provider store={store}>
|
||||
<BrowserRouter>
|
||||
<ApiContext.Provider value={api}>
|
||||
<AuthProvider>
|
||||
<App />
|
||||
</AuthProvider>
|
||||
</ApiContext.Provider>
|
||||
</BrowserRouter>
|
||||
</Provider>
|
||||
</I18nextProvider>
|
||||
|
||||
@ -10,13 +10,17 @@ const routes = {
|
||||
emailEnter: () => [host, 'email'].join('/'),
|
||||
subscription: () => [host, 'subscription'].join('/'),
|
||||
createProfile: () => [host, 'profile', 'create'].join('/'),
|
||||
paymentMethod: () => [host, 'payment', 'method'].join('/'),
|
||||
wallpaper: () => [host, 'wallpaper'].join('/'),
|
||||
},
|
||||
server: {
|
||||
locales: () => [apiHost, prefix, 'locales.json'].join('/'),
|
||||
translations: () => [apiHost, prefix, 't.json'].join('/'),
|
||||
elements: () => [apiHost, prefix, 'elements.json'].join('/'),
|
||||
user: () => [apiHost, prefix, 'user.json'].join('/'),
|
||||
token: () => [apiHost, prefix, 'auth', 'token.json'].join('/'),
|
||||
assets: (category: string) => [apiHost, prefix, 'assets', 'categories', `${category}.json`].join('/'),
|
||||
assetCategories: () => [apiHost, prefix, 'assets', 'categories.json'].join('/'),
|
||||
dailyForecasts: () => [apiHost, prefix, 'user', 'daily_forecasts.json'].join('/'),
|
||||
auras: () => [apiHost, prefix, 'user', 'aura.json'].join('/'),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { createSlice } from '@reduxjs/toolkit'
|
||||
import type { PayloadAction } from '@reduxjs/toolkit'
|
||||
import type { AuthToken } from '../types'
|
||||
import type { AuthToken } from '../api'
|
||||
|
||||
const initialState: AuthToken = ''
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { createSlice } from '@reduxjs/toolkit'
|
||||
import type { PayloadAction } from '@reduxjs/toolkit'
|
||||
import type { User } from '../types'
|
||||
import type { User } from '../api'
|
||||
import { getClientLocale, getClientTimezone } from '../locales'
|
||||
|
||||
const initialState: User = {
|
||||
|
||||
77
src/types.ts
77
src/types.ts
@ -12,80 +12,3 @@ export interface SignupForm {
|
||||
birthdate: string
|
||||
birthtime: string
|
||||
}
|
||||
|
||||
export type AuthToken = string
|
||||
|
||||
export interface User {
|
||||
id: string | null | undefined
|
||||
username: string | null
|
||||
email: string
|
||||
locale: string
|
||||
state: string
|
||||
timezone: string
|
||||
new_registration: boolean
|
||||
stat: {
|
||||
last_online_at: string | null
|
||||
prev_online_at: string | null
|
||||
}
|
||||
profile: UserProfile
|
||||
daily_push_subs: Subscription[]
|
||||
}
|
||||
|
||||
export interface UserProfile {
|
||||
full_name: string | null
|
||||
gender: string | null
|
||||
birthday: string | null
|
||||
birthplace: UserBirhplace | null
|
||||
age: UserAge | null
|
||||
sign: UserSign | null
|
||||
userpic: UserPic | null
|
||||
userpic_mime_type: string | undefined
|
||||
relationship_status: string
|
||||
human_relationship_status: string
|
||||
}
|
||||
|
||||
export interface UserAge {
|
||||
years: number
|
||||
days: number
|
||||
}
|
||||
|
||||
export interface UserSign {
|
||||
house: number
|
||||
ruler: string
|
||||
dates: {
|
||||
start: {
|
||||
month: number
|
||||
day: number
|
||||
}
|
||||
end: {
|
||||
month: number
|
||||
day: number
|
||||
}
|
||||
}
|
||||
sign: string
|
||||
char: string
|
||||
polarity: string
|
||||
modality: string
|
||||
triplicity: string
|
||||
}
|
||||
|
||||
export interface UserPic {
|
||||
th: string
|
||||
th2x: string
|
||||
lg: string
|
||||
}
|
||||
|
||||
export interface UserBirhplace {
|
||||
id: string
|
||||
address: string
|
||||
coords: string
|
||||
}
|
||||
|
||||
export interface Subscription {
|
||||
id: string
|
||||
daily_push_id: string
|
||||
time: string
|
||||
updated_at: string
|
||||
created_at: string
|
||||
last_sent_at: string | null
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user