Added ShopPanel to home sidebar

• Added:
- ShopPanel to home sidebar
- DIssenter shop redux, api route/controller
This commit is contained in:
mgabdev 2020-07-01 21:33:10 -04:00
parent 0ca346b169
commit 095e646661
7 changed files with 228 additions and 0 deletions

View File

@ -0,0 +1,33 @@
# frozen_string_literal: true
class Api::V1::ShopController < Api::BaseController
before_action :require_user!
respond_to :json
skip_before_action :set_cache_headers
def index
type = params[:type]
if type == 'featured_products'
body = Redis.current.get("gabstore:featuredproducts")
if body.nil?
uri = URI("https://shop.dissenter.com/product/group/json")
uri.query = URI.encode_www_form({})
res = Net::HTTP.get_response(uri)
if res.is_a?(Net::HTTPSuccess)
body = res.body
Redis.current.set("gabstore:featuredproducts", res.body)
Redis.current.expire("gabstore:featuredproducts", 15.minutes.seconds)
end
end
render json: body
else
raise GabSocial::NotPermittedError
end
end
end

View File

@ -0,0 +1,47 @@
import api from '../api'
import { me } from '../initial_state'
export const SHOP_FEATURED_PRODUCTS_FETCH_REQUEST = 'SHOP_FEATURED_PRODUCTS_FETCH_REQUEST'
export const SHOP_FEATURED_PRODUCTS_FETCH_SUCCESS = 'SHOP_FEATURED_PRODUCTS_FETCH_SUCCESS'
export const SHOP_FEATURED_PRODUCTS_FETCH_FAIL = 'SHOP_FEATURED_PRODUCTS_FETCH_FAIL'
export const fetchFeaturedProducts = () => {
return function (dispatch, getState) {
if (!me) return
dispatch(fetchFeaturedProductsRequest('featured'))
api(getState).get(`/api/v1/shop?type=featured_products`).then((response) => {
try {
dispatch(fetchFeaturedProductsSuccess(response.data.data, 'featured'))
} catch (error) {
//
}
}).catch(function (error) {
dispatch(fetchFeaturedProductsFail(error, 'featured'))
})
}
}
function fetchFeaturedProductsRequest(listType) {
return {
type: SHOP_FEATURED_PRODUCTS_FETCH_REQUEST,
listType,
}
}
function fetchFeaturedProductsSuccess(items, listType) {
return {
type: SHOP_FEATURED_PRODUCTS_FETCH_SUCCESS,
items,
listType,
}
}
function fetchFeaturedProductsFail(error, listType) {
return {
type: SHOP_FEATURED_PRODUCTS_FETCH_FAIL,
error,
listType,
}
}

View File

@ -0,0 +1,102 @@
import { defineMessages, injectIntl } from 'react-intl'
import { fetchFeaturedProducts } from '../../actions/shop'
import PanelLayout from './panel_layout'
import Image from '../image'
import Text from '../text'
const messages = defineMessages({
title: { id: 'shop_panel.title', defaultMessage: 'Dissenter Shop' },
shop_now: { id: 'shop_panel.shop_now', defaultMessage: 'Visit the Dissenter Shop' },
})
const mapStateToProps = (state) => ({
items: state.getIn(['shop', 'featured', 'items']),
isError: state.getIn(['shop', 'featured', 'isError']),
})
const mapDispatchToProps = (dispatch) => ({
onFetchFeaturedProducts: () => dispatch(fetchFeaturedProducts()),
})
export default
@connect(mapStateToProps, mapDispatchToProps)
@injectIntl
class ShopPanel extends PureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
products: PropTypes.array,
isLazy: PropTypes.bool,
onFetchFeaturedProducts: PropTypes.func.isRequired,
isError: PropTypes.bool.isRequired,
}
state = {
fetched: !this.props.isLazy,
}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.shouldLoad && !prevState.fetched) {
return { fetched: true }
}
return null
}
componentDidUpdate(prevProps, prevState) {
if (!prevState.fetched && this.state.fetched) {
this.props.onFetchFeaturedProducts()
}
}
componentDidMount() {
if (!this.props.isLazy) {
this.props.onFetchFeaturedProducts()
}
}
render() {
const {
intl,
items,
isError,
} = this.props
if (!items || isError || !Array.isArray(items)) return null
return (
<PanelLayout
noPadding
title={intl.formatMessage(messages.title)}
footerButtonTitle={intl.formatMessage(messages.shop_now)}
footerButtonTo='/'
>
<div className={[_s.default, _s.flexRow, _s.flexWrap, _s.pl5, _s.pt5].join(' ')}>
{
items.map((block) => (
<a
className={[_s.default, _s.width50PC, _s.noUnderline, _s.overflowHidden, _s.cursorPointer, _s.pb5, _s.pr5].join(' ')}
target='_blank'
rel='noreferrer noopener'
href={block.link}
title={block.name}
>
<Image
src={block.image}
className={[_s.width100PC, _s.height122PX].join(' ')}
/>
<Text
align='center'
className={[_s.py10, _s.px10].join(' ')}
>
{block.name}
</Text>
</a>
))
}
</div>
</PanelLayout>
)
}
}

