Commit dba9a687 authored by PDuarte's avatar PDuarte

Episodes UI incomplet

parent 745f82a6
...@@ -29,6 +29,12 @@ export default [ ...@@ -29,6 +29,12 @@ export default [
title: 'Project Seasons', title: 'Project Seasons',
icon: <Briefcase />, icon: <Briefcase />,
navLink: '/assets/seasons' navLink: '/assets/seasons'
},
{
id: 'episodesDash',
title: 'Project Episodes',
icon: <Briefcase />,
navLink: '/assets/episodes'
} }
] ]
} }
......
...@@ -99,6 +99,30 @@ const AssetsRoutes = [ ...@@ -99,6 +99,30 @@ const AssetsRoutes = [
{ {
path: '/assets/seasons', path: '/assets/seasons',
component: lazy(() => import('../../views/assets/seasons')) component: lazy(() => import('../../views/assets/seasons'))
},
// episodes
{
path: '/assets/episodes/edit',
exact: true,
component: () => <Redirect to='/assets/episodes/edit/1' />
},
{
path: '/assets/episodes/edit/:id',
component: lazy(() => import('../../views/assets/episodes/edit')),
meta: {
navLink: '/assets/episodes/edit'
}
},
{
path: '/assets/episodes/add',
component: lazy(() => import('../../views/assets/episodes/add')),
meta: {
navLink: '/assets/episodes/add'
}
},
{
path: '/assets/episodes',
component: lazy(() => import('../../views/assets/episodes'))
} }
] ]
......
// ** React Imports
import { Fragment } from 'react'
import { Link } from 'react-router-dom'
// ** Store & Actions
import { addepisode } from '../../store/actions'
import { useDispatch, useSelector } from 'react-redux'
// ** Custom Components
import Breadcrumbs from '@components/breadcrumbs'
// ** Third Party Components
import { Row, Col } from 'reactstrap'
// module settings
import moduleSettings from '../module'
// ** Tables
import ElementCard from '../card'
// ** Styles
import '@styles/react/libs/tables/react-dataTable-component.scss'
const Tables = () => {
const dispatch = useDispatch()
const storeNavbar = useSelector(state => state.navbar)
const onSubmitHandler = (values, uploadFile) => {
dispatch(
addepisode({
projectid: values.projectid,
title: values.title,
parentid: values.parentid,
seriesid: values.seriesid,
seasonid: values.seasonid,
parenttype: values.parenttype,
external_id: values.external_id,
external_url: values.external_url,
textual: values.textual,
availability: values.availability,
genres: values.genres,
subgenres: values.subgenres,
data: uploadFile
}
)
)
}
return (
<Fragment>
<Breadcrumbs breadCrumbTitle='Seasons' breadCrumbParent='Seasons' breadCrumbActive={moduleSettings.mainTitle} />
<Row>
<Col sm='12'>
<Link to={moduleSettings.baseURL}>Back to {moduleSettings.mainTitle}</Link>
</Col>
</Row>
<Row>
<Col sm='12'>
<div className="card">
<div className="card-header">
<h4 className="card-title">New {moduleSettings.mainTitleSingle}</h4>
</div>
<div className="card-body">
{storeNavbar.projectCurrent === null ? <div>
Select Project
</div> : <ElementCard selectedElement={{
id: '<generate>',
projectid: storeNavbar.projectCurrent.value,
title: '',
parentid:'<generate>',
parenttype: 'Episodes',
external_id: '',
external_url: '',
seriesID: 0,
seasonid: 1,
textual: [],
genres: [],
subgenres: [],
availability: [],
imagery: []
}}
onSubmitHandler={onSubmitHandler}
/>
}
</div>
</div>
</Col>
</Row>
</Fragment>
)
}
export default Tables
import { Fragment, useEffect, useState } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import {getProject} from '../../../settings/store/actions'
import { Card, CardBody, Row, Col, CardHeader, CardTitle, Label, Input, FormGroup, CardText, Button } from 'reactstrap'
import { selectThemeColors } from '@utils'
import Flatpickr from 'react-flatpickr'
import Select, { components } from 'react-select'
import { platform } from 'chart.js'
import Moment from 'moment'
const PlanAvaliability = ({dataElement, handleElmChange}) => {
const [pickerstartdate, setPickerstartdate] = useState(Date.parse(dataElement.startdate)),
[pickerenddate, setPickerenddate] = useState(Date.parse(dataElement.enddate)),
[platforms, setPlatforms] = useState([]),
[geolocations, setGeolocations] = useState([]),
[avaliaPlatforms, setAvaliaPlatforms] = useState([]),
[permitGeo, setPermitGeo] = useState([]),
[denytGeo, setDenyGeo] = useState([]),
store = useSelector(state => state.projectsettings)
useEffect(() => {
if (!store.selectedProject) return
console.log(store.selectedProject)
const platforms = store.selectedProject.platforms.map(elm => {
return {
value: elm.id,
label: elm.name
}
})
setPlatforms(platforms)
const geo = store.selectedProject.geolocations.map(elm => {
return {
value: elm.id,
label: elm.name
}
})
setGeolocations(geo)
}, [store.selectedProject])
useEffect(() => {
if (!dataElement) return
const selected = dataElement.platforms.map(elm => {
return {
value: elm.id,
label: elm.name
}
})
setAvaliaPlatforms(selected)
const geoPermit = dataElement.geolocations.map(elm => {
return elm.pivot.action === "permit" ? {
value: elm.id,
label: elm.name
} : null
})
setPermitGeo(geoPermit)
const geoDeny = dataElement.geolocations.map(elm => {
return elm.pivot.action === "deny" ? {
value: elm.id,
label: elm.name
} : null
})
setDenyGeo(geoDeny)
}, [dataElement])
const updatePlatforms = (value) => {
const newValue = value.map(elm => {
return {
id: elm.value,
name: elm.label,
pivot: {
idavailability: dataElement.id,
idplatform:elm.value
}
}
})
const newData = {
...dataElement,
platforms: newValue
}
handleElmChange(newData)
},
updateStartDate = (value) => {
const newData = {
...dataElement,
startdate: Moment(value[0]).format('YYYY-MM-DD HH:mm:ss')
}
handleElmChange(newData)
setPickerstartdate(value)
console.log(value)
},
updateEndDate = (value) => {
const newData = {
...dataElement,
enddate: Moment(value[0]).format('YYYY-MM-DD HH:mm:ss')
}
handleElmChange(newData)
setPickerenddate(value)
},
updateGeo = (value, actionValue) => {
const newValue = value.map(elm => {
return {
id: elm.value,
name: elm.label,
pivot: {
idgeolocation: elm.value,
idavailability: dataElement.id,
action: actionValue
}
}
})
let coValues
if (actionValue === 'permit') {
coValues = denytGeo.filter(q => !!q).map(elm => {
return {
id: elm.value,
name: elm.label,
pivot: {
idgeolocation: elm.value,
idavailability: dataElement.id,
action: 'deny'
}
}
})
} else {
console.log(permitGeo)
coValues = permitGeo.filter(q => !!q).map(elm => {
return {
id: elm.value,
name: elm.label,
pivot: {
idgeolocation: elm.value,
idavailability: dataElement.id,
action: 'permit'
}
}
})
}
const geoparts = newValue.concat(coValues)
const newData = {
...dataElement,
geolocations: geoparts
}
handleElmChange(newData)
},
platfomsOnChange = (value, { action, removedValue }) => {
switch (action) {
case 'remove-value':
case 'pop-value':
if (removedValue.isFixed) {
return
}
setAvaliaPlatforms(value)
break
case 'clear':
value = genresAllOptions.filter(v => v.isFixed)
setAvaliaPlatforms(value)
break
default:
setAvaliaPlatforms(value)
break
}
updatePlatforms(value)
},
permitGeoOnChange = (value, { action, removedValue }) => {
switch (action) {
case 'remove-value':
case 'pop-value':
if (removedValue.isFixed) {
return
}
setPermitGeo(value)
break
case 'clear':
value = genresAllOptions.filter(v => v.isFixed)
setPermitGeo(value)
break
default:
setPermitGeo(value)
break
}
updateGeo(value, 'permit')
},
denyGeoOnChange = (value, { action, removedValue }) => {
switch (action) {
case 'remove-value':
case 'pop-value':
if (removedValue.isFixed) {
return
}
setDenyGeo(value)
break
case 'clear':
value = genresAllOptions.filter(v => v.isFixed)
setDenyGeo(value)
break
default:
setDenyGeo(value)
break
}
updateGeo(value, 'deny')
}
return <Fragment>
<Row>
<Col md='12' sm='12'>
<CardTitle tag="h5"> Avaliability id:{dataElement.id}</CardTitle>
</Col>
</Row>
<Row>
<Col md='4' sm='12'>
<FormGroup>
<Label for='startdate'>Start date</Label>
<Flatpickr
value={pickerstartdate}
// data-enable-time
id={`startdate-picker${dataElement.id}`}
className='form-control'
onChange={date => updateStartDate(date)}
options={{
enableTime: true,
dateFormat: 'Y-m-d H:i',
time_24hr: true
}}
/>
</FormGroup>
</Col>
<Col md='8' sm='12'>
<Label for='platforms'>Platforms</Label>
<Select
isClearable={false}
theme={selectThemeColors}
value={avaliaPlatforms}
isMulti
name={`platforms${dataElement.id}`}
options={platforms}
onChange={platfomsOnChange}
className='react-select'
classNamePrefix='select'
/>
</Col>
</Row>
<Row>
<Col md='4' sm='12'>
<FormGroup>
<Label for='enddate'>End date</Label>
<Flatpickr
value={pickerenddate}
// data-enable-time
id={`enddate-picker${dataElement.id}`}
className='form-control'
onChange={date => updateEndDate(date) }
options={{
enableTime: true,
dateFormat: 'Y-m-d H:i',
time_24hr: true
}}
/>
</FormGroup>
</Col>
<Col md='4' sm='12'>
<Label for='locationspermit'>Locations Permit</Label>
<Select
isClearable={false}
theme={selectThemeColors}
value={permitGeo}
isMulti
name={`platforms${dataElement.id}`}
options={geolocations}
onChange={permitGeoOnChange}
className='react-select'
classNamePrefix='select'
/>
</Col>
<Col md='4' sm='12'>
<Label for='locationDeny'>Locations Deny</Label>
<Select
isClearable={false}
theme={selectThemeColors}
value={denytGeo}
isMulti
name={`platforms${dataElement.id}`}
options={geolocations}
onChange={denyGeoOnChange}
className='react-select'
classNamePrefix='select'
/>
</Col>
</Row>
<div className=".divider"></div>
</Fragment>
}
const AvaliabilityBlock = ({dataElement, handleElmChange}) => {
const handleAvalChange = (value) => {
const newData = dataElement.map(elm => {
if (elm.id === value.id) {
elm.platforms = value.platforms
elm.geolocations = value.geolocations
elm.startdate = value.startdate
elm.enddate = value.enddate
}
})
// console.log(value)
},
handleAddBlock = () => {
if (!dataElement) return
const newData = dataElement
newData.push({
id: `<generated${dataElement.length}>`,
idassets: 'current',
startdate: '',
enddate: '',
platforms: [],
geolocations: []
})
handleElmChange(newData)
console.log(dataElement)
}
return <Row>
<Col sm='12'>
<Card>
<CardBody className='pt-2'>
{ dataElement !== null && dataElement.map(elm => {
return <PlanAvaliability
key={elm.id}
dataElement={elm}
handleElmChange={handleAvalChange}
/>
})
}
<Col sm="12" className="text-center">
<Button.Ripple
className='mb-1 mb-sm-0 mr-0 mr-sm-1'
type='button'
color='primary'
onClick={() => handleAddBlock()}
>
New
</Button.Ripple>
</Col>
</CardBody>
</Card>
</Col>
</Row>
}
export default AvaliabilityBlock
\ No newline at end of file
import { Fragment, useEffect, useState } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import {Button, Media, Card, CardBody, Row, Col, CardHeader, CardTitle, Label, Input, FormGroup, CardText } from 'reactstrap'
import { Camera, Lock, Edit, Trash2 } from 'react-feather'
const BlocoImage = ({title, img, handelImageChange}) => {
const [imgd, setImgd] = useState(false)
const onChange = e => {
const reader = new FileReader(),
files = e.target.files
reader.onload = function () {
setImgd(reader.result)
handelImageChange(title, JSON.stringify(reader.result))
}
reader.readAsDataURL(files[0])
}
useEffect(() => {
if (img !== null && img !== undefined) {
return setImgd(`${process.env.REACT_APP_IMAGERY}/${img}`)
}
}, [img])
return <Fragment>
<Media className='mb-2'>
{ imgd === null || imgd === false || imgd === undefined ? (
<Camera
className='user-avatar rounded mr-2 my-25 cursor-pointer'
alt={title}
height='90'
width='90'
/>) : (<img
className='user-avatar rounded mr-2 my-25 cursor-pointer'
src={imgd}
alt={title}
height='90'
width='90'
/>)}
<Media className='mt-50' body>
<h4>{title} </h4>
<div className='d-flex flex-wrap mt-1 px-0'>
<Button.Ripple id='change-img' tag={Label} className='mr-75 mb-0' color='primary'>
<span className='d-none d-sm-block'>Change</span>
<span className='d-block d-sm-none'>
<Edit size={14} />
</span>
<input type='file' hidden id={`change-img-${title}`}
onChange={onChange}
accept='image/*' />
</Button.Ripple>
<Button.Ripple color='secondary' outline onClick={ e => { setImgd(null) } }>
<span className='d-none d-sm-block'>Remove</span>
<span className='d-block d-sm-none'>
<Trash2 size={14} />
</span>
</Button.Ripple>
</div>
</Media>
</Media>
</Fragment>
}
const PlanImages = ({language, dataElement, handleElmChange}) => {
const handleInputChange = (value, file) => {
// console.log(value)
// console.log(file)
// //dataElement[field] = value
handleElmChange(value, file, language)
}
return <Fragment>
<CardTitle tag="h5">{language.name} Imagery </CardTitle>
<Col md='12' sm='12'>
<FormGroup>
<Label for='title'>Titlle</Label>
</FormGroup>
</Col>
<Row>
<Col md='4' >
<BlocoImage
title="portrait"
img={dataElement && dataElement.portrait}
handelImageChange={handleInputChange}
/>
</Col>
<Col md='4' >
<BlocoImage
title="landscape"
img={dataElement && dataElement.landscape}
handelImageChange={handleInputChange}
/>
</Col>
<Col md='4' >
<BlocoImage
title="thumbnail"
img={dataElement && dataElement.thumbnail}
handelImageChange={handleInputChange}
/>
</Col>
<Col md='4' >
<BlocoImage
title="banner"
img={dataElement && dataElement.banner}
handelImageChange={handleInputChange}
/>
</Col>
<Col md='4' >
<BlocoImage
title="icon"
img={dataElement && dataElement.icon}
handelImageChange={handleInputChange}
/>
</Col>
<Col md='4' >
<BlocoImage
title="hbackground"
img={dataElement && dataElement.hbackground}
handelImageChange={handleInputChange}
/>
</Col>
<Col md='4' >
<BlocoImage
title="vbackground"
img={dataElement && dataElement.vbackground}
handelImageChange={handleInputChange}
/>
</Col>
<Col md='4' >
<BlocoImage
title="hover"
img={dataElement && dataElement.hover}
handelImageChange={handleInputChange}
/>
</Col>
<Col md='4' >
<BlocoImage
title="focus"
img={dataElement && dataElement.focus}
handelImageChange={handleInputChange}
/>
</Col>
</Row>
</Fragment>
}
const ImageryBlock = ({dataElement, handleElmChange}) => {
const store = useSelector(state => state.projectsettings)
// dispatch = useDispatch(),
// handleLangChange = () => {
// handleTextualChange(dataElement)
// }
// useEffect(() => {
// console.log('aki')
// console.log(dataElement)
// }, [store.projectsettings])
return <Row>
<Col sm='12'>
<Card>
<CardBody className='pt-2'>
{ store.selectedProject !== null
&& dataElement
&& store.selectedProject.languages.map(language => {
let images = dataElement.filter(e => e.langcode === language.langcode)
if (images.length < 1) {
images = [
{
id: '<genrated>',
idassets: '<assetid>',
langcode: language.langcode,
longdescription: '',
shortdescriptions: '',
title: ''
}
]
dataElement.push(images[0])
}
return <PlanImages
key={language.id}
language={language}
dataElement={images[0]}
handleElmChange={handleElmChange}
/>
}
)}
</CardBody>
</Card>
</Col>
</Row>
}
export default ImageryBlock
\ No newline at end of file
// ** React Imports
import { useState, useEffect, Fragment } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { toast } from 'react-toastify'
import Avatar from '@components/avatar'
import Select, { components } from 'react-select'
import {Media, Button, Label, Form, FormGroup, Input, Table, CustomInput, Card, CardBody, Row, Col, Nav, NavItem, NavLink, TabContent, TabPane, Alert, CardHeader, CardTitle, CardText } from 'reactstrap'
import { isObjEmpty, selectThemeColors } from '@utils'
import { Bell, Check, Hash, X, AlertTriangle, Info } from 'react-feather'
// ** Store & Actions
import {getData_series, getData_seasons, resetResults} from '../../store/actions'
// import { getData_pagetypes } from '../../../settings/store/actions'
import { getData_layoutPlaylists } from '../../../screens/store/actions'
import { useForm } from 'react-hook-form'
import classnames from 'classnames'
import Swal from 'sweetalert2'
import withReactContent from 'sweetalert2-react-content'
import TextualBlock from './textual'
import AvaliabilityBlock from './avaliability'
import ImageryBlock from './imagery'
// ** Styles
import '@styles/react/apps/app-users.scss'
import '@styles/react/libs/flatpickr/flatpickr.scss'
const SuccessProgressToast = () => (
<Fragment>
<div className='toastify-header'>
<div className='title-wrapper'>
<Avatar size='sm' color='success' icon={<Check size={12} />} />
<h6 className='toast-title'>Saved !</h6>
</div>
<small className='text-muted'></small>
</div>
<div className='toastify-body'>
<span role='img' aria-label='toast-text'>
👋 Good job.
</span>
</div>
</Fragment>
)
const ElementCard = ({ selectedElement, onSubmitHandler, handelDelete }) => {
const store = useSelector(state => state.projectsettings)
const [PlatformName, setPlatformName] = useState('Web')
const MySwal = withReactContent(Swal)
const handleError = (text) => {
return MySwal.fire({
title: 'Error!',
text,
icon: 'error',
customClass: {
confirmButton: 'btn btn-primary'
},
buttonsStyling: false
})
}
const [dataElement, setElementData] = useState(null),
[genresAllOptions, setGenresAllOptions] = useState([]),
[genresAsset, setGenresAsset] = useState([]),
[genresSubAsset, setGenresSubAsset] = useState([]),
{ register, errors, handleSubmit } = useForm(),
settingStore = useSelector(state => state.projectsettings),
screensStore = useSelector(state => state.screens),
projectAssets = useSelector(state => state.assets),
// [pagetypes, setPagetypes] = useState(null),
// [layoutplaylists, setLayoutplaylists] = useState(null),
[activeTab, setActiveTab] = useState(0),
[uploadFiles, setUploadFile] = useState([]),
//
toggle = tab => setActiveTab(tab),
dispatch = useDispatch(),
notifySuccessProgress = () => toast.success(<SuccessProgressToast />),
onSubmit = values => {
if (isObjEmpty(errors)) {
const submitElement = {
...dataElement,
idproject: values.idproject,
title: values.title,
seriesid: values.seriesid,
seasonid: values.seasonid,
parentid: values.parentid,
parenttype: values.parenttype,
external_id: values.external_id,
external_url: values.external_url
}
onSubmitHandler(submitElement, uploadFiles)
}
},
handleTextualChange = value => {
const newData = {
...dataElement,
textual: value
}
setElementData(newData)
},
handleAvalChange = value => {
// console.log(value)
const newData = {
...dataElement,
availability: value
}
setElementData(newData)
},
updateGenres = (value) => {
const newValue = value.map(elm => {
return {
id: elm.value,
idproject: dataElement.projectid,
name: elm.label,
pivot: {
idasset: dataElement.id,
idgenres:elm.value1
}
}
})
const newData = {
...dataElement,
genres: newValue
}
setElementData(newData)
},
updateSubGenres = (value) => {
const newValue = value.map(elm => {
return {
id: elm.value,
idproject: dataElement.projectid,
name: elm.label,
pivot: {
idasset: dataElement.id,
idgenres:elm.value1
}
}
})
const newData = {
...dataElement,
subgenres: newValue
}
setElementData(newData)
},
genreOnChange = (value, { action, removedValue }) => {
switch (action) {
case 'remove-value':
case 'pop-value':
if (removedValue.isFixed) {
return
}
setGenresAsset(value)
break
case 'clear':
value = genresAllOptions.filter(v => v.isFixed)
setGenresAsset(value)
break
default:
setGenresAsset(value)
break
}
updateGenres(value)
},
genreSubOnChange = (value, { action, removedValue }) => {
switch (action) {
case 'remove-value':
case 'pop-value':
if (removedValue.isFixed) {
return
}
setGenresSubAsset(value)
break
case 'clear':
value = genresAllOptions.filter(v => v.isFixed)
setGenresSubAsset(value)
break
default:
setGenresSubAsset(value)
break
}
updateSubGenres(value)
},
handleImageryChange = (prop, file, lang) => {
let newUpload = uploadFiles.filter(elm => elm.type !== prop || elm.langcode.langcode !== lang.langcode)
newUpload = newUpload.concat({
type: prop,
langcode: lang,
obj: file
})
setUploadFile(newUpload)
}
useEffect(() => {
if (selectedElement !== null || (selectedElement !== null && dataElement !== null && selectedElement.id !== dataElement.id)) {
const genres = selectedElement.genres.map(elm => {
return {
value: elm.id,
label: elm.name
}
})
setGenresAsset(genres)
const subgenres = selectedElement.subgenres.map(elm => {
return {
value: elm.id,
label: elm.name
}
})
setGenresSubAsset(subgenres)
return setElementData(selectedElement)
}
}, [selectedElement])
useEffect(() => {
if (store.errorMsg !== '') {
handleError(store.errorMsg)
dispatch(resetResults())
}
}, [store.errorMsg])
useEffect(() => {
if (store.saveSucces) {
notifySuccessProgress()
dispatch(resetResults())
}
}, [store.saveSucces])
// populate page types
// useEffect(() => {
// if (!settingStore.allDataPagetypes || settingStore.allDataPagetypes.length < 1) {
// dispatch(getData_pagetypes({
// start: 1,
// length: 1000,
// q: null
// }))
// }
// }, [dispatch])
// useEffect(() => {
// setPagetypes(settingStore.allDataPagetypes)
// }, [settingStore.allDataPagetypes])
useEffect(() => {
if (!settingStore.selectedProject) return
console.log(settingStore.selectedProject)
const genres = settingStore.selectedProject.genres.map(elm => {
return {
value: elm.id,
label: elm.name
}
})
setGenresAllOptions(genres)
dispatch(getData_series({
start: 0,
length: 1000,
idproject: selectedElement.projectid,
q: null
}))
}, [settingStore.selectedProject])
useEffect(() => {
if (dataElement !== null && (!projectAssets.allDataSeries || projectAssets.allDataSeries.length < 1)) {
dispatch(getData_series({
start: 0,
length: 1000,
idproject: dataElement.idproject,
q: null
}))
}
if (dataElement !== null && dataElement.seriesid !== null && (!projectAssets.allDataSeasons || projectAssets.allDataSeasons.length < 1)) {
dispatch(getData_seasons({
start: 0,
length: 1000,
idproject: dataElement.idproject,
seriesid: dataElement.seriesid,
q: null
}))
}
}, [dataElement])
// populate layout menus
// useEffect(() => {
// if (!screensStore.allDataLayoutPlaylists || screensStore.allDataLayoutPlaylists.length < 1) {
// dispatch(getData_layoutPlaylists({
// start: 1,
// length: 1000,
// q: null
// }))
// }
// }, [dispatch])
// useEffect(() => {
// setLayoutplaylists(screensStore.allDataLayoutPlaylists)
// }, [screensStore.allDataLayoutPlaylists])
return (
<Fragment>
<Form
onSubmit={handleSubmit(onSubmit)}
>
<Row>
<Col md='4' sm='12'>
<FormGroup>
<Label for='id'>ID</Label>
<Input
readOnly={true}
type='text'
name='id'
id='id'
placeholder='id'
defaultValue={dataElement && dataElement.id}
/>
</FormGroup>
</Col>
<Col md='4' sm='12'>
<FormGroup>
<Label for='name'>Project ID</Label>
<Input
readOnly={true}
type='text'
name='projectid'
id='projectid'
innerRef={register({ required: true })}
placeholder='projectid'
defaultValue={dataElement && dataElement.projectid}
className={classnames({ 'is-invalid': errors['projectid'] })}
/>
</FormGroup>
</Col>
<Col md='4' sm='12'>
<FormGroup>
<Label for='title'>Title</Label>
<Input
type='text'
name='title'
id='title'
innerRef={register({ required: true })}
placeholder='title'
defaultValue={dataElement && dataElement.title}
className={classnames({ 'is-invalid': errors['title'] })}
/>
</FormGroup>
</Col>
<Col md='4' sm='12'>
<FormGroup>
<Label for='parenttype'>Parent Type</Label>
<Input
readOnly={true}
type='text'
name='parenttype'
id='parenttype'
innerRef={register({ required: false })}
placeholder='parenttype'
defaultValue={dataElement && dataElement.parenttype}
className={classnames({ 'is-invalid': errors['parenttype'] })}
/>
</FormGroup>
</Col>
<Col md='4' sm='12'>
<FormGroup>
<Label for='parentid'>Parent Id</Label>
<Input
readOnly={true}
type='text'
name='parentid'
id='parentid'
innerRef={register({ required: false })}
placeholder='parentid'
defaultValue={dataElement && dataElement.parentid}
className={classnames({ 'is-invalid': errors['parentid'] })}
/>
</FormGroup>
</Col>
<Col md='4' sm='12'>
<FormGroup>
<Label for='seriesid'>Series</Label>
<Input
type='select'
name='seriesid'
id='seriesid'
innerRef={register({ required: true })}
placeholder='seriesid'
defaultValue={dataElement && dataElement.seriesid}
className={classnames({ 'is-invalid': errors['seriesid'] })}
>
{!!projectAssets.allDataSeries && !!dataElement ? projectAssets.allDataSeries.map(option => {
return <option key={option.id}
selected={option.id === dataElement.seriesID ? option.id : ''}
value={option.id}>{option.title}</option>
}) : <option>Loading</option> }
</Input>
</FormGroup>
</Col>
<Col md='4' sm='12'>
<FormGroup>
<Label for='seasonid'>Season</Label>
<Input
type='select'
name='seasonid'
id='seasonid'
innerRef={register({ required: false })}
placeholder='seasonid'
defaultValue={dataElement && dataElement.seasonid}
className={classnames({ 'is-invalid': errors['seasonid'] })}
>
{!!projectAssets.allDataSeasons && !!dataElement ? projectAssets.allDataSeasons.map(option => {
return <option key={option.id}
selected={option.id === dataElement.seasonid ? option.id : ''}
value={option.id}>{option.title}</option>
}) : <option>Loading</option> }
</Input>
</FormGroup>
</Col>
<Col md='4' sm='12'>
<FormGroup>
<Label for='external_id'>External Id*</Label>
<Input
type='text'
name='external_id'
id='external_id'
innerRef={register({ required: false })}
placeholder='external_id'
defaultValue={dataElement && dataElement.external_id}
className={classnames({ 'is-invalid': errors['external_id'] })}
/>
</FormGroup>
</Col>
<Col md='4' sm='12'>
<FormGroup>
<Label for='external_id'>External Url*</Label>
<Input
type='text'
name='external_url'
id='external_url'
innerRef={register({ required: false })}
placeholder='external_url'
defaultValue={dataElement && dataElement.external_url}
className={classnames({ 'is-invalid': errors['external_url'] })}
/>
</FormGroup>
</Col>
</Row>
<Row>
<Col className='mb-1' md='6' sm='12'>
<h6 className="py-1 mx-1 mb-0 font-medium-2"><Hash /> Genres</h6>
<Select
isClearable={false}
theme={selectThemeColors}
value={genresAsset}
isMulti
name='genreassets'
options={genresAllOptions}
onChange={genreOnChange}
className='react-select'
classNamePrefix='select'
/>
</Col>
<Col className='mb-1' md='6' sm='12'>
<h6 className="py-1 mx-1 mb-0 font-medium-2"><Hash /> Sub-genres</h6>
<Select
isClearable={false}
theme={selectThemeColors}
value={genresSubAsset}
isMulti
name='subgenreassets'
options={genresAllOptions}
onChange={genreSubOnChange}
className='react-select'
classNamePrefix='select'
/>
</Col>
</Row>
<Row className='app-user-edit'>
<Col sm='12'>
<Card>
<CardBody className='pt-2'>
<Nav pills>
<NavItem>
<NavLink
active={activeTab === 0}
onClick={() => toggle(0)}
>
<span className='align-middle d-none d-sm-block'>Textual</span>
</NavLink>
</NavItem>
<NavItem>
<NavLink
active={activeTab === 1}
onClick={() => toggle(1)}
>
<span className='align-middle d-none d-sm-block'>Imagery</span>
</NavLink>
</NavItem>
<NavItem>
<NavLink
active={activeTab === 2}
onClick={() => toggle(2)}
>
<span className='align-middle d-none d-sm-block'>Avaliability</span>
</NavLink>
</NavItem>
</Nav>
<TabContent
activeTab={activeTab}
>
<TabPane tabId={0}>
<TextualBlock
dataElement={dataElement && dataElement.textual}
handleTextualChange={handleTextualChange}
/>
</TabPane>
<TabPane tabId={1}>
<ImageryBlock
dataElement={dataElement && dataElement.imagery}
handleElmChange={handleImageryChange}
/>
</TabPane>
<TabPane tabId={2}>
<AvaliabilityBlock
dataElement={dataElement && dataElement.availability}
handleElmChange={handleAvalChange}
/>
</TabPane>
</TabContent>
</CardBody>
</Card>
</Col>
</Row>
<Row className='app-user-edit'>
<Col className='d-flex flex-sm-row flex-column mt-2' sm='12'>
<Button.Ripple className='mb-1 mb-sm-0 mr-0 mr-sm-1' type='submit' color='primary'>
Save Changes
</Button.Ripple>
{ !!handelDelete &&
<Button.Ripple style={{marginLeft: 'auto'}} color='danger' outline onClick={() => handelDelete()} >
Delete
</Button.Ripple>
}
</Col>
</Row>
</Form>
</Fragment>
)
}
export default ElementCard
\ No newline at end of file
import { Fragment, useEffect } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import {getProject} from '../../../settings/store/actions'
import { Card, CardBody, Row, Col, CardHeader, CardTitle, Label, Input, FormGroup, CardText } from 'reactstrap'
import { languages } from 'prismjs'
const PlanLang = ({language, dataElement, LangChange}) => {
const handleInputChange = (value, field) => {
dataElement[field] = value
LangChange(dataElement)
}
return <Fragment>
<CardTitle tag="h5">{language.name} Textual </CardTitle>
<Col md='12' sm='12'>
<FormGroup>
<Label for='title'>Titlle</Label>
<Input
type='text'
name='title'
id='title'
// innerRef={register({ required: true })}
placeholder='title'
defaultValue={dataElement && dataElement.title}
onChange={(e) => handleInputChange(e.target.value, 'title')}
// className={classnames({ 'is-invalid': errors['title'] })}
/>
</FormGroup>
</Col>
<Col md='12' sm='12'>
<FormGroup>
<Label for='longdescription'>Long description</Label>
<Input
type='textarea'
name='longdescription'
id='longdescription'
// innerRef={register({ required: true })}
placeholder='longdescription'
defaultValue={dataElement && dataElement.longdescription}
onChange={(e) => handleInputChange(e.target.value, 'longdescription')}
// className={classnames({ 'is-invalid': errors['shortdescriptions'] })}
/>
</FormGroup>
</Col>
<Col md='12' sm='12'>
<FormGroup>
<Label for='shortdescriptions'>Short description</Label>
<Input
type='textarea'
name='shortdescriptions'
id='shortdescriptions'
// innerRef={register({ required: true })}
placeholder='shortdescriptions'
defaultValue={dataElement && dataElement.shortdescriptions}
onChange={(e) => handleInputChange(e.target.value, 'shortdescriptions')}
// className={classnames({ 'is-invalid': errors['shortdescriptions'] })}
/>
</FormGroup>
</Col>
</Fragment>
}
const TextualBlock = ({dataElement, handleTextualChange}) => {
const store = useSelector(state => state.projectsettings),
dispatch = useDispatch(),
handleLangChange = () => {
handleTextualChange(dataElement)
}
// populate layout menus
useEffect(() => {
if (!store.selectedProject || store.selectedProject.length < 1) {
dispatch(getProject(2))
}
}, [dispatch])
return <Row>
<Col sm='12'>
<Card>
<CardBody className='pt-2'>
{ store.selectedProject !== null
&& dataElement
&& store.selectedProject.languages.map(language => {
let textuals = dataElement.filter(e => e.langcode === language.langcode)
if (textuals.length < 1) {
textuals = [
{
id: '<genrated>',
idassets: '<assetid>',
langcode: language.langcode,
longdescription: '',
shortdescriptions: '',
title: ''
}
]
dataElement.push(textuals[0])
}
return <PlanLang
key={language.id}
language={language}
dataElement={textuals[0]}
LangChange={handleLangChange}
/>
}
)}
</CardBody>
</Card>
</Col>
</Row>
}
export default TextualBlock
// ** React Imports
import { Link } from 'react-router-dom'
import { cleanasset } from '../store/actions'
import { store } from '@store/storeConfig/store'
// ** Custom Components
import Avatar from '@components/avatar'
// module settings
import moduleSettings from './module'
// ** Third Party Components
import axios from 'axios'
import { MoreVertical, Edit, FileText, Archive, Trash } from 'react-feather'
import { Badge, UncontrolledDropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap'
// ** Vars
const states = ['success', 'danger', 'warning', 'info', 'dark', 'primary', 'secondary']
const status = {
1: { title: 'Current', color: 'light-primary' },
2: { title: 'Professional', color: 'light-success' },
3: { title: 'Rejected', color: 'light-danger' },
4: { title: 'Resigned', color: 'light-warning' },
5: { title: 'Applied', color: 'light-info' }
}
export let data
// ** Get initial Data
axios.get('/api/datatables/initial-data').then(response => {
data = response.data
})
// ** Table Zero Config Column
export const basicColumns = [
{
name: 'ID',
selector: 'id',
sortable: true,
maxWidth: '100px'
},
{
name: 'Name',
selector: 'name',
sortable: true,
minWidth: '225px'
},
{
name: 'Email',
selector: 'email',
sortable: true,
minWidth: '310px'
},
{
name: 'Position',
selector: 'post',
sortable: true,
minWidth: '250px'
},
{
name: 'Age',
selector: 'age',
sortable: true,
minWidth: '100px'
},
{
name: 'Salary',
selector: 'salary',
sortable: true,
minWidth: '175px'
}
]
// ** Expandable table component
const ExpandableTable = ({ data }) => {
return (
<div className='expandable-content p-2'>
<p>
<span className='font-weight-bold'>City:</span> {data.city}
</p>
<p>
<span className='font-weight-bold'>Experience:</span> {data.experience}
</p>
<p className='m-0'>
<span className='font-weight-bold'>Post:</span> {data.post}
</p>
</div>
)
}
// ** Table Common Column
export const columns = [
{
name: 'Name',
selector: 'name',
sortable: true,
minWidth: '250px',
cell: row => (
<div className='d-flex align-items-center'>
{row.avatar === '' ? (
<Avatar color={`light-${states[row.status]}`} content={row.full_name} initials />
) : (
<Avatar img={require(`@src/assets/images/portrait/small/avatar-s-${row.avatar}`).default} />
)}
<div className='user-info text-truncate ml-1'>
<span className='d-block font-weight-bold text-truncate'>{row.full_name}</span>
<small>{row.post}</small>
</div>
</div>
)
},
{
name: 'Status',
selector: 'status',
sortable: true,
minWidth: '150px',
cell: row => {
return (
<Badge color={status[row.status].color} pill>
{status[row.status].title}
</Badge>
)
}
},
{
name: 'Actions',
allowOverflow: true,
cell: row => {
return (
<div className='d-flex'>
<UncontrolledDropdown>
<DropdownToggle className='pr-1' tag='span'>
<MoreVertical size={15} />
</DropdownToggle>
<DropdownMenu right>
<DropdownItem tag='a' href='/' className='w-100' onClick={e => e.preventDefault()}>
<FileText size={15} />
<span className='align-middle ml-50'>Details</span>
</DropdownItem>
<DropdownItem tag='a' href='/' className='w-100' onClick={e => e.preventDefault()}>
<Archive size={15} />
<span className='align-middle ml-50'>Archive</span>
</DropdownItem>
<DropdownItem tag='a' href='/' className='w-100' onClick={e => e.preventDefault()}>
<Trash size={15} />
<span className='align-middle ml-50'>Delete</span>
</DropdownItem>
</DropdownMenu>
</UncontrolledDropdown>
<Edit size={15} />
</div>
)
}
}
]
// ** Table Intl Column
export const multiLingColumns = [
{
name: 'Name',
selector: 'name',
sortable: true,
minWidth: '200px'
},
{
name: 'Status',
selector: 'status',
sortable: true,
minWidth: '150px',
cell: row => {
return (
<Badge color={status[row.status].color} pill>
{status[row.status].title}
</Badge>
)
}
},
{
name: 'Actions',
allowOverflow: true,
cell: row => {
return (
<div className='d-flex'>
<UncontrolledDropdown>
<DropdownToggle className='pr-1' tag='span'>
<MoreVertical size={15} />
</DropdownToggle>
<DropdownMenu right>
<DropdownItem>
<FileText size={15} />
<span className='align-middle ml-50'>Details</span>
</DropdownItem>
<DropdownItem>
<Archive size={15} />
<span className='align-middle ml-50'>Archive</span>
</DropdownItem>
<DropdownItem>
<Trash size={15} />
<span className='align-middle ml-50'>Delete</span>
</DropdownItem>
</DropdownMenu>
</UncontrolledDropdown>
<Edit size={15} />
</div>
)
}
}
]
// ** Table Server Side Column
export const serverSideColumns = [
{
name: 'ID',
selector: 'id',
sortable: true,
minWidth: '25px'
},
{
name: 'Title',
selector: 'title',
sortable: true,
minWidth: '225px',
cell: row => (
<div className='d-flex justify-content-left align-items-center'>
<div className='d-flex flex-column'>
<Link
to={`${moduleSettings.baseURL}/edit/${row.id}`}
className='user-name text-truncate mb-0'
onClick={() => store.dispatch(cleanasset(row.id))}
>
<span className='font-weight-bold'>{row.title}</span>
</Link>
<small className='text-truncate text-muted mb-0'>edit</small>
</div>
</div>
)
},
{
name: 'Type',
selector: 'parenttype',
sortable: true,
minWidth: '225px'
}
]
// ** Table Adv Search Column
export const advSearchColumns = [
{
name: 'Name',
selector: 'full_name',
sortable: true,
minWidth: '200px'
},
{
name: 'Email',
selector: 'email',
sortable: true,
minWidth: '250px'
},
{
name: 'Post',
selector: 'post',
sortable: true,
minWidth: '250px'
},
{
name: 'City',
selector: 'city',
sortable: true,
minWidth: '150px'
},
{
name: 'Date',
selector: 'start_date',
sortable: true,
minWidth: '150px'
},
{
name: 'Salary',
selector: 'salary',
sortable: true,
minWidth: '100px'
}
]
export default ExpandableTable
// ** React Imports
import { Fragment } from 'react'
import { Link } from 'react-router-dom'
// ** Custom Components
import Breadcrumbs from '@components/breadcrumbs'
// ** Third Party Components
import { Row, Col } from 'reactstrap'
// ** Tables
import ElementEdit from './main'
// ** Styles
import '@styles/react/libs/tables/react-dataTable-component.scss'
// module settings
import moduleSettings from '../module'
const Tables = () => {
return (
<Fragment>
<Breadcrumbs breadCrumbTitle='Episodes' breadCrumbParent='Episodes' breadCrumbActive={moduleSettings.mainTitle} />
<Row>
<Col sm='12'>
<Link to={moduleSettings.baseURL}>Back to {moduleSettings.mainTitleSingle}</Link>
</Col>
</Row>
<Row>
<Col sm='12'>
<div className="card">
<div className="card-header">
<h4 className="card-title">{moduleSettings.mainTitleSingle}</h4>
</div>
<div className="card-body">
<ElementEdit />
</div>
</div>
</Col>
</Row>
</Fragment>
)
}
export default Tables
import { useState, useEffect, Fragment } from 'react'
import { useParams, Link } from 'react-router-dom'
// ** Store & Actions
import { getepisode, updateepisodes, deleteasset } from '../../store/actions'
import { useSelector, useDispatch } from 'react-redux'
import { Alert } from 'reactstrap'
import ElementCard from '../card'
// module settings
import moduleSettings from '../module'
import { Upload } from 'react-feather'
import _ from 'lodash'
const ElementEdit = () => {
// ** States & Vars
const store = useSelector(state => state.assets),
[dataElement, setElementData] = useState(null),
dispatch = useDispatch(),
{ id } = useParams()
const onSubmitHandler = (values, uploadFile) => {
// console.log(values)
// console.log(uploadFile)
dispatch(
updateepisodes({
...dataElement,
idproject: values.idproject,
title: values.title,
seriesid: values.seriesid,
seasonid: values.seasonid,
parentid: values.parentid,
parenttype: values.parenttype,
external_id: values.external_id,
external_url: values.external_url,
genres: values.genres,
subgenres: values.subgenres,
data: uploadFile
})
)
}
const handelDelete = () => {
if (!confirm('Delete')) return
dispatch(
deleteasset({ ...dataElement })
)
}
// ** Function to get user on mount
useEffect(() => {
dispatch(getepisode(id))
}, [dispatch])
// ** Update user image on mount or change
useEffect(() => {
console.log(store.selectedEpisode)
if (store.selectedEpisode !== null || (store.selectedEpisode !== null && dataElement !== null && store.selectedEpisode.id !== dataElement.id)) {
return setElementData(store.selectedEpisode)
}
}, [store.selectedEpisode])
return store.selectedEpisode !== null && store.selectedEpisode !== undefined ? (
<ElementCard
selectedElement={store.selectedEpisode}
onSubmitHandler={onSubmitHandler}
handelDelete={handelDelete}
/>
) : (
<Alert color='info'>
<h4 className='alert-heading'>Loading {moduleSettings.mainTitleSingle}</h4>
<div className='alert-body'>
If {moduleSettings.mainTitleSingle} with id: {id} doesn't exist. Check list of all {moduleSettings.mainTitle}: <Link to={moduleSettings.baseURL}>{moduleSettings.mainTitle} List</Link>
</div>
</Alert>
)
}
export default ElementEdit
// ** React Imports
import { Fragment } from 'react'
// ** Custom Components
import Breadcrumbs from '@components/breadcrumbs'
// ** Third Party Components
import { Row, Col } from 'reactstrap'
// ** Tables
import DataTable from './table'
// ** Styles
import '@styles/react/libs/tables/react-dataTable-component.scss'
// module settings
import moduleSettings from './module'
const Tables = () => {
return (
<Fragment>
<Breadcrumbs breadCrumbTitle='Episodes' breadCrumbParent='Episodes' breadCrumbActive={moduleSettings.mainTitle} />
<Row>
<Col sm='12'>
<DataTable />
</Col>
</Row>
</Fragment>
)
}
export default Tables
const moduleSettings = {
mainTitle: 'Episodes',
mainTitleSingle: 'Episode',
apiBaseURL: '/api/episodes',
baseURL: '/assets/episodes',
newElement: {
slug: 0,
type: 0
},
elementsOption: {
}
}
export default moduleSettings
\ No newline at end of file
import { Fragment, useState, useEffect, memo } from 'react'
// ** Table Columns
import { serverSideColumns } from './data'
// ** Store & Actions
import { getData_episodes} from '../store/actions'
import { useSelector, useDispatch } from 'react-redux'
import DataTableServerSide from '@components/datatable'
// module settings
import moduleSettings from './module'
const DataTable = () => {
// ** Store Vars
const dispatch = useDispatch()
const store = useSelector(state => state.assets)
const storeNavbar = useSelector(state => state.navbar)
useEffect(() => {
dispatch(getData_episodes({
start: 0,
length: 1000
}))
}, [storeNavbar.projectCurrent])
return (
<DataTableServerSide
cardTitle={moduleSettings.mainTitle}
allData={store.allDataEpisodes}
getData={getData_episodes}
serverSideColumns={serverSideColumns}
linkAddButton={`${moduleSettings.baseURL}/add`}
total={store.totalEpisodes}
/>
)
}
export default memo(DataTable)
...@@ -274,7 +274,7 @@ const handleError = (text) => { ...@@ -274,7 +274,7 @@ const handleError = (text) => {
}, [settingStore.selectedProject]) }, [settingStore.selectedProject])
useEffect(() => { useEffect(() => {
if (dataElement !== null && (!projectAssets.allDatatSeries || projectAssets.allDatatSeries.length < 1)) { if (dataElement !== null && (!projectAssets.allDataSeries || projectAssets.allDataSeries.length < 1)) {
dispatch(getData_series({ dispatch(getData_series({
start: 0, start: 0,
length: 1000, length: 1000,
......
import {store} from '@store/storeConfig/store'
import axios from 'axios'
import moduleSettings from '../../episodes/module'
import {setSaveSatus, setErrorMsg} from '../../../../redux/actions/api'
const _getData_episodes = params => {
return async dispatch => {
await axios.get(`${process.env.REACT_APP_API}${moduleSettings.apiBaseURL}`, {params}
).then(response => {
dispatch({
type: 'GET_DATA_EPISODES',
allData: response.data.data,
// datalayoumenus: response.data.invoices,
totalPages: response.data.recordsTotal,
params: response.data.params
})
})
}
}
export const getData_episodes = params => {
if (!!params.idproject && params.idproject !== null) {
const newparams = {
...params,
type: 'Episodes'
}
return _getData_episodes(newparams)
}
const currentProject = store.getState().navbar.projectCurrent
const newparams = {
...params,
idproject: !currentProject ? '%' : currentProject.value,
type: 'Episodes'
}
return _getData_episodes(newparams)
}
export const updateepisodes = params => {
return (dispatch, getState) => {
axios
.put(`${process.env.REACT_APP_API}${moduleSettings.apiBaseURL}/${params.id}`, params)
.then(response => {
dispatch({
type: 'UPDATE_ASSETS',
params
})
})
.then(() => {
dispatch(setSaveSatus(true))
})
.catch(err => {
const errosMsg = !err.response ? 'error' : err.response.data.message
console.log(errosMsg)
dispatch(setErrorMsg(errosMsg))
})
}
}
export const getepisode = id => {
return async dispatch => {
await axios
.get(`${process.env.REACT_APP_API}${moduleSettings.apiBaseURL}/${id}`)
.then(response => {
// console.log('leu')
// console.log(response)
dispatch({
type: 'GET_EPISODE',
data: response.data.data
})
})
.catch(err => console.log(err))
}
}
export const addepisode = params => {
return (dispatch, getState) => {
axios
.post(`${process.env.REACT_APP_API}${moduleSettings.apiBaseURL}`, params)
.then(response => {
dispatch({
type: 'ADD_ASSET',
params
})
})
.then(() => {
dispatch(setSaveSatus(true))
})
.catch(err => {
const errosMsg = !err.response ? 'error' : err.response.data.message
console.log(errosMsg)
dispatch(setErrorMsg(errosMsg))
})
}
}
\ No newline at end of file
...@@ -3,6 +3,7 @@ export * from './movies' ...@@ -3,6 +3,7 @@ export * from './movies'
export * from './lives' export * from './lives'
export * from './series' export * from './series'
export * from './seasons' export * from './seasons'
export * from './episodes'
export const resetResults = id => { export const resetResults = id => {
......
...@@ -35,7 +35,13 @@ const initialState = { ...@@ -35,7 +35,13 @@ const initialState = {
totalSeasons: 1, totalSeasons: 1,
paramsSeasons: {}, paramsSeasons: {},
allDataSeasons: [], allDataSeasons: [],
selectedSeason: null selectedSeason: null,
dataEpisodes: [],
totalEpisodes: 1,
paramsEpisodes: {},
allDataEpisodes: [],
selectedEpisode: null
} }
...@@ -122,6 +128,19 @@ const assets = (state = initialState, action) => { ...@@ -122,6 +128,19 @@ const assets = (state = initialState, action) => {
return { ...state, return { ...state,
selectedSeason : action.data selectedSeason : action.data
} }
// Episodes
case 'GET_DATA_EPISODES':
return {
...state,
allDataEpisodes: action.allData,
dataEpisodes: action.data,
totalEpisodes: action.totalPages,
paramsEpisodes: action.params
}
case 'GET_EPISODE':
return { ...state,
selectedEpisode : action.data
}
// default // default
default: default:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment