mirror of
https://github.com/oceanprotocol/commons.git
synced 2023-03-15 18:03:00 +01:00
channel teaser component, use on channels page
This commit is contained in:
parent
1000185841
commit
1b7d343984
@ -6,7 +6,7 @@ import cx from 'classnames'
|
|||||||
import styles from './Asset.module.scss'
|
import styles from './Asset.module.scss'
|
||||||
import CategoryImage from '../atoms/CategoryImage'
|
import CategoryImage from '../atoms/CategoryImage'
|
||||||
|
|
||||||
const AssetLink = ({
|
const Asset = ({
|
||||||
asset,
|
asset,
|
||||||
list,
|
list,
|
||||||
minimal
|
minimal
|
||||||
@ -55,4 +55,4 @@ const AssetLink = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AssetLink
|
export default Asset
|
||||||
|
56
client/src/components/organisms/ChannelTeaser.module.scss
Normal file
56
client/src/components/organisms/ChannelTeaser.module.scss
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
@import '../../styles/variables';
|
||||||
|
|
||||||
|
.channel {
|
||||||
|
width: 100%;
|
||||||
|
padding-top: $spacer * 2;
|
||||||
|
|
||||||
|
@media (min-width: $break-point--medium) {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
> div {
|
||||||
|
&:first-child {
|
||||||
|
margin-right: $spacer;
|
||||||
|
margin-bottom: $spacer;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $break-point--medium) {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
flex: 0 0 24.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: $font-size-h4;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ .channel {
|
||||||
|
border-top: 1px solid $brand-grey-lighter;
|
||||||
|
margin-top: $spacer * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.channelTitle {
|
||||||
|
margin-top: $spacer * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channelResults {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-gap: $spacer;
|
||||||
|
|
||||||
|
@media (min-width: $break-point--small) {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
> article {
|
||||||
|
min-width: calc(18rem + #{$spacer * 2.3});
|
||||||
|
}
|
||||||
|
}
|
98
client/src/components/organisms/ChannelTeaser.tsx
Normal file
98
client/src/components/organisms/ChannelTeaser.tsx
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import React, { Component } from 'react'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
import { User } from '../../context'
|
||||||
|
import { Logger } from '@oceanprotocol/squid'
|
||||||
|
import Spinner from '../atoms/Spinner'
|
||||||
|
import Asset from '../molecules/Asset'
|
||||||
|
import styles from './ChannelTeaser.module.scss'
|
||||||
|
import channels from '../../data/channels.json'
|
||||||
|
|
||||||
|
interface ChannelTeaserProps {
|
||||||
|
channel: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ChannelTeaserState {
|
||||||
|
channelAssets?: any[]
|
||||||
|
isLoadingChannel?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class ChannelTeaser extends Component<
|
||||||
|
ChannelTeaserProps,
|
||||||
|
ChannelTeaserState
|
||||||
|
> {
|
||||||
|
public static contextType = User
|
||||||
|
|
||||||
|
// Get channel content
|
||||||
|
public channel = channels.items
|
||||||
|
.filter(({ slug }) => slug === this.props.channel)
|
||||||
|
.map(channel => channel)[0]
|
||||||
|
|
||||||
|
public state = {
|
||||||
|
channelAssets: [],
|
||||||
|
isLoadingChannel: true
|
||||||
|
}
|
||||||
|
|
||||||
|
public async componentDidMount() {
|
||||||
|
this.getChannelAssets()
|
||||||
|
}
|
||||||
|
|
||||||
|
private getChannelAssets = async () => {
|
||||||
|
const { ocean } = this.context
|
||||||
|
|
||||||
|
const searchQuery = {
|
||||||
|
offset: 4,
|
||||||
|
page: 1,
|
||||||
|
query: {
|
||||||
|
// TODO: replace dummy category
|
||||||
|
// categories: [this.channel.title],
|
||||||
|
categories: ['Engineering'],
|
||||||
|
price: [-1, 1]
|
||||||
|
},
|
||||||
|
sort: {
|
||||||
|
datePublished: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const search = await ocean.aquarius.queryMetadata(searchQuery)
|
||||||
|
this.setState({
|
||||||
|
channelAssets: search.results,
|
||||||
|
isLoadingChannel: false
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
Logger.error(error.message)
|
||||||
|
this.setState({ isLoadingChannel: false })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
const { channelAssets, isLoadingChannel } = this.state
|
||||||
|
const { title, slug, teaser } = this.channel
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.channel}>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<h2 className={styles.channelTitle}>
|
||||||
|
<Link to={`/channels/${slug}`}>{title} →</Link>
|
||||||
|
</h2>
|
||||||
|
<p>{teaser}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{isLoadingChannel ? (
|
||||||
|
<Spinner message="Loading..." />
|
||||||
|
) : channelAssets && channelAssets.length ? (
|
||||||
|
<div className={styles.channelResults}>
|
||||||
|
{channelAssets.map((asset: any) => (
|
||||||
|
<Asset key={asset.id} asset={asset} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div>No data sets found.</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@
|
|||||||
{
|
{
|
||||||
"title": "Test Channel",
|
"title": "Test Channel",
|
||||||
"slug": "test-channel",
|
"slug": "test-channel",
|
||||||
|
"teaser": "Hello teaser.",
|
||||||
"description": "Hello description."
|
"description": "Hello description."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
15
client/src/routes/Channels.test.tsx
Normal file
15
client/src/routes/Channels.test.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { BrowserRouter as Router } from 'react-router-dom'
|
||||||
|
import { render } from 'react-testing-library'
|
||||||
|
import Channels from './Channels'
|
||||||
|
|
||||||
|
describe('Channels', () => {
|
||||||
|
it('renders without crashing', () => {
|
||||||
|
const { container } = render(
|
||||||
|
<Router>
|
||||||
|
<Channels />
|
||||||
|
</Router>
|
||||||
|
)
|
||||||
|
expect(container.firstChild).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
})
|
@ -2,22 +2,19 @@ import React, { Component } from 'react'
|
|||||||
import Route from '../components/templates/Route'
|
import Route from '../components/templates/Route'
|
||||||
import Content from '../components/atoms/Content'
|
import Content from '../components/atoms/Content'
|
||||||
import channels from '../data/channels.json'
|
import channels from '../data/channels.json'
|
||||||
import { Link } from 'react-router-dom'
|
import ChannelTeaser from '../components/organisms/ChannelTeaser'
|
||||||
|
|
||||||
class Channels extends Component {
|
class Channels extends Component {
|
||||||
public render() {
|
public render() {
|
||||||
return (
|
return (
|
||||||
<Route title={channels.title} description={channels.description}>
|
<Route title={channels.title} description={channels.description}>
|
||||||
<Content>
|
<Content wide>
|
||||||
<ul>
|
{channels.items.map(channel => (
|
||||||
{channels.items.map(channel => (
|
<ChannelTeaser
|
||||||
<li key={channel.title}>
|
key={channel.title}
|
||||||
<Link to={`/channels/${channel.slug}`}>
|
channel={channel.slug}
|
||||||
{channel.title}
|
/>
|
||||||
</Link>
|
))}
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</Content>
|
</Content>
|
||||||
</Route>
|
</Route>
|
||||||
)
|
)
|
||||||
|
@ -14,56 +14,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.channel {
|
|
||||||
width: 100%;
|
|
||||||
padding-top: $spacer * 2;
|
|
||||||
|
|
||||||
@media (min-width: $break-point--medium) {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
> div {
|
|
||||||
&:first-child {
|
|
||||||
margin-right: $spacer;
|
|
||||||
margin-bottom: $spacer;
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: $break-point--medium) {
|
|
||||||
flex: 1;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
flex: 0 0 24.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: $font-size-h4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.channelTitle {
|
|
||||||
margin-top: $spacer * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.channelResults {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
grid-gap: $spacer;
|
|
||||||
|
|
||||||
@media (min-width: $break-point--small) {
|
|
||||||
grid-template-columns: repeat(2, 1fr);
|
|
||||||
}
|
|
||||||
|
|
||||||
> article {
|
|
||||||
min-width: calc(18rem + #{$spacer * 2.3});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-size: $font-size-h3;
|
font-size: $font-size-h3;
|
||||||
margin-top: $spacer * 2;
|
margin-top: $spacer * 2;
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
import React, { ChangeEvent, Component, FormEvent } from 'react'
|
import React, { ChangeEvent, Component, FormEvent } from 'react'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import { User, Market } from '../context'
|
import { User, Market } from '../context'
|
||||||
import { Logger } from '@oceanprotocol/squid'
|
|
||||||
import Spinner from '../components/atoms/Spinner'
|
|
||||||
import Asset from '../components/molecules/Asset'
|
|
||||||
import CategoryImage from '../components/atoms/CategoryImage'
|
import CategoryImage from '../components/atoms/CategoryImage'
|
||||||
import Button from '../components/atoms/Button'
|
import Button from '../components/atoms/Button'
|
||||||
import Form from '../components/atoms/Form/Form'
|
import Form from '../components/atoms/Form/Form'
|
||||||
@ -14,14 +11,8 @@ import styles from './Home.module.scss'
|
|||||||
import meta from '../data/meta.json'
|
import meta from '../data/meta.json'
|
||||||
import { History } from 'history'
|
import { History } from 'history'
|
||||||
import Content from '../components/atoms/Content'
|
import Content from '../components/atoms/Content'
|
||||||
import channels from '../data/channels.json'
|
|
||||||
import AssetsLatest from '../components/organisms/AssetsLatest'
|
import AssetsLatest from '../components/organisms/AssetsLatest'
|
||||||
|
import ChannelTeaser from '../components/organisms/ChannelTeaser'
|
||||||
// AI for Good channel
|
|
||||||
const channel = channels.items
|
|
||||||
.filter(({ slug }) => slug === 'ai-for-good')
|
|
||||||
.map(channel => channel)[0]
|
|
||||||
const { title, slug, teaser } = channel
|
|
||||||
|
|
||||||
interface HomeProps {
|
interface HomeProps {
|
||||||
history: History
|
history: History
|
||||||
@ -29,50 +20,13 @@ interface HomeProps {
|
|||||||
|
|
||||||
interface HomeState {
|
interface HomeState {
|
||||||
search?: string
|
search?: string
|
||||||
channelAssets?: any[]
|
|
||||||
isLoadingChannel?: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Home extends Component<HomeProps, HomeState> {
|
export default class Home extends Component<HomeProps, HomeState> {
|
||||||
public static contextType = User
|
public static contextType = User
|
||||||
|
|
||||||
public state = {
|
public state = {
|
||||||
search: '',
|
search: ''
|
||||||
channelAssets: [],
|
|
||||||
isLoadingChannel: true
|
|
||||||
}
|
|
||||||
|
|
||||||
public async componentDidMount() {
|
|
||||||
this.getChannelAssets()
|
|
||||||
}
|
|
||||||
|
|
||||||
private getChannelAssets = async () => {
|
|
||||||
const { ocean } = this.context
|
|
||||||
|
|
||||||
const searchQuery = {
|
|
||||||
offset: 4,
|
|
||||||
page: 1,
|
|
||||||
query: {
|
|
||||||
// TODO: remove dummy category
|
|
||||||
// categories: [title],
|
|
||||||
categories: ['Engineering'],
|
|
||||||
price: [-1, 1]
|
|
||||||
},
|
|
||||||
sort: {
|
|
||||||
datePublished: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const search = await ocean.aquarius.queryMetadata(searchQuery)
|
|
||||||
this.setState({
|
|
||||||
channelAssets: search.results,
|
|
||||||
isLoadingChannel: false
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
Logger.error(error.message)
|
|
||||||
this.setState({ isLoadingChannel: false })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private inputChange = (event: ChangeEvent<HTMLInputElement>) => {
|
private inputChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
@ -87,7 +41,7 @@ export default class Home extends Component<HomeProps, HomeState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const { channelAssets, isLoadingChannel, search } = this.state
|
const { search } = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Route
|
<Route
|
||||||
@ -114,32 +68,7 @@ export default class Home extends Component<HomeProps, HomeState> {
|
|||||||
</Content>
|
</Content>
|
||||||
|
|
||||||
<Content wide>
|
<Content wide>
|
||||||
<div className={styles.channel}>
|
<ChannelTeaser channel="ai-for-good" />
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<h2 className={styles.channelTitle}>
|
|
||||||
<Link to={`/channels/${slug}`}>
|
|
||||||
{title} →
|
|
||||||
</Link>
|
|
||||||
</h2>
|
|
||||||
<p>{teaser}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{isLoadingChannel ? (
|
|
||||||
<Spinner message="Loading..." />
|
|
||||||
) : channelAssets && channelAssets.length ? (
|
|
||||||
<div className={styles.channelResults}>
|
|
||||||
{channelAssets.map((asset: any) => (
|
|
||||||
<Asset key={asset.id} asset={asset} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div>No data sets found.</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<AssetsLatest />
|
<AssetsLatest />
|
||||||
</Content>
|
</Content>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user