= (props: ISubMenu) => {
- const { icon, title, items } = props
+ //const { icon, title, items } = props
const [collapsed, setCollapsed] = useState(true)
const toggle = () => setCollapsed(!collapsed)
- return (
-
-
-
- {icon ? : ''}
- {title}
-
-
-
- {items.map((item: ISubMenuItem, index: number) => (
-
-
- {item.icon ? : ''}
- {item.title}
-
-
- ))}
-
-
- )
+ return
+ {/*
+
+ {icon ? : ''}
+ {title}
+
+
+
+ {items.map((item: ISubMenuItem, index: number) => (
+
+
+ {item.icon ? : ''}
+ {item.title}
+
+
+ ))}
+ */}
+
}
const SideMenu : FC = () => {
- let { sideMenu = [] } = useSelector((state: IReduxState) => state.settings)
+ //let { sideMenu = [] } = useSelector((state: IReduxState) => state.settings)
return
- */}
}
diff --git a/clientapp/src/layouts/interfaces.tsx b/clientapp/src/layouts/interfaces.tsx
index 6f16a3b..6394078 100644
--- a/clientapp/src/layouts/interfaces.tsx
+++ b/clientapp/src/layouts/interfaces.tsx
@@ -1,4 +1,3 @@
-import { ISettingsState } from "../store/reducers/Settings"
export interface ILayout {
children?: React.ReactNode
diff --git a/clientapp/src/layouts/public/Footer/index.tsx b/clientapp/src/layouts/public/Footer/index.tsx
index 2f66c81..edff5da 100644
--- a/clientapp/src/layouts/public/Footer/index.tsx
+++ b/clientapp/src/layouts/public/Footer/index.tsx
@@ -1,13 +1,12 @@
import React from 'react'
import { useSelector } from 'react-redux'
import { Container } from 'reactstrap'
-import { IReduxState } from '../../../interfaces'
const Footer = () => {
- let { siteName } = useSelector((state: IReduxState) => state.settings)
+ // let { siteName } = useSelector((state: IReduxState) => state.settings)
return
}
diff --git a/clientapp/src/layouts/public/NavMenu/index.tsx b/clientapp/src/layouts/public/NavMenu/index.tsx
index 576830f..9b73207 100644
--- a/clientapp/src/layouts/public/NavMenu/index.tsx
+++ b/clientapp/src/layouts/public/NavMenu/index.tsx
@@ -3,10 +3,13 @@ import { Link } from 'react-router-dom'
import { useSelector } from 'react-redux'
import { Collapse, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } from 'reactstrap'
import { FeatherIcon } from '../../../components/FeatherIcons'
-import { IMenuItem, IReduxState } from '../../../interfaces'
+
const NavMenu : FC = () => {
- let { siteName, topMenu = [] } = useSelector((state: IReduxState) => state.settings)
+ /*
+ let { siteName, topMenu = [] } = useSelector((state: IReduxState) => {
+ return state.settings
+ })
const [state, hookState] = useState({
isOpen: false
@@ -17,14 +20,16 @@ const NavMenu : FC = () => {
isOpen: !state.isOpen
})
}
+ */
return
+ {/**
{siteName} NavbarBrand>
- {topMenu.map((item: IMenuItem, index: number) => {
+ {topMenu.map((item: IMenuItemModel, index: number) => {
return
{item.icon ? : ''}
@@ -42,6 +47,7 @@ const NavMenu : FC = () => {
+ */}
}
diff --git a/clientapp/src/httpQueries/models.ts b/clientapp/src/models/index.ts
similarity index 75%
rename from clientapp/src/httpQueries/models.ts
rename to clientapp/src/models/index.ts
index 83ca426..003518e 100644
--- a/clientapp/src/httpQueries/models.ts
+++ b/clientapp/src/models/index.ts
@@ -1,8 +1,3 @@
-export interface IFetchResult {
- status: number,
- text: string
-}
-
export interface IImageModel {
src: string,
alt: string
@@ -29,8 +24,8 @@ interface IPostItemModel {
}
export interface IBlogItemModel extends IPostItemModel {
- readTime: number,
- likes: number
+ readTime?: number,
+ likes?: number
}
export interface IShopItemModel extends IPostItemModel {
@@ -59,4 +54,21 @@ export interface IShopItemsPaginationModel extends IPostPaginationModel {
export interface ICategoryModel {
id: string,
text: string
+}
+
+export interface IRouteModel {
+ target: string
+ component?: string
+ childRoutes?: IRouteModel []
+}
+
+export interface IMenuItemModel {
+ icon?: string,
+ title?: string,
+ target?: string
+ childItems?: IMenuItemModel []
+}
+
+export interface IPageModel {
+ id: string
}
\ No newline at end of file
diff --git a/clientapp/src/pages/Blog/Catalog/index.tsx b/clientapp/src/pages/Blog/Catalog/index.tsx
index b56f9a3..bca91aa 100644
--- a/clientapp/src/pages/Blog/Catalog/index.tsx
+++ b/clientapp/src/pages/Blog/Catalog/index.tsx
@@ -4,8 +4,8 @@ import { Card, CardBody, CardFooter, CardHeader, CardImg, Col, Container, Row }
import { dateFormat } from '../../../functions'
-import { GetBlogs, IGetBlogsResponse } from '../../../httpQueries/blogs'
-import { IBlogItemModel, IBlogItemsPaginationModel } from '../../../httpQueries/models'
+import { GetBlogCatalog, IGetBlogCatalogResponse } from '../../../controllers/blogCatalog'
+import { IBlogItemModel, IBlogItemsPaginationModel } from '../../../models'
import { Categories, Empty, Search } from '../SideWidgets'
@@ -38,8 +38,8 @@ const FeaturedBlog: FC = (props) => {
}
-const BlogPagination: FC = (props) => {
- const { items } = props
+const BlogItemsPagination: FC = (props) => {
+ const { items, currentPage, totalPages } = props
return <>
{items.map((item, index) =>
@@ -51,7 +51,7 @@ const BlogPagination: FC = (props) => {
{item.created}
{item.title}
{item.shortText}
- Read more →
+ Read more →
@@ -72,13 +72,11 @@ const BlogPagination: FC = (props) => {
>
}
-
-
const BlogCatalog = () => {
- const [state, setState] = useState()
+ const [state, setState] = useState()
useEffect(() => {
- GetBlogs().then(response => {
+ GetBlogCatalog().then(response => {
setState(response)
})
}, [])
@@ -98,7 +96,7 @@ const BlogCatalog = () => {
{state?.featuredBlog ? : ''}
- {state?.blogItemsPagination ? : '' }
+ {state?.blogItemsPagination ? : '' }
diff --git a/clientapp/src/pages/Blog/SideWidgets/index.tsx b/clientapp/src/pages/Blog/SideWidgets/index.tsx
index 1988137..8b1548a 100644
--- a/clientapp/src/pages/Blog/SideWidgets/index.tsx
+++ b/clientapp/src/pages/Blog/SideWidgets/index.tsx
@@ -1,6 +1,6 @@
import React from 'react'
import { Card, CardBody, CardHeader, Col, Row } from 'reactstrap'
-import { ICategoryModel } from '../../../httpQueries/models'
+import { ICategoryModel } from '../../../models'
const Search = () => {
return
diff --git a/clientapp/src/pages/Home/index.tsx b/clientapp/src/pages/Home/index.tsx
index 9880905..8f13ab4 100644
--- a/clientapp/src/pages/Home/index.tsx
+++ b/clientapp/src/pages/Home/index.tsx
@@ -1,8 +1,11 @@
import React, { FC } from 'react'
+import { useSelector } from 'react-redux'
import { Link } from 'react-router-dom'
import { Card, CardBody, CardFooter, CardImg, Col, Container, Row } from 'reactstrap'
import { FeatherIcon } from '../../components/FeatherIcons'
-import { IImage } from '../../interfaces'
+import { IPageModel, IBlogItemModel, IImageModel } from '../../models'
+import { ApplicationState } from '../../store'
+import { IContentState } from '../../store/reducers/Content'
import style from './scss/style.module.scss'
@@ -11,6 +14,42 @@ interface ITitleSection {
text: string
}
+interface IFeaturesSectionItem {
+ icon: string,
+ title: string,
+ text: string
+}
+interface IFeaturesSection {
+ title: string,
+ items: IFeaturesSectionItem [],
+}
+
+
+interface ITestimonialsSection {
+ text: string,
+ image: IImageModel
+}
+
+interface IFeaturedBlogsSection {
+ title: string,
+ text: string,
+ items: IBlogItemModel []
+}
+
+interface ICallToActionSection {
+ title: string,
+ text: string,
+ privacyDisclaimer: string
+}
+
+interface IHomePage extends IPageModel {
+ titleSection: ITitleSection,
+ featuresSection: IFeaturesSection,
+ testimonialsSection: ITestimonialsSection,
+ featuredBlogsSection: IFeaturedBlogsSection,
+ callToActionSection: ICallToActionSection
+}
+
const TitleSection : FC = (props) => {
const { title, text } = props
@@ -36,15 +75,7 @@ const TitleSection : FC = (props) => {
}
-interface IFeaturesSectionItem {
- icon: string,
- title: string,
- text: string
-}
-interface IFeaturesSection {
- title: string,
- items: IFeaturesSectionItem [],
-}
+
const FeaturesSection: FC = (props) => {
const { title, items } = props
@@ -72,10 +103,7 @@ const FeaturesSection: FC = (props) => {
}
-interface ITestimonialsSection {
- text: string,
- image: IImage
-}
+
const TestimonialsSection: FC = (props) => {
const { text, image } = props
@@ -98,28 +126,12 @@ const TestimonialsSection: FC = (props) => {
}
-interface IBlogAuthor {
- name: string,
- image: IImage
-}
-interface IBlogItem {
- image: IImage,
- badge: string,
- title: string,
- text: string,
- author: IBlogAuthor,
- date: string,
- readTime: string
-}
-interface IFromOurBlogSection {
- title: string,
- text: string,
- items: IBlogItem []
-}
-const FromOurBlogSection: FC = (props) => {
+
+
+const FromOurBlogSection: FC = (props) => {
const { title, text, items } = props
return
@@ -148,8 +160,8 @@ const FromOurBlogSection: FC = (props) => {
-
{item.author.name}
-
{item.date} · {item.readTime}
+
{item.author.nickName}
+
{item.created} · {item.readTime}
@@ -161,11 +173,7 @@ const FromOurBlogSection: FC = (props) => {
}
-interface ICallToActionSection {
- title: string,
- text: string,
- privacyDisclaimer: string
-}
+
const CallToActionSection: FC = (props) => {
const { title, text, privacyDisclaimer } = props
@@ -191,120 +199,16 @@ const CallToActionSection: FC = (props) => {
}
const Home = () => {
- const titleSection = {
- title: "Hello, world!",
- text: `
- Welcome to your new single-page application, built with:
-
- `
- }
+ const state = useSelector((state: ApplicationState) => state.content)
- const featuresSecton = {
- title: "To help you get started, we have also set up:",
- items: [
- {
- icon: "navigation",
- title: "Client-side navigation",
- text: "For example, click Counter then Back to return here."
- },
- {
- icon: "server",
- title: "Development server integration",
- text: "In development mode, the development server from create-react-app runs in the background automatically, so your client-side resources are dynamically built on demand and the page refreshes when you modify any file."
- },
- {
- icon: "terminal",
- title: "Efficient production builds",
- text: "In production mode, development-time features are disabled, and your dotnet publish configuration produces minified, efficiently bundled JavaScript files."
- }
- ]
- }
-
- const testimonialsSection = {
- text: "The ClientApp subdirectory is a standard React application based on the create-react-app template. If you open a command prompt in that directory, you can run yarn commands such as yarn test or yarn install.",
- image: {
- src: "https://dummyimage.com/40x40/ced4da/6c757d",
- alt: "..."
- }
- }
-
- const fromOurBlogSection = {
- title: "From our blog",
- text: "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad.",
- items: [
- {
- badge: "News",
- image: {
- src: "https://dummyimage.com/600x350/ced4da/6c757d",
- alt: "..."
- },
- title: "Blog post title",
- text: "Some quick example text to build on the card title and make up the bulk of the card's content.",
- author: {
- image: {
- src: "https://dummyimage.com/40x40/ced4da/6c757d",
- alt: "..."
- },
- name: "Kelly Rowan"
- },
- date: "March 12, 2022",
- readTime: "6 min read"
- },
- {
- badge: "News",
- image: {
- src: "https://dummyimage.com/600x350/ced4da/6c757d",
- alt: "..."
- },
- title: "Blog post title",
- text: "Some quick example text to build on the card title and make up the bulk of the card's content.",
- author: {
- image: {
- src: "https://dummyimage.com/40x40/ced4da/6c757d",
- alt: "..."
- },
- name: "Kelly Rowan"
- },
- date: "March 12, 2022",
- readTime: "6 min read"
- },
- {
- badge: "News",
- image: {
- src: "https://dummyimage.com/600x350/ced4da/6c757d",
- alt: "..."
- },
- title: "Blog post title",
- text: "Some quick example text to build on the card title and make up the bulk of the card's content.",
- author: {
- image: {
- src: "https://dummyimage.com/40x40/ced4da/6c757d",
- alt: "..."
- },
- name: "Kelly Rowan"
- },
- date: "March 12, 2022",
- readTime: "6 min read"
- }
- ]
- }
-
- const callToActionSection = {
- title: "New products, delivered to you.",
- text: "Sign up for our newsletter for the latest updates.",
- privacyDisclaimer: "We care about privacy, and will never share your data."
- }
+ const page = state?.pages?.filter(x => x.id == "HomePage").shift() as IHomePage
return <>
-
-
-
-
-
+ { page?.titleSection ? : '' }
+ { page?.featuresSection ? : '' }
+ { page?.testimonialsSection ? : '' }
+ { page?.featuredBlogsSection ? : '' }
+ { page?.callToActionSection ? :'' }
>
}
diff --git a/clientapp/src/pages/Shop/Catalog/index.tsx b/clientapp/src/pages/Shop/Catalog/index.tsx
index 86c1949..51e1937 100644
--- a/clientapp/src/pages/Shop/Catalog/index.tsx
+++ b/clientapp/src/pages/Shop/Catalog/index.tsx
@@ -1,9 +1,54 @@
-import * as React from 'react'
+import React, { FC, useEffect, useState } from 'react'
import { Link } from 'react-router-dom'
import { Card, CardBody, CardFooter, CardImg, Col, Container, Row } from 'reactstrap'
import { FeatherRating } from '../../../components/FeatherRating'
+import { IShopItemsPaginationModel } from '../../../models'
+import { IGetShopCatalogResponse, GetShopCatalog } from '../../../controllers/shopCatalog'
+
+
+const ShopItemsPagination: FC = (props) => {
+ const { items, currentPage, totalPages } = props
+
+ return
+
+
+ {items.map((item, index) =>
+
+ {item.badge}
+
+
+
+
+
+
+
+
{item.title}
+
+
+
+ {item.newPrice
+ ? <>{item.price} {item.newPrice}>
+ : item.price}
+
+
+
+
+
+
+
+
+
+ )}
+
+
+
+}
+
+
const ShopCatalog = () => {
const items = [
@@ -54,6 +99,14 @@ const ShopCatalog = () => {
}
]
+ const [state, setState] = useState()
+
+ useEffect(() => {
+ GetShopCatalog().then(response => {
+ setState(response)
+ })
+ }, [])
+
return <>
@@ -65,39 +118,7 @@ const ShopCatalog = () => {
-
-
-
- {items.map((item, index) =>
-
- Sale
-
-
-
-
-
-
Fancy Product
-
-
-
- {item.newPrice
- ? <>{item.price} {item.newPrice}>
- : item.price}
-
-
-
-
-
-
-
-
-
- )}
-
-
-
+ {state?.shopItemsPagination ? : ''}
>
}
diff --git a/clientapp/src/pages/index.tsx b/clientapp/src/pages/index.tsx
index 93d514b..07f3b11 100644
--- a/clientapp/src/pages/index.tsx
+++ b/clientapp/src/pages/index.tsx
@@ -12,7 +12,7 @@ import { ShopCatalog, ShopItem } from './Shop'
import { BlogCatalog, BlogItem } from './Blog'
interface IPages {
- [key: string]: React.FC;
+ [key: string]: FC;
}
const pages: IPages = {
diff --git a/clientapp/src/restClient.ts b/clientapp/src/restClient.ts
new file mode 100644
index 0000000..1adfb77
--- /dev/null
+++ b/clientapp/src/restClient.ts
@@ -0,0 +1,62 @@
+
+
+export interface IRequest {
+ [key: string]: string | undefined
+}
+
+interface IFetchResult {
+ status: number,
+ text: string
+}
+
+const Post = () => {
+
+}
+
+const Get = async (apiUrl: string, props?: IRequest): Promise => {
+ const url = new URL(apiUrl)
+
+ if(props) {
+ Object.keys(props).forEach(key => {
+ if (typeof(props[key]) !== undefined) {
+ url.searchParams.append(key, props[key] as string)
+ }
+ })
+ }
+
+ const requestParams = {
+ method: 'GET',
+ headers: { 'accept': 'application/json', 'content-type': 'application/json' },
+ }
+
+ const fetchData = await fetch(url.toString(), requestParams)
+ .then(async fetchData => {
+ return {
+ status: fetchData.status,
+ text: await fetchData.text()
+ }
+ })
+ .catch(err => {
+ console.log(err)
+ })
+
+ return JSON.parse((fetchData as IFetchResult).text) as TResponse
+}
+
+const Put = () => {
+
+}
+
+const Delete = () => {
+
+}
+
+export {
+ Post,
+ Get,
+ Put,
+ Delete
+}
+
+
+
diff --git a/clientapp/src/store/index.ts b/clientapp/src/store/index.ts
index 916c85c..b1a22e6 100644
--- a/clientapp/src/store/index.ts
+++ b/clientapp/src/store/index.ts
@@ -1,12 +1,12 @@
import * as WeatherForecasts from './reducers/WeatherForecasts'
import * as Counter from './reducers/Counter'
-import * as Settings from './reducers/Settings'
+import * as Content from './reducers/Content'
// The top-level state object
export interface ApplicationState {
counter: Counter.CounterState | undefined
weatherForecasts: WeatherForecasts.WeatherForecastsState | undefined
- settings: Settings.ISettingsState | undefined
+ content: Content.IContentState | undefined
}
// Whenever an action is dispatched, Redux will update each top-level application state property using
@@ -15,7 +15,7 @@ export interface ApplicationState {
export const reducers = {
counter: Counter.reducer,
weatherForecasts: WeatherForecasts.reducer,
- settings: Settings.reducer
+ content: Content.reducer
}
// This type can be used as a hint on action creators so that its 'dispatch' and 'getState' params are
diff --git a/clientapp/src/store/reducers/Content.ts b/clientapp/src/store/reducers/Content.ts
new file mode 100644
index 0000000..52c7d2f
--- /dev/null
+++ b/clientapp/src/store/reducers/Content.ts
@@ -0,0 +1,60 @@
+import { Action, Reducer } from 'redux'
+import { AppThunkAction } from '..'
+import { GetStaticContent, IGetStaticContentRequest, IGetStaticContetnResponse } from '../../controllers/staticContent'
+
+export interface IContentState extends IGetStaticContetnResponse {
+ isLoading: boolean
+}
+
+interface RequestAction extends IGetStaticContentRequest {
+ type: 'REQUEST_CONTENT'
+}
+
+interface ReceiveAction extends IGetStaticContetnResponse {
+ type: 'RECEIVE_CONTENT'
+}
+
+type KnownAction = RequestAction | ReceiveAction;
+
+export const actionCreators = {
+ requestContent: (): AppThunkAction => async (dispatch, getState) => {
+
+ dispatch({ type: 'REQUEST_CONTENT' })
+
+ var fetchData = await GetStaticContent()
+ console.log(fetchData)
+
+ dispatch({ type: 'RECEIVE_CONTENT', ...fetchData })
+ }
+}
+
+const unloadedState: IContentState = {
+ siteName: "MAKS-IT",
+ routes: [
+ { target: "/", component: "Home" }
+ ],
+ isLoading: false
+}
+
+export const reducer: Reducer = (state: IContentState | undefined, incomingAction: Action): IContentState => {
+ if (state === undefined) {
+ return unloadedState
+ }
+
+ const action = incomingAction as KnownAction
+ switch (action.type) {
+ case 'REQUEST_CONTENT':
+ return {
+ ...state,
+ isLoading: true
+ }
+
+ case 'RECEIVE_CONTENT':
+ return {
+ ...action,
+ isLoading: false
+ }
+ }
+
+ return state
+}
\ No newline at end of file
diff --git a/clientapp/src/store/reducers/Settings.ts b/clientapp/src/store/reducers/Settings.ts
deleted file mode 100644
index efe0ad9..0000000
--- a/clientapp/src/store/reducers/Settings.ts
+++ /dev/null
@@ -1,211 +0,0 @@
-import { Action, Reducer } from 'redux'
-import { AppThunkAction } from '../'
-import { IMenuItem, IRoute } from '../../interfaces'
-
-export interface ISettingsState {
- siteName: string,
- routes: IRoute [],
- adminRoutes: IRoute [],
- serviceRoutes: IRoute [],
- sideMenu?: IMenuItem [],
- topMenu?: IMenuItem [],
- isLoading: boolean
-}
-
-interface RequestSettingsAction {
- type: 'REQUEST_SETTINGS'
-}
-
-interface ReceiveSettingsAction {
- type: 'RECEIVE_SETTINGS',
- siteName: string,
- routes: IRoute [],
- adminRoutes: IRoute [],
- serviceRoutes: IRoute [],
- sideMenu?: IMenuItem [],
- topMenu?: IMenuItem [],
-}
-
-type KnownAction = RequestSettingsAction | ReceiveSettingsAction;
-
-export const actionCreators = {
- requestSettings: (): AppThunkAction => (dispatch, getState) => {
-
- dispatch({ type: 'REQUEST_SETTINGS' })
-
- const appState = getState()
-
- const siteName = "MAKS-IT"
-
- const routes : IRoute[] = [
- { path: "/", component: "Home" },
- { path: "/home", component: "Home" },
- { path: "/shop",
- childRoutes: [
- {
- path: "",
- component: "ShopCatalog"
- },
- {
- path: ":page",
- childRoutes: [
- {
- path: ":slug",
- component: "ShopItem"
- }
- ]
- }
- ]
- },
-
- {
- path: "/blog",
- childRoutes: [
- {
- path: "",
- component: "BlogCatalog"
- },
- {
- path: ":page",
- component: "BlogCatalog"
- },
- {
- path: ":page",
- childRoutes: [
- {
- path: ":slug",
- component: "BlogItem"
- }
- ]
- }
- ]
- }
- ]
-
- const adminRoutes : IRoute [] = [
- { path: "/admin", component: "AdminHome" },
-
- { path: "/counter", component: "Counter" },
- { path: "/fetch-data", component: "FetchData",
- childRoutes: [
- {
- path: ":startDateIndex",
- component: "FetchData"
- }
- ]
- }
- ]
-
- const serviceRoutes : IRoute[] = [
- { path: "/signin", component: "Signin" },
- { path: "/signup", component: "Signup" }
- ]
-
- const sideMenu : IMenuItem [] = [
- {
- icon: "alert-triangle",
- title: "Home",
- target: "/admin"
- },
- {
- icon: "activity",
- title: "Page",
- items: [
- {
- icon: "activity",
- title: "Page 1",
- target: "/Page-1",
- },
- {
- icon: "activity",
- title: "Page 2",
- target: "/Page-2",
- },
- ]
- },
- {
- icon: "",
- title: "Counter",
- target: "/counter",
- },
- {
- icon: "",
- title: "Fetch data",
- target: "/fetch-data"
- },
- ]
-
- const topMenu : IMenuItem [] = [
- {
- icon: "",
- title: "Home",
- target: "/"
- },
- {
- icon: "",
- title: "Shop",
- target: "/shop",
- },
- {
- icon: "",
- title: "Blog",
- target: "/blog"
- },
- {
- icon: "",
- title: "Signin",
- target: "/signin"
- },
- {
- icon: "",
- title: "Signout",
- target: "/signout"
- }
- ]
-
- dispatch({ type: 'RECEIVE_SETTINGS', siteName, routes, adminRoutes, serviceRoutes, sideMenu, topMenu })
- }
-}
-
-const unloadedState: ISettingsState = {
- siteName: "reactredux",
- routes: [],
- adminRoutes: [],
- serviceRoutes: [],
- sideMenu: [],
- topMenu: [],
- isLoading: false
-}
-
-export const reducer: Reducer = (state: ISettingsState | undefined, incomingAction: Action): ISettingsState => {
- if (state === undefined) {
- return unloadedState
- }
-
- const action = incomingAction as KnownAction
- switch (action.type) {
- case 'REQUEST_SETTINGS':
- return {
- siteName: state.siteName,
- routes: state.routes,
- adminRoutes: state.adminRoutes,
- serviceRoutes: state.serviceRoutes,
- sideMenu: state.sideMenu,
- topMenu: state.topMenu,
- isLoading: true
- }
-
- case 'RECEIVE_SETTINGS':
- return {
- siteName: action.siteName,
- routes: action.routes,
- adminRoutes: action.adminRoutes,
- serviceRoutes: action.serviceRoutes,
- sideMenu: action.sideMenu,
- topMenu: action.topMenu,
- isLoading: false
- }
- }
-
- return state
-}
\ No newline at end of file
diff --git a/webapi/WeatherForecast/Controllers/BlogsController.cs b/webapi/WeatherForecast/Controllers/BlogCatalogController.cs
similarity index 88%
rename from webapi/WeatherForecast/Controllers/BlogsController.cs
rename to webapi/WeatherForecast/Controllers/BlogCatalogController.cs
index 42e5682..2d6d909 100644
--- a/webapi/WeatherForecast/Controllers/BlogsController.cs
+++ b/webapi/WeatherForecast/Controllers/BlogCatalogController.cs
@@ -9,7 +9,7 @@ using Core.Abstractions.Models;
namespace WeatherForecast.Controllers;
#region Input models
-public class GetBlogsResponse : ResponseModel {
+public class GetBlogCatalogResponse : ResponseModel {
public BlogItemModel FeaturedBlog { get; set; }
@@ -23,11 +23,11 @@ public class GetBlogsResponse : ResponseModel {
[AllowAnonymous]
[ApiController]
[Route("api/[controller]")]
-public class BlogsController : ControllerBase {
+public class BlogCatalogController : ControllerBase {
private readonly ILogger _logger;
- public BlogsController(ILogger logger) {
+ public BlogCatalogController(ILogger logger) {
_logger = logger;
}
@@ -48,15 +48,17 @@ public class BlogsController : ControllerBase {
Badge = "news",
Title = "Blog post title",
ShortText = "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...",
+ Text = "",
Author = new AuthorModel {
Id = Guid.NewGuid(),
Image = new ImageModel { Src = "https://dummyimage.com/40x40/ced4da/6c757d", Alt = "..." },
NickName = "Admin"
},
Created = DateTime.UtcNow,
+ Tags = new List { "react", "redux", "webapi" },
+
ReadTime = 10,
Likes = 200,
- Tags = new List { "react", "redux", "webapi" }
};
var blogModels = new List();
@@ -64,7 +66,7 @@ public class BlogsController : ControllerBase {
blogModels.Add(blogItemModel);
}
- var blogResponse = new GetBlogsResponse {
+ var blogCatalogResponse = new GetBlogCatalogResponse {
FeaturedBlog = blogItemModel,
BlogItemsPagination = new PaginationModel {
CurrentPage = currentPage,
@@ -101,7 +103,7 @@ public class BlogsController : ControllerBase {
- return Ok(blogResponse);
+ return Ok(blogCatalogResponse);
}
}
diff --git a/webapi/WeatherForecast/Controllers/ShopCatalog.cs b/webapi/WeatherForecast/Controllers/ShopCatalog.cs
deleted file mode 100644
index fe4c350..0000000
--- a/webapi/WeatherForecast/Controllers/ShopCatalog.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using Core.Abstractions.Models;
-using Core.Models;
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-using WeatherForecast.Models;
-
-namespace WeatherForecast.Controllers;
-
-#region Response models
-public class GetShopCatalogResponse : ResponseModel {
-
- public PaginationModel ShopItemsPagination { get; set; }
-}
-#endregion
-
-[AllowAnonymous]
-[ApiController]
-[Route("api/[controller]")]
-public class ShopCatalog : ControllerBase {
-
- private readonly ILogger _logger;
-
- public ShopCatalog(ILogger logger) {
- _logger = logger;
- }
-
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- [HttpGet]
- public IActionResult Get([FromQuery] Guid? category, [FromQuery] string? searchText, [FromQuery] int currentPage = 1, [FromQuery] int itemsPerPage = 4) {
- var shopItemModel = new ShopItemModel {
-
-
- };
-
-
-
-
- return Ok();
- }
-}
diff --git a/webapi/WeatherForecast/Controllers/ShopCatalogController.cs b/webapi/WeatherForecast/Controllers/ShopCatalogController.cs
new file mode 100644
index 0000000..5e236d0
--- /dev/null
+++ b/webapi/WeatherForecast/Controllers/ShopCatalogController.cs
@@ -0,0 +1,77 @@
+using Core.Abstractions.Models;
+using Core.Models;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using WeatherForecast.Models;
+
+namespace WeatherForecast.Controllers;
+
+#region Response models
+public class GetShopCatalogResponse : ResponseModel {
+
+ public PaginationModel ShopItemsPagination { get; set; }
+}
+#endregion
+
+[AllowAnonymous]
+[ApiController]
+[Route("api/[controller]")]
+public class ShopCatalogController : ControllerBase {
+
+ private readonly ILogger _logger;
+
+ public ShopCatalogController(ILogger logger) {
+ _logger = logger;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HttpGet]
+ public IActionResult Get([FromQuery] Guid? category, [FromQuery] string? searchText, [FromQuery] int currentPage = 1, [FromQuery] int itemsPerPage = 8) {
+
+ var shopModels = new List();
+ for (int i = 0; i < 8; i++) {
+ var shopItemModel = new ShopItemModel {
+ Id = Guid.NewGuid(),
+ Slug = "shop-catalog-item",
+ Image = new ImageModel { Src = "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", Alt = "..." },
+ Badge = "sale",
+ Title = "Shop item title",
+
+ ShortText = "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...",
+ Text = "",
+ Author = new AuthorModel {
+ Id = Guid.NewGuid(),
+ Image = new ImageModel { Src = "https://dummyimage.com/40x40/ced4da/6c757d", Alt = "..." },
+ NickName = "Admin"
+ },
+ Created = DateTime.UtcNow,
+
+ Tags = new List { "react", "redux", "webapi" },
+
+ Rating = 4.5,
+ Price = 20,
+ NewPrice = 10
+ };
+
+ shopModels.Add(shopItemModel);
+ }
+
+ var shopCatalogResponse = new GetShopCatalogResponse {
+ ShopItemsPagination = new PaginationModel {
+ CurrentPage = currentPage,
+ TotalPages = 100,
+ Items = shopModels
+ }
+ };
+
+
+ return Ok(shopCatalogResponse);
+ }
+}
diff --git a/webapi/WeatherForecast/Controllers/StaticContentController.cs b/webapi/WeatherForecast/Controllers/StaticContentController.cs
new file mode 100644
index 0000000..9ddaad9
--- /dev/null
+++ b/webapi/WeatherForecast/Controllers/StaticContentController.cs
@@ -0,0 +1,215 @@
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using WeatherForecast.Models;
+
+namespace WeatherForecast.Controllers;
+
+///
+///
+///
+[ApiController]
+[AllowAnonymous]
+[Route("api/[controller]")]
+public class StaticContentController : ControllerBase {
+
+ private readonly ILogger _logger;
+
+ ///
+ ///
+ ///
+ ///
+ public StaticContentController(
+ ILogger logger
+ ) {
+ _logger = logger;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ [HttpGet]
+ public IActionResult Get([FromQuery] string? locale = "en-US") {
+
+ var routes = new List {
+ new RouteModel ("/", "Home"),
+ new RouteModel ("/home", "Home")
+ };
+
+ var shopRoute = new RouteModel("/shop",
+ new List {
+ new RouteModel ("", "ShopCatalog"),
+ new RouteModel (":page", "ShopCatalog"),
+ new RouteModel (":page", new List {
+ new RouteModel (":slug", "ShopItem")
+ })
+ });
+
+ var blogRoute = new RouteModel("/blog",
+ new List {
+ new RouteModel ("", "BlogCatalog"),
+ new RouteModel (":page", "BlogCatalog"),
+ new RouteModel (":page", new List {
+ new RouteModel (":slug", "BlogItem")
+ })
+ });
+
+ routes.Add(shopRoute);
+ routes.Add(blogRoute);
+
+ var demoRoutes = new List {
+ new RouteModel ("/counter", "Counter"),
+ new RouteModel ("/fetch-data", new List {
+ new RouteModel ("", "FetchData"),
+ new RouteModel (":startDateIndex", "FetchData")
+ })
+ };
+
+ routes = routes.Concat(demoRoutes).ToList();
+
+ var adminRoutes = new List {
+ new RouteModel ("/admin", "AdminHome")
+ };
+
+ var serviceRoutes = new List {
+ new RouteModel ("/signin", "Signin"),
+ new RouteModel ("/signup", "Signup"),
+ new RouteModel ("*", "Error")
+ };
+
+ var topMenu = new List {
+ new MenuItemModel ("Home", "/"),
+ new MenuItemModel ("Shop", "/shop"),
+ new MenuItemModel ("Blog", "/blog"),
+ new MenuItemModel ("Signin", "/signin"),
+ new MenuItemModel ("Sognout", "/signout")
+ };
+
+ var sideMenu = new List {
+ new MenuItemModel ("alert-triangle", "Home", "/admin"),
+ new MenuItemModel ("activity", "Page", new List {
+ new MenuItemModel ("activity", "Page-1", "Page-1"),
+ new MenuItemModel ("activity", "Page-2", "Page-2"),
+ new MenuItemModel ("activity", "Page-3", "Page-3")
+ }),
+ new MenuItemModel ("Counter", "/counter"),
+ new MenuItemModel ("Fetch data", "/fetch-data")
+ };
+
+
+
+
+ var blogItems = new List();
+ for (int i = 0; i < 3; i++) {
+ var blogItemModel = new BlogItemModel {
+ Id = Guid.NewGuid(),
+ Slug = "blog-post-title",
+ Image = new ImageModel { Src = "https://dummyimage.com/600x350/ced4da/6c757d", Alt = "..." },
+ Badge = "news",
+ Title = "Blog post title",
+ ShortText = "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...",
+ Text = "",
+ Author = new AuthorModel {
+ Id = Guid.NewGuid(),
+ Image = new ImageModel { Src = "https://dummyimage.com/40x40/ced4da/6c757d", Alt = "..." },
+ NickName = "Admin"
+ },
+ Created = DateTime.UtcNow,
+ Tags = new List { "react", "redux", "webapi" },
+
+ ReadTime = 10,
+ Likes = 200,
+ };
+
+ blogItems.Add(blogItemModel);
+ }
+
+
+ var pages = new List