2024-09-10 00:47:03 +00:00
< template >
< div class = "editor" >
2024-10-06 00:45:56 +00:00
< p
v - if = "submitted"
class = "submitted"
>
< template v-if ="apply" > Your revision has been submitted. Thank you for your contribution ! < / template >
< template v-else > Your revision has been submitted for review. Thank you for your contribution ! < / template >
< ul >
< li >
< a
: href = "`/scene/${scene.id}/${scene.slug}`"
class = "link"
> Return to scene < / a >
< / li >
< li >
< a
: href = "`/scene/edit/${scene.id}`"
class = "link"
> Make another edit < / a >
< / li >
< li >
< a
2024-10-08 22:09:45 +00:00
: href = "`/scene/revisions/${scene.id}/${scene.slug}`"
2024-10-06 00:45:56 +00:00
class = "link"
2024-10-08 22:09:45 +00:00
> Go to scene revisions < / a >
< / li >
< li >
< a
: href = "`/user/${user.username}/revisions`"
class = "link"
> Go to user revisions < / a >
< / li >
< li v-if ="user.role !== 'user'" >
< a
href = "/admin/revisions"
class = "link"
> Go to revisions admin < / a >
2024-10-06 00:45:56 +00:00
< / li >
< / ul >
< / p >
< form
v - else
@ submit . prevent
>
2024-09-10 00:47:03 +00:00
< div class = "editor-header" >
< h2 class = "heading ellipsis" > Edit scene # { { scene . id } } < / h2 >
< a
: href = "`/scene/${scene.id}/${scene.slug}`"
target = "_blank"
class = "link noshrink"
> Go to scene < / a >
< / div >
< ul class = "nolist" >
< li
v - for = "item in fields"
: key = "`item-${item.key}`"
class = "row"
>
< div class = "item-header" >
< div class = "key" > { { item . label || item . key } } < / div >
< div class = "item-actions" >
< Icon
v - if = "!item.forced"
icon = "pencil5"
: class = "{ active: editing.has(item.key) }"
@ click = "toggleField(item)"
/ >
< / div >
< / div >
< div
class = "value"
: class = "{ disabled: !editing.has(item.key) }"
>
< EditActors
v - if = "item.type === 'actors'"
: scene = "scene"
: item = "item"
: edits = "edits"
: editing = "editing"
@ actors = "(actors) => { edits.actors = actors; }"
/ >
< EditTags
v - if = "item.type === 'tags'"
: scene = "scene"
: item = "item"
: edits = "edits"
: editing = "editing"
@ tags = "(tags) => { edits.tags = tags; }"
/ >
2024-10-06 00:45:56 +00:00
< EditMovies
v - if = "item.type === 'movies'"
: scene = "scene"
: item = "item"
: edits = "edits"
: editing = "editing"
@ movies = "(movies) => { edits.movies = movies; }"
/ >
2024-09-10 00:47:03 +00:00
< input
v - if = "item.type === 'string'"
: value = "edits[item.key] || item.value"
class = "string input"
: disabled = "!editing.has(item.key)"
@ input = "setValue(item, $event)"
>
< textarea
v - if = "item.type === 'text'"
: value = "edits[item.key] || item.value"
: placeholder = "item.placeholder"
rows = "3"
class = "text input"
: disabled = "!editing.has(item.key)"
@ input = "setValue(item, $event)"
/ >
< input
v - if = "item.type === 'date'"
type = "datetime-local"
: value = "edits[item.key] || item.value"
class = "date input"
: disabled = "!editing.has(item.key)"
@ input = "setValue(item, $event)"
>
< div
v - if = "item.type === 'duration'"
class = "duration"
>
< input
type = "number"
class = "input"
2024-10-06 21:54:54 +00:00
: value = "edits[item.key]?.[0] ?? item.value[0]"
2024-09-10 00:47:03 +00:00
min = "0"
max = "100"
: disabled = "!editing.has(item.key)"
2024-10-06 21:54:54 +00:00
@ change = "setDuration('h', $event)"
2024-09-10 00:47:03 +00:00
> H
< input
type = "number"
class = "input"
2024-10-06 21:54:54 +00:00
: value = "edits[item.key]?.[1] ?? item.value[1]"
2024-09-10 00:47:03 +00:00
min = "0"
max = "59"
: disabled = "!editing.has(item.key)"
2024-10-06 21:54:54 +00:00
@ change = "setDuration('m', $event)"
2024-09-10 00:47:03 +00:00
> M
< input
type = "number"
class = "input"
2024-10-06 21:54:54 +00:00
: value = "edits[item.key]?.[2] ?? item.value[2]"
2024-09-10 00:47:03 +00:00
min = "0"
max = "59"
: disabled = "!editing.has(item.key)"
2024-10-06 21:54:54 +00:00
@ change = "setDuration('s', $event)"
2024-09-10 00:47:03 +00:00
> S
< / div >
< / div >
< / li >
< / ul >
< div class = "editor-footer" >
< div class = "comment" >
< textarea
v - model = "comment"
rows = "3"
placeholder = "Please provide verifiable information supporting your edits."
class = "text input"
/ >
< / div >
< div class = "editor-actions" >
2024-10-06 00:45:56 +00:00
< Checkbox
v - if = "user.role !== 'user'"
label = "Approve and apply immediately"
: checked = "apply"
: disabled = "editing.size === 0"
@ change = "(checked) => apply = checked"
/ >
2024-09-10 00:47:03 +00:00
<!-- we don ' t want the return key to submit the form -- >
< button
class = "button button-primary"
type = "button"
: disabled = "editing.size === 0"
@ click = "submit"
2024-10-06 00:45:56 +00:00
>
< template v-if ="apply" > Submit < / template >
< template v-else > Submit for review < / template >
< / button >
2024-09-10 00:47:03 +00:00
< / div >
< / div >
< / form >
< / div >
< / template >
< script setup >
import { ref , computed , inject } from 'vue' ;
import { format } from 'date-fns' ;
import EditActors from '#/components/edit/actors.vue' ;
import EditTags from '#/components/edit/tags.vue' ;
2024-10-06 00:45:56 +00:00
import EditMovies from '#/components/edit/movies.vue' ;
import Checkbox from '#/components/form/checkbox.vue' ;
2024-09-10 00:47:03 +00:00
2024-10-06 00:45:56 +00:00
import {
// get,
post ,
} from '#/src/api.js' ;
2024-09-10 00:47:03 +00:00
const pageContext = inject ( 'pageContext' ) ;
const user = pageContext . user ;
const scene = ref ( pageContext . pageProps . scene ) ;
const fields = computed ( ( ) => [
{
key : 'actors' ,
type : 'actors' ,
value : scene . value . actors ,
} ,
{
key : 'tags' ,
type : 'tags' ,
2024-10-12 20:35:58 +00:00
value : scene . value . tags . toSorted ( ( tagA , tagB ) => tagA . name . localeCompare ( tagB . name ) ) ,
2024-09-10 00:47:03 +00:00
} ,
2024-10-06 00:45:56 +00:00
{
key : 'movies' ,
type : 'movies' ,
value : scene . value . movies ,
} ,
2024-09-10 00:47:03 +00:00
{
key : 'title' ,
type : 'string' ,
value : scene . value . title ,
} ,
{
key : 'description' ,
type : 'text' ,
value : scene . value . description ,
} ,
{
key : 'date' ,
type : 'date' ,
value : scene . value . date
? format ( scene . value . date , 'yyyy-MM-dd hh:mm' )
: null ,
} ,
{
key : 'duration' ,
type : 'duration' ,
value : [ Math . floor ( scene . value . duration / 3600 ) , Math . floor ( ( scene . value . duration % 3600 ) / 60 ) , scene . value . duration % 60 ] ,
} ,
{
key : 'productionDate' ,
label : 'production date' ,
type : 'date' ,
value : scene . value . productionDate
? format ( scene . value . productionDate , 'yyyy-MM-dd hh:mm' )
: null ,
} ,
... ( user . role === 'user'
? [ ]
: [ {
key : 'comment' ,
type : 'text' ,
placeholder : 'Do NOT use this field to summarize and clarify your revision. This field is for permanent notes and comments regarding the scene or database entry itself.' ,
value : scene . value . comment ,
} ] ) ,
] ) ;
const editing = ref ( new Set ( ) ) ;
const edits = ref ( { } ) ;
const comment = ref ( null ) ;
2024-10-06 00:45:56 +00:00
const apply = ref ( user . role !== 'user' ) ;
const submitted = ref ( false ) ;
2024-09-10 00:47:03 +00:00
function toggleField ( item ) {
if ( editing . value . has ( item . key ) ) {
editing . value . delete ( item . key ) ;
delete edits . value [ item . key ] ;
return ;
}
2024-10-06 00:45:56 +00:00
2024-09-10 00:47:03 +00:00
editing . value . add ( item . key ) ;
if ( Array . isArray ( item . value ) ) {
edits . value [ item . key ] = item . value . map ( ( value ) => value . hash || value . id ) ;
return ;
}
edits . value [ item . key ] = item . value ;
}
function setValue ( item , event ) {
edits . value [ item . key ] = event . target . value ;
}
const timeUnits = [ 'h' , 'm' , 's' ] ;
function setDuration ( unit , event ) {
edits . value . duration [ timeUnits . indexOf ( unit ) ] = Number ( event . target . value ) ;
}
async function submit ( ) {
try {
2024-10-06 00:45:56 +00:00
await post ( '/revisions' , {
sceneId : scene . value . id ,
2024-09-10 00:47:03 +00:00
edits : {
... edits . value ,
duration : edits . value . duration
2024-10-06 21:42:43 +00:00
? ( ( ( edits . value . duration [ 0 ] || 0 ) * 3600 ) + ( ( edits . value . duration [ 1 ] || 0 ) * 60 ) + ( edits . value . duration [ 2 ] || 0 ) ) || null
2024-09-10 00:47:03 +00:00
: undefined ,
} ,
comment : comment . value ,
2024-10-06 00:45:56 +00:00
apply : apply . value ,
2024-09-10 00:47:03 +00:00
} , {
successFeedback : 'Your revision has been submitted for approval.' ,
appendErrorMessage : true ,
} ) ;
editing . value = new Set ( ) ;
edits . value = { } ;
comment . value = null ;
2024-10-06 00:45:56 +00:00
submitted . value = true ;
2024-09-10 00:47:03 +00:00
2024-10-06 00:45:56 +00:00
// scene.value = await get(`/scenes/${scene.value.id}`);
2024-09-10 00:47:03 +00:00
} catch ( error ) {
// do nothing
}
}
< / script >
< style scoped >
. editor {
flex - grow : 1 ;
2024-10-06 00:45:56 +00:00
background : var ( -- background - dark - 10 ) ;
2024-09-10 00:47:03 +00:00
}
. editor - header {
display : flex ;
justify - content : space - between ;
align - items : center ;
padding : 1 rem ;
}
. heading {
margin : 0 ;
}
. row {
display : flex ;
align - items : center ;
padding : .25 rem 1 rem ;
}
. key {
width : 8 rem ;
text - transform : capitalize ;
font - weight : bold ;
}
2024-10-06 00:45:56 +00:00
. input {
background : var ( -- background ) ;
}
2024-09-10 00:47:03 +00:00
. item - header {
display : flex ;
align - items : center ;
}
. value {
flex - grow : 1 ;
. input {
width : 100 % ;
& : disabled {
color : var ( -- glass - strong - 10 ) ;
background : none ;
border : solid 1 px var ( -- glass - weak - 30 ) ;
}
}
. duration {
. input {
width : 5 rem ;
margin - right : .25 rem ;
& : not ( : first - child ) {
margin - left : .75 rem ;
}
}
}
& . disabled {
pointer - events : none ;
}
}
. item - actions {
. icon {
padding : .25 rem 1 rem ;
fill : var ( -- glass ) ;
overflow : hidden ;
& : hover {
cursor : pointer ;
fill : var ( -- text ) ;
}
& . active {
fill : var ( -- primary ) ;
}
}
}
. editor - footer {
display : flex ;
flex - direction : column ;
align - items : center ;
gap : 1 rem ;
padding : 1 rem 1 rem 0 1 rem ;
border - top : solid 1 px var ( -- primary - light - 30 ) ;
margin : 1 rem 0 ;
}
. comment {
width : 100 % ;
flex - shrink : 0 ;
. input {
width : 100 % ;
resize : vertical ;
}
}
. editor - actions {
display : flex ;
2024-10-06 00:45:56 +00:00
flex - direction : column ;
2024-09-10 00:47:03 +00:00
align - items : center ;
2024-10-06 00:45:56 +00:00
gap : 1.5 rem ;
margin : .5 rem 0 ;
2024-09-10 00:47:03 +00:00
. button {
padding : .5 rem 1 rem ;
font - size : 1.1 rem ;
}
}
2024-10-06 00:45:56 +00:00
. submitted {
display : flex ;
flex - direction : column ;
align - items : center ;
padding : 1 rem ;
font - weight : bold ;
line - height : 1.5 ;
}
2024-09-10 00:47:03 +00:00
@ media ( -- small ) {
. row {
flex - direction : column ;
align - items : stretch ;
margin - bottom : .25 rem ;
}
. item - header {
margin - bottom : .25 rem ;
}
. key {
flex - grow : 1 ;
}
}
< / style >