(feat): frontend get service refactoring

This commit is contained in:
Maksym Sadovnychyy 2022-08-15 19:31:39 +02:00
parent f20da5eb0f
commit 5cf3a7f7f7
33 changed files with 265 additions and 207 deletions

View File

@ -45,7 +45,7 @@ const App = () => {
const { content, header, loader } = useSelector((state: ApplicationState) => state) const { content, header, loader } = useSelector((state: ApplicationState) => state)
useEffect(() => { useEffect(() => {
dispatch(settingsActionCreators.requestContent()) dispatch(settingsActionCreators.requestContent({ searchParams: { locale: "en-US" }}))
}, []) }, [])
useEffect(() => { useEffect(() => {

View File

@ -1,11 +1,16 @@
import { AuthorModel, FormItemModel, HeaderModel, ImageModel } from "./" import { AuthorModel, FormItemModel, HeaderModel, ImageModel } from "./"
import { TitleSectionModel } from "./pageSections" import { TitleSectionModel } from "./pageSections"
export interface Params {
export interface RequestModel {
[key: string]: string | undefined [key: string]: string | undefined
} }
export interface RequestModel<T, TT> {
pathParams?: T
searchParams?: TT,
}
export interface ResponseModel {} export interface ResponseModel {}
export interface AddressPageSectionModel extends PageSectionModel { export interface AddressPageSectionModel extends PageSectionModel {

View File

@ -1,43 +1,107 @@
import { RequestModel } from "./abstractions" import { Params, RequestModel } from "./abstractions"
// Blog requests // Blog requests -----------------------------------------------------
export interface GetBlogCatalogRequestModel extends RequestModel { export interface GetBlogcatalogPathParams extends Params {}
export interface GeBlogCatalogSearchParams extends Params {}
export interface GetBlogCatalogRequestModel extends RequestModel<GetBlogcatalogPathParams, GeBlogCatalogSearchParams> {
category?: string, category?: string,
searchText?: string, searchText?: string,
currentPage?: string, currentPage?: string,
itemsPerPage?: string itemsPerPage?: string
} }
export interface GetBlogCategoriesRequestModel extends RequestModel { } // --------------------------------------------------------------------
export interface GetBlogCategoriesPathParams extends Params {}
export interface GetBlogCategoriesSearchParams extends Params {}
export interface GetBlogCategoriesRequestModel extends RequestModel<GetBlogCategoriesPathParams, GetBlogCategoriesSearchParams> { }
export interface GetBlogItemRequestModel extends RequestModel { // --------------------------------------------------------------------
export interface GetBlogItemPathParams extends Params {}
export interface GetBlogItemSearchParams extends Params {
slug: string slug: string
} }
export interface GetBlogItemRequestModel extends RequestModel<GetBlogItemPathParams, GetBlogItemSearchParams> {
export interface GetBlogFeaturedRequestModel extends RequestModel { } }
// Static content
export interface GetContentRequestModel extends RequestModel { // ---------------------------------------------------------------------
export interface GetBlogFeaturedPathParams extends Params {}
export interface GetBlogFeaturedSearchParams extends Params {}
export interface GetBlogFeaturedRequestModel extends RequestModel<GetBlogFeaturedPathParams, GetBlogFeaturedSearchParams> { }
// Static content -------------------------------------------------
export interface GetContentPathParams extends Params {}
export interface GetContentSearchParams extends Params {
locale?: string locale?: string
} }
// Shop requests export interface GetContentRequestModel extends RequestModel<GetContentPathParams, GetContentSearchParams> { }
export interface GetShopCatalogRequestModel extends RequestModel {
// Shop requests -------------------------------------------------
export interface GetShopCatalogPathParams extends Params {}
export interface GetShopCatalogSearchParams extends Params {
category?: string, category?: string,
searchText?: string, searchText?: string,
currentPage?: string, currentPage?: string,
itemsPerPage?: string itemsPerPage?: string
} }
export interface GetShopCategoriesRequestModel extends RequestModel { } export interface GetShopCatalogRequestModel extends RequestModel<GetShopCatalogPathParams, GetShopCatalogSearchParams> { }
export interface GetShopFeaturedRequestModel extends RequestModel { } // Shop cart items ------------------------------------------------
export interface GetShopCartItemsPathParams extends Params {
export interface GetShopItemRequestModel extends RequestModel { userId: string
slug: string
} }
export interface GetShopRelatedRequestModel extends RequestModel { } export interface GetShopCartItemsSearchParams extends Params {
userId: string
}
export interface GetShopCartRequestModel extends RequestModel {} export interface GetShopCartItemsRequestModel extends RequestModel<GetShopCartItemsPathParams, GetShopCartItemsSearchParams> {}
// -------------------------------------------------------------------
export interface GetShopCategoriesPathParams extends Params {}
export interface GetShopCategoriesSearchParams extends Params {}
export interface GetShopCategoriesRequestModel extends RequestModel<GetShopCategoriesPathParams, GetShopCategoriesSearchParams> { }
// ------------------------------------------------------------------
export interface GetShopFeaturedSearchParams extends Params {}
export interface GetShopFeaturedPathParams extends Params {}
export interface GetShopFeaturedRequestModel extends RequestModel<GetShopFeaturedSearchParams, GetShopFeaturedPathParams> { }
// -------------------------------------------------------------------
export interface GetShopItemPathParams extends Params {}
export interface GetShopItemSearchParams extends Params {
slug: string
}
export interface GetShopItemRequestModel extends RequestModel<GetShopItemPathParams, GetShopItemSearchParams> {
}
// -------------------------------------------------------------------
export interface GetShopRelatedPathParams extends Params {}
export interface GetShopRelatedSearchParams extends Params {}
export interface GetShopRelatedRequestModel extends RequestModel<GetShopRelatedPathParams, GetShopRelatedSearchParams> { }
// -------------------------------------------------------------------
export interface GetShopCartItemPathParams extends Params {}
export interface GetShopCartItemSearchParams extends Params {}
export interface GetShopCartItemRequestModel extends RequestModel<GetShopCartItemPathParams, GetShopCartItemSearchParams> {}

View File

@ -1,4 +1,4 @@
import { BlogItemModel, CategoryModel, CommentModel, HeaderModel, LocalizationModel, MenuItemModel, PaginationModel, RouteModel, ShopItemModel } from "./" import { BlogItemModel, CategoryModel, CommentModel, HeaderModel, ImageModel, LocalizationModel, MenuItemModel, PaginationModel, RouteModel, ShopItemModel } from "./"
import { ResponseModel } from "./abstractions" import { ResponseModel } from "./abstractions"
import * as Pages from "./pages" import * as Pages from "./pages"
@ -24,8 +24,18 @@ export interface GetShopRelatedResponseModel extends ResponseModel {
items: ShopItemModel [] items: ShopItemModel []
} }
export interface GetShopCartResponseModel extends ResponseModel {
items: ShopItemModel [] export interface GetShopCartItemResponseModel {
slug: string
sku: string,
image: ImageModel,
title: string,
brandName: string,
shortText: string,
created: string,
price: number,
newPrice?: number,
quantity: number
} }

View File

@ -59,7 +59,9 @@ const BlogItem = () => {
useEffect(() => { useEffect(() => {
if(params?.slug) if(params?.slug)
dispatch(blogItemActionCreators.requestBlogItem({ dispatch(blogItemActionCreators.requestBlogItem({
slug: params.slug searchParams: {
slug: params.slug
}
})) }))
}, []) }, [])

View File

@ -4,7 +4,7 @@ import React, { useEffect, useState } from 'react'
// Redux // Redux
import { useDispatch, useSelector } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
import { actionCreators as loaderActionCreators } from '../../../store/reducers/Loader' import { actionCreators as loaderActionCreators } from '../../../store/reducers/Loader'
// import { actionCreator as shopCartActionCreator } from '../../../store/reducers/ShopCart' import { actionCreators as shopCartActionCreators } from '../../../store/reducers/ShopCart'
import { ApplicationState } from '../../../store' import { ApplicationState } from '../../../store'
import { Button, Col, Container, Input, InputGroup, Row } from 'reactstrap' import { Button, Col, Container, Input, InputGroup, Row } from 'reactstrap'
@ -18,13 +18,19 @@ const Cart = () => {
const dispatch = useDispatch() const dispatch = useDispatch()
const { content, shopCart } = useSelector((state: ApplicationState) => state) const { content, shopCart } = useSelector((state: ApplicationState) => state)
useEffect(() => { useEffect(() => {
content?.isLoading || shopCart?.isLoading dispatch(shopCartActionCreators.requestCart({ pathParams: { userId: "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60" }}))
}, [])
useEffect(() => {
content?.isLoading
? dispatch(loaderActionCreators.show()) ? dispatch(loaderActionCreators.show())
: setTimeout(() => { : setTimeout(() => {
dispatch(loaderActionCreators.hide()) dispatch(loaderActionCreators.hide())
}, 1000) }, 1000)
}, [content?.isLoading, shopCart?.isLoading]) }, [content?.isLoading])
const { const {
currencySymbol = "" currencySymbol = ""

View File

@ -94,7 +94,9 @@ const ShopItemsSection: FC<ShopItems> = ({
currentPage: currentPage, currentPage: currentPage,
onClick: (nextPage) => { onClick: (nextPage) => {
dispatch(shopCatalogActionCreators.requestShopCatalog({ dispatch(shopCatalogActionCreators.requestShopCatalog({
currentPage: nextPage + "" searchParams: {
currentPage: nextPage + ""
}
})) }))
navigate(`${path}/${nextPage}`) navigate(`${path}/${nextPage}`)
@ -119,7 +121,9 @@ const ShopCatalog = () => {
useEffect(() => { useEffect(() => {
dispatch(shopCatalogActionCreators.requestShopCatalog({ dispatch(shopCatalogActionCreators.requestShopCatalog({
currentPage: params?.page ? params.page : "1" searchParams: {
currentPage: params?.page ? params.page : "1"
}
})) }))
}, []) }, [])

View File

@ -35,7 +35,9 @@ const ShopItem : FC = () => {
useEffect(() => { useEffect(() => {
if(params?.slug) if(params?.slug)
dispatch(shopItemActionCreators.requestShopItem({ dispatch(shopItemActionCreators.requestShopItem({
slug: params.slug searchParams: {
slug: params.slug
}
})) }))
}, []) }, [])

View File

@ -1,4 +1,4 @@
import { RequestModel } from "./models/abstractions" import { Params, RequestModel } from "./models/abstractions"
@ -12,13 +12,21 @@ const Post = () => {
} }
const Get = async <T>(apiUrl: string, props?: RequestModel): Promise<T | null> => { const Get = async <T>(apiUrl: string, pathParams?: Params, searchParams?: Params): Promise<T | null> => {
const url = new URL(apiUrl) const url = new URL(apiUrl)
if(props) { if(pathParams) {
Object.keys(props).forEach(key => { Object.keys(pathParams).forEach(key => {
if (typeof(props[key]) !== undefined) { if (typeof(pathParams[key]) !== undefined) {
url.searchParams.append(key, props[key] as string) url.pathname += `/${pathParams[key]}`
}
})
}
if(searchParams) {
Object.keys(searchParams).forEach(key => {
if (typeof(searchParams[key]) !== undefined) {
url.searchParams.append(key, searchParams[key] as string)
} }
}) })
} }

View File

@ -22,7 +22,7 @@ type KnownAction = RequestAction | ReceiveAction
export const actionCreators = { export const actionCreators = {
requestBlogCatalog: (props?: GetBlogCatalogRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => { requestBlogCatalog: (props?: GetBlogCatalogRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => {
Get<Promise<GetBlogCatalogResponseModel>>('https://localhost:7151/api/BlogCatalog', props) Get<Promise<GetBlogCatalogResponseModel>>('https://localhost:7151/api/BlogCatalog', props?.pathParams, props?.searchParams)
.then(response => response) .then(response => response)
.then(data => { .then(data => {
if(data) if(data)

View File

@ -22,7 +22,7 @@ type KnownAction = RequestAction | ReceiveAction
export const actionCreators = { export const actionCreators = {
requestBlogCategories: (props?: GetBlogCategoriesRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => { requestBlogCategories: (props?: GetBlogCategoriesRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => {
Get<Promise<GetBlogCategoriesResponseModel>>('https://localhost:7151/api/BlogCategories', props) Get<Promise<GetBlogCategoriesResponseModel>>('https://localhost:7151/api/BlogCategories', props?.pathParams, props?.searchParams)
.then(response => response) .then(response => response)
.then(data => { .then(data => {
if(data) if(data)

View File

@ -22,7 +22,7 @@ type KnownAction = RequestAction | ReceiveAction
export const actionCreators = { export const actionCreators = {
requestBlogFeatured: (props?: GetBlogFeaturedRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => { requestBlogFeatured: (props?: GetBlogFeaturedRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => {
Get<Promise<GetBlogFeaturedResponseModel>>('https://localhost:7151/api/BlogFeatured', props) Get<Promise<GetBlogFeaturedResponseModel>>('https://localhost:7151/api/BlogFeatured', props?.pathParams, props?.searchParams)
.then(response => response) .then(response => response)
.then(data => { .then(data => {
if(data) if(data)

View File

@ -20,16 +20,16 @@ interface ReceiveAction extends GetBlogItemResponseModel {
type KnownAction = RequestAction | ReceiveAction type KnownAction = RequestAction | ReceiveAction
export const actionCreators = { export const actionCreators = {
requestBlogItem: (props: GetBlogItemRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => { requestBlogItem: (props?: GetBlogItemRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => {
Get<Promise<GetBlogItemResponseModel>>('https://localhost:7151/api/BlogItem', props) Get<Promise<GetBlogItemResponseModel>>('https://localhost:7151/api/BlogItem', props?.pathParams, props?.searchParams)
.then(response => response) .then(response => response)
.then(data => { .then(data => {
if(data) if(data)
dispatch({ type: 'RECEIVE_BLOG_ITEM', ...data }) dispatch({ type: 'RECEIVE_BLOG_ITEM', ...data })
}) })
dispatch({ type: 'REQUEST_BLOG_ITEM', slug: props.slug }) // dispatch({ type: 'REQUEST_BLOG_ITEM', slug: props.slug })
} }
} }

View File

@ -23,7 +23,7 @@ type KnownAction = RequestAction | ReceiveAction;
export const actionCreators = { export const actionCreators = {
requestContent: (props?: GetContentRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => { requestContent: (props?: GetContentRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => {
Get<Promise<GetContentResponseModel>>('https://localhost:7151/api/Content/404c8232-9048-4519-bfba-6e78dc7005ca?locale=en-US', props) Get<Promise<GetContentResponseModel>>('https://localhost:7151/api/Content/404c8232-9048-4519-bfba-6e78dc7005ca', props?.pathParams, props?.searchParams)
.then(response => response) .then(response => response)
.then((data) => { .then((data) => {
if(data) { if(data) {

View File

@ -1,34 +1,47 @@
import { Action, Reducer } from 'redux' import { Action, Reducer } from 'redux'
import { AppThunkAction } from '..' import { AppThunkAction } from '..'
import { ShopItemModel } from '../../models'
import { GetShopCartRequestModel } from '../../models/requests'
import { GetShopCartResponseModel } from '../../models/responses'
export interface ShopCartState extends GetShopCartResponseModel { import { GetShopCartItemsRequestModel } from '../../models/requests'
import { GetShopCartItemResponseModel } from '../../models/responses'
import { Get } from '../../restClient'
export interface ShopCartState {
items: GetShopCartItemResponseModel [],
isLoading: boolean isLoading: boolean
} }
export interface RequestAction extends GetShopCartRequestModel { export interface RequestAction {
type: 'REQUEST_CART' type: 'REQUEST_CART_ITEMS'
} }
export interface ReceiveAction extends GetShopCartResponseModel { export interface ReceiveAction {
type: 'RECEIVE_CART' items: GetShopCartItemResponseModel [],
type: 'RECEIVE_CART_ITEMS'
} }
export interface IncrementItemQuantityAction extends GetShopCartResponseModel { // export interface IncrementItemQuantityAction extends GetShopCartResponseModel {
type: 'INCREMENT_ITEM_QUANTITY' // type: 'INCREMENT_ITEM_QUANTITY'
} // }
export interface DecrementItmeQuantityAction extends GetShopCartResponseModel { // export interface DecrementItmeQuantityAction extends GetShopCartResponseModel {
type: 'DECREMENT_ITEM_QUANTITY' // type: 'DECREMENT_ITEM_QUANTITY'
} // }
export type KnownAction = RequestAction | ReceiveAction | IncrementItemQuantityAction | DecrementItmeQuantityAction export type KnownAction = RequestAction | ReceiveAction //| IncrementItemQuantityAction | DecrementItmeQuantityAction
export const actionCreators = { export const actionCreators = {
requestCart: (): AppThunkAction<KnownAction> => (dispatch, getState) => { requestCart: (props?: GetShopCartItemsRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => {
Get<Promise<GetShopCartItemResponseModel []>>('https://localhost:7151/api/ShopCartItems/404c8232-9048-4519-bfba-6e78dc7005ca', props?.pathParams, props?.searchParams)
.then(response => response)
.then(data => {
if(data)
dispatch({ type: 'RECEIVE_CART_ITEMS', items: [...data] })
})
dispatch({ type: 'REQUEST_CART_ITEMS' })
}, },
addToCart: (): AppThunkAction<KnownAction> => (dispatch, getState) => { addToCart: (): AppThunkAction<KnownAction> => (dispatch, getState) => {
@ -43,103 +56,61 @@ export const actionCreators = {
// dispatch({ type: 'REQUEST_BLOG_ITEM', slug: props.slug }) // dispatch({ type: 'REQUEST_BLOG_ITEM', slug: props.slug })
}, },
increment: (): AppThunkAction<KnownAction> => (dispatch, getState) => { // increment: (startDateIndex: number): AppThunkAction<KnownAction> => (dispatch, getState) => {
const items: ShopItemModel [] = [] // const items: ShopItemModel [] = []
dispatch({ type: 'INCREMENT_ITEM_QUANTITY', items }) // dispatch({ type: 'INCREMENT_ITEM_QUANTITY', items })
}, // },
decrement: (): AppThunkAction<KnownAction> => (dispatch, getState) => { // decrement: (): AppThunkAction<KnownAction> => (dispatch, getState) => {
const items: ShopItemModel [] = [] // const items: ShopItemModel [] = []
dispatch({ type: 'DECREMENT_ITEM_QUANTITY', items }) // dispatch({ type: 'DECREMENT_ITEM_QUANTITY', items })
}, // },
remFromCart: (): AppThunkAction<KnownAction> => (dispatch, getState) => { // remFromCart: (): AppThunkAction<KnownAction> => (dispatch, getState) => {
} // }
} }
const unloadedState: ShopCartState = { const unloadedState: ShopCartState = {
items: [ items: [
{ {
id: '',
slug: "shop-catalog-item", slug: "shop-catalog-item",
sku: "SKU-0", sku: "SKU-0",
image: { src: "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", alt: "..." }, image: { src: "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", alt: "..." },
badges: [ "sale" ],
title: "Shop item title", title: "Shop item title",
brandName: "Brand & Name", brandName: "Brand & Name",
shortText: "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...", shortText: "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...",
text: "",
author: {
id: '',
image: { src: "https://dummyimage.com/40x40/ced4da/6c757d", alt: "..." },
nickName: "Admin"
},
created: (new Date).toString(), created: (new Date).toString(),
tags: [ "react", "redux", "webapi" ],
rating: 4.5,
price: 20, price: 20,
newPrice: 10, newPrice: 10,
quantity: 1 quantity: 1
}, },
{ {
id: '',
slug: "shop-catalog-item", slug: "shop-catalog-item",
sku: "SKU-0", sku: "SKU-0",
image: { src: "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", alt: "..." }, image: { src: "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", alt: "..." },
badges: [ "sale" ],
title: "Shop item title", title: "Shop item title",
brandName: "Brand & Name", brandName: "Brand & Name",
shortText: "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...", shortText: "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...",
text: "",
author: {
id: '',
image: { src: "https://dummyimage.com/40x40/ced4da/6c757d", alt: "..." },
nickName: "Admin"
},
created: (new Date).toString(), created: (new Date).toString(),
tags: [ "react", "redux", "webapi" ],
rating: 4.5,
price: 20, price: 20,
newPrice: 10, newPrice: 10,
quantity: 1
quantity: 2
}, },
{ {
id: '',
slug: "shop-catalog-item", slug: "shop-catalog-item",
sku: "SKU-0", sku: "SKU-0",
image: { src: "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", alt: "..." }, image: { src: "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", alt: "..." },
badges: [ "sale" ],
title: "Shop item title", title: "Shop item title",
brandName: "Brand & Name", brandName: "Brand & Name",
shortText: "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...", shortText: "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...",
text: "",
author: {
id: '',
image: { src: "https://dummyimage.com/40x40/ced4da/6c757d", alt: "..." },
nickName: "Admin"
},
created: (new Date).toString(), created: (new Date).toString(),
tags: [ "react", "redux", "webapi" ],
rating: 4.5,
price: 20, price: 20,
newPrice: 10, newPrice: 10,
quantity: 1
quantity: 3
} }
], ],
@ -153,29 +124,29 @@ export const reducer: Reducer<ShopCartState> = (state: ShopCartState | undefined
const action = incomingAction as KnownAction const action = incomingAction as KnownAction
switch (action.type) { switch (action.type) {
case 'REQUEST_CART': case 'REQUEST_CART_ITEMS':
return { return {
...state, ...state,
isLoading: true isLoading: true
} }
case 'RECEIVE_CART': case 'RECEIVE_CART_ITEMS':
return { return {
...action, ...action,
isLoading: false isLoading: false
} }
case 'INCREMENT_ITEM_QUANTITY': // case 'INCREMENT_ITEM_QUANTITY':
return { // return {
...action, // ...action,
isLoading: false // isLoading: false
} // }
case 'DECREMENT_ITEM_QUANTITY': // case 'DECREMENT_ITEM_QUANTITY':
return { // return {
...action, // ...action,
isLoading: false // isLoading: false
} // }
} }
return state return state

View File

@ -22,7 +22,7 @@ type KnownAction = RequestAction | ReceiveAction
export const actionCreators = { export const actionCreators = {
requestShopCatalog: (props?: GetShopCatalogRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => { requestShopCatalog: (props?: GetShopCatalogRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => {
Get<Promise<GetShopCatalogResponseModel>>('https://localhost:7151/api/ShopCatalog', props) Get<Promise<GetShopCatalogResponseModel>>('https://localhost:7151/api/ShopCatalog', props?.pathParams, props?.searchParams)
.then(response => response) .then(response => response)
.then(data => { .then(data => {
if(data) if(data)

View File

@ -22,7 +22,7 @@ type KnownAction = RequestAction | ReceiveAction
export const actionCreators = { export const actionCreators = {
requestShopCategories: (props?: GetShopCategoriesRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => { requestShopCategories: (props?: GetShopCategoriesRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => {
Get<Promise<GetShopCategoriesResponseModel>>('https://localhost:7151/api/ShopCategories', props) Get<Promise<GetShopCategoriesResponseModel>>('https://localhost:7151/api/ShopCategories', props?.pathParams, props?.searchParams)
.then(response => response) .then(response => response)
.then(data => { .then(data => {
if(data) if(data)

View File

@ -22,7 +22,7 @@ type KnownAction = RequestAction | ReceiveAction
export const actionCreators = { export const actionCreators = {
requestShopFeatured: (props?: GetShopFeaturedRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => { requestShopFeatured: (props?: GetShopFeaturedRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => {
Get<Promise<GetShopFeaturedResponseModel>>('https://localhost:7151/api/ShopFeatured', props) Get<Promise<GetShopFeaturedResponseModel>>('https://localhost:7151/api/ShopFeatured', props?.pathParams, props?.searchParams)
.then(response => response) .then(response => response)
.then(data => { .then(data => {
if(data) if(data)

View File

@ -21,16 +21,16 @@ interface ReceiveAction extends GetShopItemResponseModel {
type KnownAction = RequestAction | ReceiveAction type KnownAction = RequestAction | ReceiveAction
export const actionCreators = { export const actionCreators = {
requestShopItem: (props: GetShopItemRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => { requestShopItem: (props?: GetShopItemRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => {
Get<Promise<GetShopItemResponseModel>>('https://localhost:7151/api/ShopItem', props) Get<Promise<GetShopItemResponseModel>>('https://localhost:7151/api/ShopItem', props?.pathParams, props?.searchParams)
.then(response => response) .then(response => response)
.then(data => { .then(data => {
if(data) if(data)
dispatch({ type: 'RECEIVE_SHOP_ITEM', ...data }) dispatch({ type: 'RECEIVE_SHOP_ITEM', ...data })
}) })
dispatch({ type: 'REQUEST_SHOP_ITEM', slug: props.slug }) // dispatch({ type: 'REQUEST_SHOP_ITEM', slug: props.slug })
} }
} }

View File

@ -22,7 +22,7 @@ type KnownAction = RequestAction | ReceiveAction
export const actionCreators = { export const actionCreators = {
requestShopRelated: (props?: GetShopRelatedRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => { requestShopRelated: (props?: GetShopRelatedRequestModel): AppThunkAction<KnownAction> => (dispatch, getState) => {
Get<Promise<GetShopRelatedResponseModel>>('https://localhost:7151/api/ShopRelated', props) Get<Promise<GetShopRelatedResponseModel>>('https://localhost:7151/api/ShopRelated', props?.pathParams, props?.searchParams)
.then(response => response) .then(response => response)
.then(data => { .then(data => {
if(data) if(data)

View File

@ -6,5 +6,6 @@ using System.Threading.Tasks;
namespace Core.Abstractions.DomainObjects { namespace Core.Abstractions.DomainObjects {
public abstract class DomainObjectBase<T> : EquatableBase<T> { public abstract class DomainObjectBase<T> : EquatableBase<T> {
} }
} }

View File

@ -7,7 +7,7 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Core.Models { namespace Core.Models {
public class PaginationModel<T> : ResponseModelBase { public abstract class PaginationModelBase<T> : ResponseModelBase {
public int TotalPages { get; set; } public int TotalPages { get; set; }
public int CurrentPage { get; set; } public int CurrentPage { get; set; }
public List<T> Items { get; set; } public List<T> Items { get; set; }

View File

@ -6,9 +6,6 @@ using System.Threading.Tasks;
namespace Core.Abstractions.Models { namespace Core.Abstractions.Models {
public abstract class RequestModelBase<T> : ModelBase { public abstract class RequestModelBase<T> : ModelBase {
public abstract T ApplyTo(T obj);
public abstract T ToDomainObject(); public abstract T ToDomainObject();
} }
} }

View File

@ -15,7 +15,7 @@ namespace DataProviders {
(List<ShopCartItem>?, IDomainResult) GetAll(Guid siteId, Guid userId); (List<ShopCartItem>?, IDomainResult) GetAll(Guid siteId, Guid userId);
(ShopCartItem?, IDomainResult) Get(Guid siteId, Guid userId, string sku); (ShopCartItem?, IDomainResult) Get(Guid siteId, Guid userId, string sku);
(Guid?, IDomainResult) Update(ShopCartItem shopCart); (Guid?, IDomainResult) Update(ShopCartItem shopCart);
IDomainResult Delete(Guid siteId, Guid userId, string sku); IDomainResult Delete(Guid id);
} }
public class ShopCartDataProvider : DataProviderBase<ShopCartItem>, IShopCartDataProvider { public class ShopCartDataProvider : DataProviderBase<ShopCartItem>, IShopCartDataProvider {
@ -45,8 +45,7 @@ namespace DataProviders {
public (Guid?, IDomainResult) Update(ShopCartItem shopCart) => public (Guid?, IDomainResult) Update(ShopCartItem shopCart) =>
UpdateWithPredicate(shopCart, x => x.Id == shopCart.Id, _collectionName); UpdateWithPredicate(shopCart, x => x.Id == shopCart.Id, _collectionName);
public IDomainResult Delete(Guid siteId, Guid userId, string sku) { public IDomainResult Delete(Guid id) =>
throw new NotImplementedException(); DeleteWithPredicate(x => x.Id == id, _collectionName);
}
} }
} }

View File

@ -59,8 +59,10 @@ public class BlogCatalogController : ControllerBase {
var totalPages = blogModels.Count() / itemsPerPage; var totalPages = blogModels.Count() / itemsPerPage;
var blogCatalogResponse = new GetBlogCatalogResponseModel { var blogCatalogResponse = new GetBlogCatalogResponseModel {
/*
FeaturedBlog = blogModels[0], FeaturedBlog = blogModels[0],
BlogItemsPagination = new PaginationModel<BlogItemModel> { BlogItemsPagination = new PaginationModelBase<BlogItemModel> {
CurrentPage = currentPage, CurrentPage = currentPage,
TotalPages = totalPages, TotalPages = totalPages,
Items = blogModels.Skip((currentPage -1) * itemsPerPage).Take(itemsPerPage).ToList() Items = blogModels.Skip((currentPage -1) * itemsPerPage).Take(itemsPerPage).ToList()
@ -90,7 +92,7 @@ public class BlogCatalogController : ControllerBase {
Id = Guid.NewGuid(), Id = Guid.NewGuid(),
Text = "Tutorials" Text = "Tutorials"
} }
} }*/
}; };

View File

@ -59,11 +59,11 @@ public class ShopCatalogController : ControllerBase {
} }
var shopCatalogResponse = new GetShopCatalogResponseModel { var shopCatalogResponse = new GetShopCatalogResponseModel {
ShopItemsPagination = new PaginationModel<ShopItemModel> { /*ShopItemsPagination = new PaginationModelBase<ShopItemModel> {
CurrentPage = currentPage, CurrentPage = currentPage,
TotalPages = 100, TotalPages = 100,
Items = shopModels Items = shopModels
} }*/
}; };

View File

@ -15,23 +15,19 @@ namespace WeatherForecast.Models.Requests {
public double NewPrice { get; set; } public double NewPrice { get; set; }
public uint Quantity { get; set; } public uint Quantity { get; set; }
public override ShopCartItem ApplyTo(ShopCartItem shopCart) { public override ShopCartItem ToDomainObject() => new ShopCartItem {
shopCart.Slug = Slug; Slug = Slug,
shopCart.Image = new Image { Image = new Image {
Src = Image.Src, Src = Image.Src,
Alt = Image.Alt Alt = Image.Alt
}; },
shopCart.Title = Title; Title = Title,
shopCart.BrandName = BrandName; BrandName = BrandName,
shopCart.ShortText = ShortText; ShortText = ShortText,
shopCart.Created = Created; Created = Created,
shopCart.Price = Price; Price = Price,
shopCart.NewPrice = NewPrice; NewPrice = NewPrice,
shopCart.Quantity = Quantity; Quantity = Quantity
};
return shopCart;
}
public override ShopCartItem ToDomainObject() => ApplyTo(new ShopCartItem());
} }
} }

View File

@ -15,23 +15,20 @@ namespace WeatherForecast.Models.Requests {
public double NewPrice { get; set; } public double NewPrice { get; set; }
public uint Quantity { get; set; } public uint Quantity { get; set; }
public override ShopCartItem ApplyTo(ShopCartItem shopCart) {
shopCart.Slug = Slug; public override ShopCartItem ToDomainObject() => new ShopCartItem {
shopCart.Image = new Image { Slug = Slug,
Image = new Image {
Src = Image.Src, Src = Image.Src,
Alt = Image.Alt Alt = Image.Alt
}; },
shopCart.Title = Title; Title = Title,
shopCart.BrandName = BrandName; BrandName = BrandName,
shopCart.ShortText = ShortText; ShortText = ShortText,
shopCart.Created = Created; Created = Created,
shopCart.Price = Price; Price = Price,
shopCart.NewPrice = NewPrice; NewPrice = NewPrice,
shopCart.Quantity = Quantity; Quantity = Quantity
};
return shopCart;
}
public override ShopCartItem ToDomainObject() => ApplyTo(new ShopCartItem());
} }
} }

View File

@ -8,6 +8,6 @@ namespace WeatherForecast.Models.Responses {
public List<CategoryModel> Categories { get; set; } public List<CategoryModel> Categories { get; set; }
public PaginationModel<BlogItemModel> BlogItemsPagination { get; set; } public PaginationModelBase<BlogItemModel> BlogItemsPagination { get; set; }
} }
} }

View File

@ -1,14 +0,0 @@
using Core.Abstractions.Models;
using Core.DomainObjects.Documents;
namespace WeatherForecast.Models.Responses {
public class GetShopCartItemsResponseModel : ResponseModelBase {
public List<GetShopCartItemResponseModel> Items { get; set; }
public GetShopCartItemsResponseModel(List<ShopCartItem> items) {
Items = items.Select(x => new GetShopCartItemResponseModel(x)).ToList();
}
}
}

View File

@ -3,6 +3,6 @@ using Core.Models;
namespace WeatherForecast.Models.Responses { namespace WeatherForecast.Models.Responses {
public class GetShopCatalogResponseModel : ResponseModelBase { public class GetShopCatalogResponseModel : ResponseModelBase {
public PaginationModel<ShopItemModel> ShopItemsPagination { get; set; } public PaginationModelBase<ShopItemModel> ShopItemsPagination { get; set; }
} }
} }

View File

@ -31,13 +31,13 @@ namespace WeatherForecast.Services {
if (getResult.IsSuccess) if (getResult.IsSuccess)
return IDomainResult.Failed<Guid?>(); return IDomainResult.Failed<Guid?>();
var obj = requestModel.ToDomainObject(); var item = requestModel.ToDomainObject();
obj.SiteId = siteId; item.SiteId = siteId;
obj.UserId = userId; item.UserId = userId;
obj.Sku = sku; item.Sku = sku;
var (id, insertResult) = _shopCartDataProvider.Insert(obj); var (id, insertResult) = _shopCartDataProvider.Insert(item);
if (!insertResult.IsSuccess) if (!insertResult.IsSuccess)
return IDomainResult.Failed<Guid?>(); return IDomainResult.Failed<Guid?>();
@ -59,10 +59,15 @@ namespace WeatherForecast.Services {
if (!getResult.IsSuccess || item == null) if (!getResult.IsSuccess || item == null)
return (null, getResult); return (null, getResult);
var newShopCart = requestData.ApplyTo(item); // construct domain object from model
var newItem = requestData.ToDomainObject();
newItem.Id = item.Id;
newItem.SiteId = siteId;
newItem.UserId = userId;
newItem.Sku = sku;
if (!item.Equals(newShopCart)) { if (!item.Equals(newItem)) {
var (id, updateResult) = _shopCartDataProvider.Update(item); var (id, updateResult) = _shopCartDataProvider.Update(newItem);
if (!updateResult.IsSuccess || id == null) if (!updateResult.IsSuccess || id == null)
return (null, updateResult); return (null, updateResult);
} }
@ -71,7 +76,11 @@ namespace WeatherForecast.Services {
} }
public IDomainResult Delete(Guid siteId, Guid userId, string sku) { public IDomainResult Delete(Guid siteId, Guid userId, string sku) {
var result = _shopCartDataProvider.Delete(siteId, userId, sku); var (item, getResult) = _shopCartDataProvider.Get(siteId, userId, sku);
if (!getResult.IsSuccess || item == null)
return getResult;
var result = _shopCartDataProvider.Delete(item.Id);
if (!result.IsSuccess) if (!result.IsSuccess)
return result; return result;

View File

@ -1,13 +1,12 @@
using DataProviders; using DataProviders;
using DomainResults.Common; using DomainResults.Common;
using WeatherForecast.Models.Requests;
using WeatherForecast.Models.Responses; using WeatherForecast.Models.Responses;
namespace WeatherForecast.Services { namespace WeatherForecast.Services {
public interface IShopCartItemsService { public interface IShopCartItemsService {
(GetShopCartItemsResponseModel?, IDomainResult) Get(Guid siteId, Guid userId); (List<GetShopCartItemResponseModel>?, IDomainResult) Get(Guid siteId, Guid userId);
} }
public class ShopCartItemsService : IShopCartItemsService { public class ShopCartItemsService : IShopCartItemsService {
@ -23,14 +22,14 @@ namespace WeatherForecast.Services {
_shopCartDataProvider = shopCartDataprovider; _shopCartDataProvider = shopCartDataprovider;
} }
public (GetShopCartItemsResponseModel?, IDomainResult) Get(Guid siteId, Guid userId) { public (List<GetShopCartItemResponseModel>?, IDomainResult) Get(Guid siteId, Guid userId) {
var (items, result) = _shopCartDataProvider.GetAll(siteId, userId); var (items, result) = _shopCartDataProvider.GetAll(siteId, userId);
if (!result.IsSuccess || items == null) if (!result.IsSuccess || items == null)
return (null, result); return (null, result);
return IDomainResult.Success(new GetShopCartItemsResponseModel(items)); return IDomainResult.Success(items.Select(x => new GetShopCartItemResponseModel(x)).ToList());
} }
} }
} }