This commit is contained in:
2024-09-20 17:18:18 +02:00
parent 6a65074c16
commit cd3d836c20
10 changed files with 574 additions and 37 deletions

View File

@@ -0,0 +1,102 @@
// Need to use the React-specific entry point to import createApi
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
import {
GetAllPostsArgs,
GetAllPostsResponse,
LoginArgs,
LoginResponse,
MeResponse,
UploadFileResponse,
UserPosts,
UserProfile,
} from '@/services/instagram.types'
// Define a service using a base URL and expected endpoints
export const instagramApi = createApi({
tagTypes: ['Posts'],
reducerPath: 'instagramApi',
baseQuery: fetchBaseQuery({
baseUrl: 'https://inctagram.work/api/',
prepareHeaders: (headers) => {
const token = localStorage.getItem('access_token')
if (token) {
headers.set('Authorization', `Bearer ${token}`)
}
return headers
},
}),
endpoints: (builder) => ({
getAllPublicPosts: builder.query<
GetAllPostsResponse,
GetAllPostsArgs | void
>({
query: (arg) => {
const { endCursorPostId, ...params } = arg ?? {}
return { url: `/v1/public-posts/all/${endCursorPostId}`, params }
},
}),
login: builder.mutation<LoginResponse, LoginArgs>({
query: (args) => ({ url: 'v1/auth/login', body: args, method: 'POST' }),
}),
me: builder.query<MeResponse, void>({
query: () => ({
url: '/v1/auth/me',
}),
}),
getUserProfile: builder.query<UserProfile, { id: number }>({
query: ({ id }) => ({
url: `/v1/public-user/profile/${id}`,
}),
}),
getUserPosts: builder.query<UserPosts, { id: number }>({
providesTags: ['Posts'],
query: ({ id }) => ({
url: `/v1/public-posts/user/${id}`,
}),
}),
uploadFileForPost: builder.mutation<UploadFileResponse, { file: File }>({
query: ({ file }) => {
const formData = new FormData()
formData.append('file', file)
return {
url: '/v1/posts/image',
body: formData,
method: 'POST',
}
},
}),
createPost: builder.mutation<
any,
{ description: string; uploadIds: string[] }
>({
invalidatesTags: ['Posts'],
query: ({ description, uploadIds }) => {
return {
url: '/v1/posts',
body: {
description,
childrenMetadata: uploadIds.map((id) => {
return {
uploadId: id,
}
}),
},
method: 'POST',
}
},
}),
}),
})
// Export hooks for usage in functional components, which are
// auto-generated based on the defined endpoints
export const {
useGetAllPublicPostsQuery,
useLoginMutation,
useMeQuery,
useGetUserProfileQuery,
useGetUserPostsQuery,
useUploadFileForPostMutation,
useCreatePostMutation,
} = instagramApi

View File

@@ -0,0 +1,91 @@
export interface UserProfile {
id: number
userName: string
firstName: string
lastName: string
city: string
country: string
region: string
dateOfBirth: string
aboutMe: string
avatars: Avatar[]
createdAt: string
}
export interface Avatar {
url: string
width: number
height: number
fileSize: number
createdAt: string
}
export interface MeResponse {
userId: number
userName: string
email: string
isBlocked: boolean
}
export interface LoginArgs {
email: string
password: string
}
export interface LoginResponse {
accessToken: string
}
export interface GetAllPostsArgs {
pageSize?: number
sortBy?: string
sortDirection?: 'asc' | 'desc'
endCursorPostId?: number
}
export interface GetAllPostsResponse {
totalCount: number
pageSize: number
items: Post[]
totalUsers: number
}
export interface Post {
id: number
userName: string
description: string
location?: string | null
images: Image[]
createdAt: string
updatedAt: string
avatarOwner?: string
ownerId: number
owner: Owner
likesCount: number
isLiked: boolean
}
export interface Owner {
firstName: string
lastName: string
}
export interface Image {
url: string
width: number
height: number
fileSize: number
createdAt: string
uploadId: string
}
export interface UserPosts {
totalCount: number
pageSize: number
items: Post[]
totalUsers: number
}
export interface UploadFileResponse {
images: Image[]
}

33
src/services/store.ts Normal file
View File

@@ -0,0 +1,33 @@
import {
Action,
combineSlices,
configureStore,
ThunkAction,
} from '@reduxjs/toolkit'
import { createWrapper } from 'next-redux-wrapper'
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import { instagramApi } from '@/services/instagram.api'
const makeStore = () =>
configureStore({
reducer: combineSlices(instagramApi),
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(instagramApi.middleware),
devTools: true,
})
export type AppStore = ReturnType<typeof makeStore>
export type AppState = ReturnType<AppStore['getState']>
export type AppDispatch = AppStore['dispatch']
export type AppThunk<ReturnType = void> = ThunkAction<
ReturnType,
AppState,
unknown,
Action
>
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = () => useDispatch<AppDispatch>()
export const useAppSelector: TypedUseSelectorHook<AppState> = useSelector
export const wrapper = createWrapper<AppStore>(makeStore)