remove creator

This commit is contained in:
SrGooglo 2023-02-24 14:30:48 +00:00
parent 5b48b72a5f
commit 79565eb041
6 changed files with 0 additions and 614 deletions

View File

@ -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>
}

View File

@ -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;
}
}

View File

@ -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>
}

View File

@ -1,7 +0,0 @@
import React from "react"
export default (props) => {
return <div className="content">
<h1>Video Creator</h1>
</div>
}

View File

@ -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>
}
}

View File

@ -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;
}
}