mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-11 03:24:16 +00:00
remove creator
This commit is contained in:
parent
5b48b72a5f
commit
79565eb041
@ -1,296 +0,0 @@
|
|||||||
import React from "react"
|
|
||||||
import * as antd from "antd"
|
|
||||||
import { DateTime } from "luxon"
|
|
||||||
import PostModel from "models/post"
|
|
||||||
|
|
||||||
import { Icons } from "components/Icons"
|
|
||||||
|
|
||||||
import "./index.less"
|
|
||||||
|
|
||||||
const UploadHint = (props) => {
|
|
||||||
return <div className="uploadHint">
|
|
||||||
<Icons.MdPlaylistAdd />
|
|
||||||
<p>Upload your tracks</p>
|
|
||||||
<p>Drag and drop your tracks here or click this box to start uploading files.</p>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Handle `cntr+v` to paste data from the clipboard to the post additions
|
|
||||||
// TODO: Send file deletion request to the server when user removes file from the list
|
|
||||||
// TODO: Make cover preview style more beautiful (E.G. Use the entire div as background)
|
|
||||||
// TODO: Make files list item can be dragged to change their order
|
|
||||||
// TODO: Make files can be modified (E.G. Change cover, change title, change artist, etc.)
|
|
||||||
|
|
||||||
export default (props) => {
|
|
||||||
const api = app.api.withEndpoints("main")
|
|
||||||
|
|
||||||
const [playlistName, setPlaylistName] = React.useState(null)
|
|
||||||
const [playlistDescription, setPlaylistDescription] = React.useState(null)
|
|
||||||
const [playlistArtist, setPlaylistArtist] = React.useState(null)
|
|
||||||
const [coverURL, setCoverURL] = React.useState(null)
|
|
||||||
const [fileList, setFileList] = React.useState([])
|
|
||||||
|
|
||||||
const [pending, setPending] = React.useState([])
|
|
||||||
const [loading, setLoading] = React.useState(false)
|
|
||||||
|
|
||||||
const handleTitleOnChange = (event) => {
|
|
||||||
const value = event.target.value
|
|
||||||
|
|
||||||
if (value === "") {
|
|
||||||
return setPlaylistName(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
return setPlaylistName(event.target.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleDescriptionOnChange = (event) => {
|
|
||||||
const value = event.target.value
|
|
||||||
|
|
||||||
if (value === "") {
|
|
||||||
return setPlaylistDescription(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
return setPlaylistDescription(event.target.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleArtistOnChange = (event) => {
|
|
||||||
const value = event.target.value
|
|
||||||
|
|
||||||
if (value === "") {
|
|
||||||
return setPlaylistArtist(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
return setPlaylistArtist(event.target.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleUploaderOnChange = (change) => {
|
|
||||||
switch (change.file.status) {
|
|
||||||
case "uploading": {
|
|
||||||
setPending([...pending, change.file.uid])
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case "done": {
|
|
||||||
const recivedFiles = []
|
|
||||||
|
|
||||||
// remove pending file
|
|
||||||
setPending(pending.filter(uid => uid !== change.file.uid))
|
|
||||||
|
|
||||||
// push to file list
|
|
||||||
if (Array.isArray(change.file.response)) {
|
|
||||||
recivedFiles.push(...change.file.response)
|
|
||||||
} else {
|
|
||||||
recivedFiles.push(change.file.response)
|
|
||||||
}
|
|
||||||
|
|
||||||
// add uid to files
|
|
||||||
recivedFiles.forEach((file) => {
|
|
||||||
file.uid = change.file.uid
|
|
||||||
})
|
|
||||||
|
|
||||||
setFileList([...fileList, ...recivedFiles])
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case "removed": {
|
|
||||||
// remove from file list
|
|
||||||
setFileList(fileList.filter(file => file.uid !== change.file.uid))
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleCoverUploaderOnChange = (change) => {
|
|
||||||
switch (change.file.status) {
|
|
||||||
case "uploading": {
|
|
||||||
setPending([...pending, change.file.uid])
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case "done": {
|
|
||||||
// remove pending file
|
|
||||||
setPending(pending.filter(uid => uid !== change.file.uid))
|
|
||||||
|
|
||||||
setCoverURL(change.file.response[0].url)
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case "removed": {
|
|
||||||
setCoverURL(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleUpload = async (req) => {
|
|
||||||
// get file data
|
|
||||||
const file = req.file
|
|
||||||
|
|
||||||
// append to form data
|
|
||||||
const formData = new FormData()
|
|
||||||
formData.append("files", file)
|
|
||||||
|
|
||||||
// send request
|
|
||||||
const request = await api.post.upload(formData, undefined).catch((error) => {
|
|
||||||
console.error(error)
|
|
||||||
antd.message.error(error)
|
|
||||||
req.onError(error)
|
|
||||||
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
if (request) {
|
|
||||||
return req.onSuccess(request)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const checkCanSubmit = () => {
|
|
||||||
const nameValid = playlistName !== null && playlistName.length !== 0
|
|
||||||
const filesListValid = fileList.length !== 0
|
|
||||||
const isPending = pending.length !== 0
|
|
||||||
|
|
||||||
return nameValid && filesListValid && !isPending
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
setLoading(true)
|
|
||||||
|
|
||||||
let RequestData = {
|
|
||||||
type: "playlist",
|
|
||||||
message: playlistDescription ?? "No description",
|
|
||||||
timestamp: DateTime.local().toISO(),
|
|
||||||
data: {
|
|
||||||
title: playlistName,
|
|
||||||
cover: coverURL,
|
|
||||||
artist: playlistArtist,
|
|
||||||
playlist: fileList.map((file) => {
|
|
||||||
return {
|
|
||||||
title: file.name,
|
|
||||||
cover: file.cover ?? coverURL,
|
|
||||||
artist: file.artist ?? "Unknown",
|
|
||||||
src: file.url,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await PostModel.create(RequestData).catch(error => {
|
|
||||||
console.error(error)
|
|
||||||
antd.message.error(error)
|
|
||||||
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
setLoading(false)
|
|
||||||
|
|
||||||
if (response) {
|
|
||||||
if (typeof props.close === "function") {
|
|
||||||
props.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return <div className="content">
|
|
||||||
<div className="playlistCreator">
|
|
||||||
<div className="inputField">
|
|
||||||
<Icons.MdOutlineMusicNote />
|
|
||||||
<antd.Input
|
|
||||||
className="inputText"
|
|
||||||
placeholder="Playlist Title"
|
|
||||||
size="large"
|
|
||||||
bordered={false}
|
|
||||||
onChange={handleTitleOnChange}
|
|
||||||
maxLength={120}
|
|
||||||
value={playlistName}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="inputField">
|
|
||||||
<Icons.MdOutlineDescription />
|
|
||||||
<antd.Input
|
|
||||||
className="inputText"
|
|
||||||
placeholder="Description"
|
|
||||||
bordered={false}
|
|
||||||
onChange={handleDescriptionOnChange}
|
|
||||||
maxLength={2500}
|
|
||||||
value={playlistDescription}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="inputField">
|
|
||||||
<Icons.MdOutlinePersonOutline />
|
|
||||||
<antd.Input
|
|
||||||
className="inputText"
|
|
||||||
placeholder="Artist"
|
|
||||||
bordered={false}
|
|
||||||
onChange={handleArtistOnChange}
|
|
||||||
maxLength={300}
|
|
||||||
value={playlistArtist}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="inputField">
|
|
||||||
<Icons.MdImage />
|
|
||||||
{
|
|
||||||
coverURL && <div className="coverPreview">
|
|
||||||
<img src={coverURL} alt="cover" />
|
|
||||||
<antd.Button
|
|
||||||
onClick={() => {
|
|
||||||
setCoverURL(null)
|
|
||||||
}}
|
|
||||||
icon={<Icons.MdClose />}
|
|
||||||
shape="round"
|
|
||||||
>
|
|
||||||
Remove Cover
|
|
||||||
</antd.Button>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
{
|
|
||||||
!coverURL && <antd.Upload
|
|
||||||
className="coverUploader"
|
|
||||||
customRequest={handleUpload}
|
|
||||||
onChange={handleCoverUploaderOnChange}
|
|
||||||
accept="image/*"
|
|
||||||
>
|
|
||||||
<antd.Button icon={<Icons.MdImage />}>Upload cover</antd.Button>
|
|
||||||
</antd.Upload>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="files">
|
|
||||||
<antd.Upload
|
|
||||||
className="uploader"
|
|
||||||
listType="picture"
|
|
||||||
customRequest={handleUpload}
|
|
||||||
onChange={handleUploaderOnChange}
|
|
||||||
accept="audio/*"
|
|
||||||
multiple
|
|
||||||
>
|
|
||||||
{fileList.length === 0 ? <UploadHint /> : <antd.Button icon={<Icons.MdCloudUpload />}>
|
|
||||||
Upload files
|
|
||||||
</antd.Button>}
|
|
||||||
</antd.Upload>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<antd.Button
|
|
||||||
type="primary"
|
|
||||||
size="large"
|
|
||||||
disabled={!checkCanSubmit()}
|
|
||||||
icon={<Icons.MdCampaign />}
|
|
||||||
loading={loading}
|
|
||||||
onClick={handleSubmit}
|
|
||||||
>
|
|
||||||
Publish
|
|
||||||
</antd.Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="footer">
|
|
||||||
<p>
|
|
||||||
Uploading files that are not permitted by our <a onClick={() => app.setLocation("/terms")}>Terms of Service</a> may result in your account being suspended.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
@ -1,135 +0,0 @@
|
|||||||
.playlistCreator {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.inputField {
|
|
||||||
display: inline-flex;
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
align-self: start;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
font-size: 2rem;
|
|
||||||
|
|
||||||
color: var(--text-color);
|
|
||||||
|
|
||||||
h1,
|
|
||||||
h2,
|
|
||||||
h3,
|
|
||||||
h4,
|
|
||||||
h5,
|
|
||||||
h6,
|
|
||||||
p,
|
|
||||||
span {
|
|
||||||
color: var(--text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.inputText {
|
|
||||||
width: 100%;
|
|
||||||
color: var(--text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.coverUploader {
|
|
||||||
width: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.coverPreview {
|
|
||||||
height: 5vh;
|
|
||||||
|
|
||||||
img {
|
|
||||||
height: 100%;
|
|
||||||
border-radius: 10px;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
|
||||||
margin: 0 !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.files {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
border-radius: 8px;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
padding: 10px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
.uploader,
|
|
||||||
.ant-upload {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-upload-list,
|
|
||||||
.ant-upload-list-picture-container {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-upload-list-item-thumbnail {
|
|
||||||
display: inline-flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-upload-list-item {
|
|
||||||
display: inline-flex;
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.uploadHint {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
align-self: center;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
font-size: 3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
position: relative;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
import React from "react"
|
|
||||||
|
|
||||||
import { PostCreator } from "components"
|
|
||||||
|
|
||||||
export default (props) => {
|
|
||||||
const handleOnPost = () => {
|
|
||||||
if (typeof props.close === "function") {
|
|
||||||
return props.close()
|
|
||||||
} else {
|
|
||||||
console.error("No close function provided")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return <div className="content">
|
|
||||||
<PostCreator onPost={handleOnPost} />
|
|
||||||
</div>
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
import React from "react"
|
|
||||||
|
|
||||||
export default (props) => {
|
|
||||||
return <div className="content">
|
|
||||||
<h1>Video Creator</h1>
|
|
||||||
</div>
|
|
||||||
}
|
|
@ -1,81 +0,0 @@
|
|||||||
import React from "react"
|
|
||||||
import { Button } from "antd"
|
|
||||||
import { Icons, createIconRender } from "components/Icons"
|
|
||||||
|
|
||||||
import PostCreator from "./creators/post"
|
|
||||||
import PlaylistCreator from "./creators/playlist"
|
|
||||||
import VideoCreator from "./creators/video"
|
|
||||||
|
|
||||||
import "./index.less"
|
|
||||||
|
|
||||||
const CreatorsTypes = {
|
|
||||||
post: {
|
|
||||||
label: "Text Post",
|
|
||||||
icon: "FileText",
|
|
||||||
component: PostCreator
|
|
||||||
},
|
|
||||||
playlist: {
|
|
||||||
label: "Playlist",
|
|
||||||
icon: "Music",
|
|
||||||
component: PlaylistCreator
|
|
||||||
},
|
|
||||||
video: {
|
|
||||||
label: "Video",
|
|
||||||
icon: "Video",
|
|
||||||
component: VideoCreator,
|
|
||||||
disabled: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class Creator extends React.Component {
|
|
||||||
state = {
|
|
||||||
type: null
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCreatorType = (type) => {
|
|
||||||
this.setState({ type })
|
|
||||||
}
|
|
||||||
|
|
||||||
renderCreator = (...props) => {
|
|
||||||
if (!this.state.type) {
|
|
||||||
return <div className="typeSelector">
|
|
||||||
{Object.keys(CreatorsTypes).map((type) => {
|
|
||||||
const { label, icon = "PlusCircle" } = CreatorsTypes[type]
|
|
||||||
|
|
||||||
return <Button
|
|
||||||
key={type}
|
|
||||||
className="typeButton"
|
|
||||||
disabled={CreatorsTypes[type].disabled}
|
|
||||||
icon={createIconRender(icon)}
|
|
||||||
onClick={() => this.handleCreatorType(type)}
|
|
||||||
>
|
|
||||||
{label}
|
|
||||||
</Button>
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!CreatorsTypes[this.state.type]) {
|
|
||||||
return <div className="content">
|
|
||||||
<h1>Creator not found</h1>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
return React.createElement(CreatorsTypes[this.state.type].component, this.props)
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return <div className="creator">
|
|
||||||
<div className="header">
|
|
||||||
<h1><Icons.Box /> Creator</h1>
|
|
||||||
{!this.state.type ? <p><Icons.MdInfoOutline /> Select an type to start creating...</p> : <div>
|
|
||||||
<Button icon={<Icons.ChevronLeft />} onClick={() => this.handleCreatorType()}>
|
|
||||||
Back
|
|
||||||
</Button>
|
|
||||||
</div>}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{this.renderCreator()}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
.creator {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
color: var(--text-color);
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 2.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1,
|
|
||||||
h2,
|
|
||||||
h3,
|
|
||||||
h4,
|
|
||||||
h5,
|
|
||||||
h6,
|
|
||||||
p,
|
|
||||||
span {
|
|
||||||
color: var(--text-color);
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.typeSelector {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
.typeButton {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
height: 100px;
|
|
||||||
width: 100px;
|
|
||||||
|
|
||||||
padding: 20px;
|
|
||||||
margin: 0 10px;
|
|
||||||
|
|
||||||
font-size: 1.2rem;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
font-size: 3rem;
|
|
||||||
margin: 0 0 5px 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user