Added ShopPanel to home sidebar
• Added: - ShopPanel to home sidebar - DIssenter shop redux, api route/controller
This commit is contained in:
parent
0ca346b169
commit
095e646661
33
app/controllers/api/v1/shop_controller.rb
Normal file
33
app/controllers/api/v1/shop_controller.rb
Normal 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
|
47
app/javascript/gabsocial/actions/shop.js
Normal file
47
app/javascript/gabsocial/actions/shop.js
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
102
app/javascript/gabsocial/components/panel/shop_panel.js
Normal file
102
app/javascript/gabsocial/components/panel/shop_panel.js
Normal 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>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -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} />
|
||||||
|
@ -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,
|
||||||
|
41
app/javascript/gabsocial/reducers/shop.js
Normal file
41
app/javascript/gabsocial/reducers/shop.js
Normal 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
|
||||||
|
}
|
||||||
|
}
|
@ -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]
|
||||||
|
Loading…
Reference in New Issue
Block a user