Skip to content

Commit

Permalink
NFT UI
Browse files Browse the repository at this point in the history
  • Loading branch information
1aerostorm committed Sep 11, 2023
1 parent cc3352d commit f208a00
Show file tree
Hide file tree
Showing 13 changed files with 500 additions and 40 deletions.
4 changes: 2 additions & 2 deletions app/ResolveRoute.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
export const routeRegex = {
UserProfile1: /^\/(@[\w\.\d-]+)\/?$/,
UserProfile2: /^\/(@[\w\.\d-]+)\/(transfers|assets|create-asset|invites|curation-rewards|author-rewards|donates-from|donates-to|filled-orders|permissions|created|password|witness|settings)\/??(?:&?[^=&]*=[^=&]*)*$/,
UserProfile2: /^\/(@[\w\.\d-]+)\/(transfers|assets|create-asset|invites|curation-rewards|author-rewards|donates-from|donates-to|nft|nft-collections|filled-orders|permissions|created|password|witness|settings)\/??(?:&?[^=&]*=[^=&]*)*$/,
UserProfile3: /^\/(@[\w\.\d-]+)\/[\w\.\d-]+/,
UserAssetEndPoints: /^\/(@[\w\.\d-]+)\/assets\/([\w\d.-]+)\/(update|transfer)$/,
UserEndPoints: /^(transfers|assets|create-asset|invites|curation-rewards|author-rewards|donates-from|donates-to|filled-orders|permissions|created|password|witness|settings)$/,
UserEndPoints: /^(transfers|assets|create-asset|invites|curation-rewards|author-rewards|donates-from|donates-to|nft|nft-collections|filled-orders|permissions|created|password|witness|settings)$/,
WorkerSort: /^\/workers\/([\w\d\-]+)\/?($|\?)/,
WorkerSearchByAuthor: /^\/workers\/([\w\d\-]+)\/(\@[\w\d.-]+)\/?($|\?)/,
WorkerRequest: /^\/workers\/([\w\d\-]+)\/(\@[\w\d.-]+)\/([\w\d-]+)\/?($|\?)/,
Expand Down
1 change: 1 addition & 0 deletions app/components/all.scss
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
@import "./modules/Powerdown.scss";
@import "./modules/QuickBuy.scss";
@import "./modules/Modals";
@import "./modules/nft/CreateNFTCollection";

// pages
@import "./pages/Exchanges";
Expand Down
18 changes: 9 additions & 9 deletions app/components/modules/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,20 +91,20 @@ class Header extends React.Component {
const name = acct_meta ? normalizeProfile(acct_meta.toJS()).name : null;
const user_title = name ? `${name} (@${user_name})` : user_name;
page_title = user_title;
if(route.params[1] === "curation-rewards"){
if (route.params[1] === "curation-rewards"){
page_title = tt('header_jsx.curation_rewards_by') + " " + user_title;
}
if(route.params[1] === "author-rewards"){
} else if (route.params[1] === "author-rewards"){
page_title = tt('header_jsx.author_rewards_by') + " " + user_title;
}
if(route.params[1] === "donates-from"){
} else if (route.params[1] === "donates-from"){
page_title = tt('header_jsx.donates_from') + " " + user_title;
}
if(route.params[1] === "donates-to"){
} else if (route.params[1] === "donates-to"){
page_title = tt('header_jsx.donates_to') + " " + user_title;
}
if(route.params[1] === "recent-replies"){
} else if (route.params[1] === "recent-replies"){
page_title = tt('header_jsx.replies_to') + " " + user_title;
} else if (route.params[1] === "nft"){
page_title = tt('header_jsx.nft_tokens') + " " + user_title
} else if (route.params[1] === "nft-collections"){
page_title = tt('header_jsx.nft_collections') + " " + user_title
}
} else if (route.page === 'ConvertAssetsPage') {
page_title = tt('g.convert_assets')
Expand Down
217 changes: 217 additions & 0 deletions app/components/modules/nft/CreateNFTCollection.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
import React, { Component, } from 'react'
import tt from 'counterpart'
import { connect, } from 'react-redux'
import CloseButton from 'react-foundation-components/lib/global/close-button'
import { Formik, Form, Field, ErrorMessage, } from 'formik'

import transaction from 'app/redux/Transaction'

class CreateNFTCollection extends Component {
state = {
collection: {
name: '',
json_metadata: '',
max_token_count: 4294967295
}
}

validate = (values) => {
const errors = {}
const { name } = values
if (name.length < 3) {
errors.name = tt('assets_jsx.symbol_too_short')
} else {
const parts = name.split('.')
if (parts[0] == 'GOLOS' || parts[0] == 'GBG' || parts[0] == 'GESTS') {
errors.name = tt('assets_jsx.top_symbol_not_your')
} else if (parts.length == 2 && parts[1].length < 3) {
errors.name = tt('assets_jsx.subsymbol_too_short')
}
}
return errors
}

setSubmitting = (submitting) => {
this.setState({ submitting })
}

_onSubmit = async (values) => {
this.setSubmitting(true)
const { currentUser } = this.props
const username = currentUser.get('username')
await this.props.createCollection(values.name, values.json_metadata, values.max_token_count, username, () => {
this.props.fetchState()
this.props.onClose()
this.setSubmitting(false)
}, (err) => {
console.error(err)
this.setSubmitting(false)
})
}

_renderSubmittingIndicator = () => {
const { submitting } = this.state

return submitting ? <span className='submitter'>
<LoadingIndicator type='circle' />
</span> : null
}

onNameChange = (e, values, setFieldValue) => {
let newName = ''
let hasDot
for (let i = 0; i < e.target.value.length; ++i) {
const c = e.target.value[i]
if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && c !== '.') {
continue
}
if (c == '.') {
if (i < 3 || hasDot) {
continue
}
hasDot = true
}
newName += c.toUpperCase()
}
setFieldValue('name', newName)
}

render() {
const { onClose, } = this.props;
const { submitting } = this.state

return (<div className='CreateNFTCollection'>
<CloseButton onClick={onClose} />
<h4>
{tt('create_nft_collection_jsx.title')}
</h4>
<Formik
initialValues={this.state.collection}
enableReinitialize={true}
validate={this.validate}
onSubmit={this._onSubmit}
>
{({
handleSubmit, isValid, values, setFieldValue, handleChange,
}) => {
return (
<Form>
<div className='row'>
<div className='column small-5'>
{tt('create_nft_collection_jsx.name')}
<div className='input-group' style={{marginBottom: 5}}>
<Field name='name' type='text' maxLength='14' onChange={(e) => this.onNameChange(e, values, setFieldValue)} />
</div>
</div>
<div className='column small-7 padding-left'>
{tt('create_nft_collection_jsx.coll_title')}
<div className='input-group' style={{marginBottom: 5}}>
<Field name='title' type='text' />
</div>
<ErrorMessage name='title' component='div' className='error' />
</div>
<ErrorMessage name='name' component='div' className='error' />
</div>
<div>
{tt('create_nft_collection_jsx.coll_descr')}
{' '}
{tt('create_nft_collection_jsx.not_required')}
</div>
<div className='row'>
<div className='column small-12'>
<div className='input-group' style={{marginBottom: 5}}>
<Field name='description' type='text' />
</div>
<ErrorMessage name='description' component='div' className='error' />
</div>
</div>
<div>
{tt('create_nft_collection_jsx.image')}
</div>
<div className='row'>
<div className='column small-12'>
<div className='input-group' style={{marginBottom: 5}}>
<Field name='image' type='text' />
</div>
<ErrorMessage name='image' component='div' className='error' />
</div>
</div>
<div>
{tt('create_nft_collection_jsx.json_metadata')}
</div>
<div className='row'>
<div className='column small-12'>
<div className='input-group' style={{marginBottom: 5}}>
<Field name='json_metadata' type='text' />
</div>
<ErrorMessage name='json_metadata' component='div' className='error' />
</div>
</div>
<div>
{tt('create_nft_collection_jsx.token_count')}
</div>
<div className='row'>
<div className='column small-6'>
<div className='input-group' style={{marginBottom: 5}}>
<Field name='token_count' type='text' />
</div>
</div>
<div className='column small-6 padding-left'>
<div className='input-group' style={{marginBottom: 5}}>
<Field name='infinity' type='checkbox' />
{tt('create_nft_collection_jsx.infinity')}
</div>
</div>
</div>
<div className='row' style={{ marginTop: '0.5rem' }}>
<div className='column small-8'>
<button type='submit' disabled={!isValid || submitting} className='button'>
{tt('create_nft_collection_jsx.create')}
</button>
<button type='button' disabled={submitting} className='button hollow' onClick={onClose}>
{tt('g.cancel')}
</button>
{this._renderSubmittingIndicator()}
</div>
</div>
</Form>
)}}</Formik>
</div>)
}
}

export default connect(
// mapStateToProps
(state, ownProps) => {
const {locationBeforeTransitions: {pathname}} = state.routing;
let currentUser = ownProps.currentUser || state.user.getIn(['current'])
if (!currentUser) {
const currentUserNameFromRoute = pathname.split(`/`)[1].substring(1);
currentUser = Map({username: currentUserNameFromRoute});
}
const currentAccount = currentUser && state.global.getIn(['accounts', currentUser.get('username')]);
return { ...ownProps, currentUser, currentAccount, };
},

dispatch => ({
createCollection: ({
name, json_metadata, max_token_count, currentUser, successCallback, errorCallback
}) => {
const username = currentUser.get('username')
const operation = {
creator: username,
name,
json_metadata,
max_token_count
}

dispatch(transaction.actions.broadcastOperation({
type: 'nft_collection',
username,
operation,
successCallback,
errorCallback
}))
}
})
)(CreateNFTCollection)
9 changes: 9 additions & 0 deletions app/components/modules/nft/CreateNFTCollection.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.CreateNFTCollection {
.column {
padding-left: 0rem;
padding-right: 0rem;
}
.padding-left {
padding-left: 0.75rem;
}
}
94 changes: 94 additions & 0 deletions app/components/modules/nft/NFTCollections.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import {connect} from 'react-redux';
import { Link } from 'react-router';
import tt from 'counterpart';
import { Asset } from 'golos-lib-js/lib/utils';
import Reveal from 'react-foundation-components/lib/global/reveal';

import DialogManager from 'app/components/elements/common/DialogManager';
import Icon from 'app/components/elements/Icon';
import LoadingIndicator from 'app/components/elements/LoadingIndicator'
import CreateNFTCollection from 'app/components/modules/nft/CreateNFTCollection'
import g from 'app/redux/GlobalReducer'
import user from 'app/redux/User'

class NFTCollections extends Component {
state = {}

constructor() {
super()
}

showCreate = (e) => {
e.preventDefault()
this.setState({
showCreate: true,
})
}

hideCreate = () => {
this.setState({
showCreate: false,
})
}

render() {
const { account, isMyAccount, nft_collections, fetchState } = this.props
const accountName = account.get('name')

const collections = nft_collections ? nft_collections.toJS() : null

let items
if (!collections) {
items = <LoadingIndicator type='circle' />
} else if (!collections.length) {
if (isMyAccount) {
items = <span>{tt('nft_collections_jsx.not_yet')}</span>
} else {
items = <span>{tt('nft_collections_jsx.not_yet2') + accountName + tt('nft_collections_jsx.not_yet3')}</span>
}
} else {
items = JSON.stringify(collections)
}

const { showCreate } = this.state

return (<div>
<div className="row">
<div className="column small-12">
<h4 className="Assets__header">{tt('g.nft_collections')}</h4>
{isMyAccount && <a href='#' onClick={this.showCreate} className="button hollow float-right">
{tt('nft_collections_jsx.create')}
</a>}
</div>
</div>
<div className="row">
<div className="column small-12">
{items}
</div>
</div>

<Reveal show={showCreate} revealStyle={{ width: '450px' }}>
<CreateNFTCollection
onClose={this.hideCreate}
fetchState={fetchState}
/>
</Reveal>
</div>)
}
}

export default connect(
(state, ownProps) => {
return {...ownProps,
nft_collections: state.global.get('nft_collections')
}
},
dispatch => ({
fetchState: () => {
const pathname = window.location.pathname
dispatch({type: 'FETCH_STATE', payload: {pathname}})
}
})
)(NFTCollections)
Loading

0 comments on commit f208a00

Please sign in to comment.