View File

@ -9,6 +9,7 @@ import GroupsPanel from '../components/panel/groups_panel'
import ListsPanel from '../components/panel/lists_panel' import ListsPanel from '../components/panel/lists_panel'
import LinkFooter from '../components/link_footer' import LinkFooter from '../components/link_footer'
import WhoToFollowPanel from '../components/panel/who_to_follow_panel' import WhoToFollowPanel from '../components/panel/who_to_follow_panel'
import ShopPanel from '../components/panel/shop_panel'
import ProgressPanel from '../components/panel/progress_panel' import ProgressPanel from '../components/panel/progress_panel'
import ProPanel from '../components/panel/pro_panel' import ProPanel from '../components/panel/pro_panel'
import UserPanel from '../components/panel/user_panel' import UserPanel from '../components/panel/user_panel'
@ -103,6 +104,7 @@ class HomePage extends PureComponent {
<ProgressPanel /> <ProgressPanel />
<ProPanel isPro={isPro} /> <ProPanel isPro={isPro} />
<TrendsPanel /> <TrendsPanel />
<ShopPanel isLazy shouldLoad={lazyLoaded} />
<ListsPanel isLazy shouldLoad={lazyLoaded} /> <ListsPanel isLazy shouldLoad={lazyLoaded} />
<WhoToFollowPanel isLazy shouldLoad={lazyLoaded} /> <WhoToFollowPanel isLazy shouldLoad={lazyLoaded} />
<GroupsPanel isLazy shouldLoad={lazyLoaded} /> <GroupsPanel isLazy shouldLoad={lazyLoaded} />

View File

@ -29,6 +29,7 @@ import relationships from './relationships'
import reports from './reports' import reports from './reports'
import search from './search' import search from './search'
import settings from './settings' import settings from './settings'
import shop from './shop'
import sidebar from './sidebar' import sidebar from './sidebar'
import statuses from './statuses' import statuses from './statuses'
import status_lists from './status_lists' import status_lists from './status_lists'
@ -69,6 +70,7 @@ const reducers = {
reports, reports,
search, search,
settings, settings,
shop,
sidebar, sidebar,
statuses, statuses,
status_lists, status_lists,

View File

@ -0,0 +1,41 @@
import {
SHOP_FEATURED_PRODUCTS_FETCH_REQUEST,
SHOP_FEATURED_PRODUCTS_FETCH_SUCCESS,
SHOP_FEATURED_PRODUCTS_FETCH_FAIL,
} from '../actions/shop'
import {
Map as ImmutableMap,
List as ImmutableList,
fromJS,
} from 'immutable'
const initialState = ImmutableMap({
featured: ImmutableMap({
items: ImmutableList(),
isError: false,
isLoading: false,
}),
})
export default function suggestionsReducer(state = initialState, action) {
switch(action.type) {
case SHOP_FEATURED_PRODUCTS_FETCH_REQUEST:
return state.withMutations((map) => {
map.setIn([action.listType, 'isError'], false)
map.setIn([action.listType, 'isLoading'], true)
})
case SHOP_FEATURED_PRODUCTS_FETCH_SUCCESS:
return state.withMutations((map) => {
map.setIn([action.listType, 'items'], action.items)
map.setIn([action.listType, 'isError'], false)
map.setIn([action.listType, 'isLoading'], false)
})
case SHOP_FEATURED_PRODUCTS_FETCH_FAIL:
return state.withMutations((map) => {
map.setIn([action.listType, 'isError'], true)
map.setIn([action.listType, 'isLoading'], false)
})
default:
return state
}
}

View File

@ -327,6 +327,7 @@ Rails.application.routes.draw do
end end
resources :gab_trends, only: [:index] resources :gab_trends, only: [:index]
resources :shop, only: [:index]
resources :streaming, only: [:index] resources :streaming, only: [:index]
resources :custom_emojis, only: [:index] resources :custom_emojis, only: [:index]
resources :suggestions, only: [:index, :destroy] resources :suggestions, only: [:index, :destroy]