2023-04-23 08:26:39 -05:00
// Copyright (C) 2022-present Daniel31x13 <daniel31x13@gmail.com>
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3.
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
2023-05-26 23:29:45 -05:00
import React , { useState } from "react" ;
2023-04-24 16:30:40 -05:00
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" ;
2023-05-26 14:52:18 -05:00
import {
faClose ,
2023-05-26 23:29:45 -05:00
faPenToSquare ,
2023-05-26 14:52:18 -05:00
faUser ,
faUserPlus ,
} from "@fortawesome/free-solid-svg-icons" ;
2023-04-24 16:30:40 -05:00
import useCollectionStore from "@/store/collections" ;
2023-05-26 23:11:29 -05:00
import { CollectionIncludingMembers , Member } from "@/types/global" ;
2023-04-26 15:40:48 -05:00
import { useSession } from "next-auth/react" ;
2023-05-23 18:07:26 -05:00
import addMemberToCollection from "@/lib/client/addMemberToCollection" ;
2023-05-28 00:55:49 -05:00
import ImageWithFallback from "../../ImageWithFallback" ;
import Checkbox from "../../Checkbox" ;
2023-04-23 08:26:39 -05:00
2023-04-24 16:30:40 -05:00
type Props = {
toggleCollectionModal : Function ;
2023-05-26 23:29:45 -05:00
activeCollection : CollectionIncludingMembers ;
2023-04-24 16:30:40 -05:00
} ;
2023-04-23 08:26:39 -05:00
2023-05-28 00:55:49 -05:00
export default function TeamManagement ( {
2023-05-26 23:29:45 -05:00
toggleCollectionModal ,
activeCollection ,
} : Props ) {
const [ collection , setCollection ] =
useState < CollectionIncludingMembers > ( activeCollection ) ;
2023-04-23 08:26:39 -05:00
2023-05-28 00:55:49 -05:00
const [ isPublic , setIsPublic ] = useState ( false ) ;
const currentURL = new URL ( document . URL ) ;
const publicCollectionURL = ` ${ currentURL . origin } /public/collections/ ${ collection . id } ` ;
2023-05-26 23:11:29 -05:00
const [ member , setMember ] = useState < Member > ( {
canCreate : false ,
canUpdate : false ,
canDelete : false ,
user : {
name : "" ,
email : "" ,
} ,
} ) ;
2023-04-26 15:40:48 -05:00
2023-05-28 00:55:49 -05:00
const { updateCollection } = useCollectionStore ( ) ;
2023-04-23 08:26:39 -05:00
2023-05-26 23:29:45 -05:00
const session = useSession ( ) ;
2023-05-26 23:11:29 -05:00
const setMemberState = ( newMember : Member ) = > {
if ( ! collection ) return null ;
setCollection ( {
. . . collection ,
members : [ . . . collection . members , newMember ] ,
2023-05-23 18:07:26 -05:00
} ) ;
2023-05-26 23:11:29 -05:00
setMember ( {
canCreate : false ,
canUpdate : false ,
canDelete : false ,
user : {
name : "" ,
email : "" ,
} ,
} ) ;
2023-05-23 18:07:26 -05:00
} ;
2023-05-26 23:29:45 -05:00
const submit = async ( ) = > {
if ( ! collection ) return null ;
2023-05-28 00:55:49 -05:00
const response = await updateCollection ( collection ) ;
2023-05-26 23:29:45 -05:00
if ( response ) toggleCollectionModal ( ) ;
} ;
2023-04-24 16:30:40 -05:00
return (
< div className = "flex flex-col gap-3 sm:w-[35rem] w-80" >
2023-05-28 00:55:49 -05:00
< p className = "text-xl text-sky-500 mb-2 text-center w-5/6 mx-auto" >
Sharing & Collaboration Settings
2023-05-26 23:29:45 -05:00
< / p >
2023-05-16 12:08:28 -05:00
2023-05-28 00:55:49 -05:00
< p className = "text-sm font-bold text-sky-300" > Make Public < / p >
2023-05-26 23:29:45 -05:00
< Checkbox
label = "Make this a public collection."
2023-05-28 00:55:49 -05:00
state = { isPublic }
onClick = { ( ) = > setIsPublic ( ! isPublic ) }
2023-05-26 23:29:45 -05:00
/ >
2023-05-28 00:55:49 -05:00
2023-05-26 23:29:45 -05:00
< p className = "text-gray-500 text-sm" >
2023-05-28 00:55:49 -05:00
This will let < b > Anyone < / b > to view this collection .
< / p >
{ isPublic ? (
< div >
< p className = "mb-2 text-gray-500" > Public Link ( Click to copy ) < / p >
< div
2023-05-28 12:22:01 -05:00
onClick = { ( ) = > {
try {
navigator . clipboard
. writeText ( publicCollectionURL )
. then ( ( ) = > console . log ( "Copied!" ) ) ;
} catch ( err ) {
alert ( err ) ;
console . log ( err ) ;
}
} }
2023-05-28 00:55:49 -05:00
className = "w-full hide-scrollbar overflow-x-auto whitespace-nowrap rounded-md p-3 border-sky-100 border-solid border outline-none hover:border-sky-500 duration-100 cursor-text"
>
{ publicCollectionURL }
< / div >
< / div >
) : null }
< hr / >
< p className = "text-sm font-bold text-sky-300" > Member Management < / p >
2023-04-26 15:40:48 -05:00
2023-05-23 18:07:26 -05:00
< div className = "relative" >
< input
2023-05-26 23:11:29 -05:00
value = { member . user . email }
2023-05-23 18:07:26 -05:00
onChange = { ( e ) = > {
2023-05-26 23:11:29 -05:00
setMember ( {
. . . member ,
user : { . . . member . user , email : e.target.value } ,
} ) ;
2023-05-23 18:07:26 -05:00
} }
2023-05-28 00:55:49 -05:00
onKeyDown = { ( e ) = >
e . key === "Enter" &&
addMemberToCollection (
session . data ? . user . email as string ,
member . user . email ,
collection ,
setMemberState
)
}
2023-05-23 18:07:26 -05:00
type = "text"
placeholder = "Email"
className = "w-full rounded-md p-3 pr-12 border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100"
/ >
< div
onClick = { ( ) = >
addMemberToCollection (
session . data ? . user . email as string ,
2023-05-26 23:29:45 -05:00
member . user . email ,
2023-05-26 23:11:29 -05:00
collection ,
setMemberState
2023-05-23 18:07:26 -05:00
)
2023-05-16 12:08:28 -05:00
}
2023-05-23 18:07:26 -05:00
className = "absolute flex items-center justify-center right-2 top-2 bottom-2 bg-sky-500 hover:bg-sky-400 duration-100 text-white w-9 rounded-md cursor-pointer"
>
2023-05-26 14:52:18 -05:00
< FontAwesomeIcon icon = { faUserPlus } className = "w-6 h-6" / >
2023-05-23 18:07:26 -05:00
< / div >
< / div >
2023-05-26 23:11:29 -05:00
{ collection ? . members [ 0 ] ? . user ? (
< >
< p className = "text-center text-gray-500 text-xs sm:text-sm" >
( All Members have < b > Read < / b > access to this collection . )
< / p >
2023-04-26 15:40:48 -05:00
2023-05-28 00:55:49 -05:00
< div className = "max-h-[20rem] overflow-auto flex flex-col gap-3 rounded-md shadow-inner" >
2023-05-28 12:22:01 -05:00
{ collection . members
. sort ( ( a , b ) = > ( a . userId as number ) - ( b . userId as number ) )
. map ( ( e , i ) = > {
return (
< div
key = { i }
className = "relative border p-2 rounded-md border-sky-100 flex flex-col sm:flex-row sm:items-center gap-2 justify-between"
>
< FontAwesomeIcon
icon = { faClose }
className = "absolute right-2 top-2 text-gray-500 h-4 hover:text-red-500 duration-100 cursor-pointer"
title = "Remove Member"
onClick = { ( ) = > {
const updatedMembers = collection . members . filter (
( member ) = > {
return member . user . email !== e . user . email ;
}
) ;
setCollection ( {
. . . collection ,
members : updatedMembers ,
} ) ;
} }
/ >
< div className = "flex items-center gap-2" >
< ImageWithFallback
key = { i }
src = { ` /api/avatar/ ${ e . userId } ` }
className = "h-10 w-10 shadow rounded-full border-[3px] border-sky-100"
>
< div className = "text-white bg-sky-500 h-10 w-10 shadow rounded-full border-[3px] border-sky-100 flex items-center justify-center" >
< FontAwesomeIcon icon = { faUser } className = "w-5 h-5" / >
< / div >
< / ImageWithFallback >
< div >
< p className = "text-sm font-bold text-sky-500" >
{ e . user . name }
< / p >
< p className = "text-sky-900" > { e . user . email } < / p >
2023-05-26 23:11:29 -05:00
< / div >
< / div >
2023-05-28 12:22:01 -05:00
< div className = "flex sm:block items-center gap-5" >
< div >
< p className = "font-bold text-sm text-gray-500" >
Permissions
< / p >
< p className = "text-xs text-gray-400 mb-2" >
( Click to toggle . )
< / p >
< / div >
2023-04-27 18:13:21 -05:00
2023-05-28 12:22:01 -05:00
< div >
< label className = "cursor-pointer mr-1" >
< input
type = "checkbox"
id = "canCreate"
className = "peer sr-only"
checked = { e . canCreate }
onChange = { ( ) = > {
const updatedMembers = collection . members . map (
( member ) = > {
if ( member . user . email === e . user . email ) {
return {
. . . member ,
canCreate : ! e . canCreate ,
} ;
}
return member ;
2023-05-26 23:11:29 -05:00
}
2023-05-28 12:22:01 -05:00
) ;
setCollection ( {
. . . collection ,
members : updatedMembers ,
} ) ;
} }
/ >
< span className = "text-sky-900 peer-checked:bg-sky-500 text-sm hover:bg-sky-200 duration-75 peer-checked:text-white rounded p-1 select-none" >
Create
< / span >
< / label >
2023-04-27 18:13:21 -05:00
2023-05-28 12:22:01 -05:00
< label className = "cursor-pointer mr-1" >
< input
type = "checkbox"
id = "canUpdate"
className = "peer sr-only"
checked = { e . canUpdate }
onChange = { ( ) = > {
const updatedMembers = collection . members . map (
( member ) = > {
if ( member . user . email === e . user . email ) {
return {
. . . member ,
canUpdate : ! e . canUpdate ,
} ;
}
return member ;
2023-05-26 23:11:29 -05:00
}
2023-05-28 12:22:01 -05:00
) ;
setCollection ( {
. . . collection ,
members : updatedMembers ,
} ) ;
} }
/ >
< span className = "text-sky-900 peer-checked:bg-sky-500 text-sm hover:bg-sky-200 duration-75 peer-checked:text-white rounded p-1 select-none" >
Update
< / span >
< / label >
2023-04-27 18:13:21 -05:00
2023-05-28 12:22:01 -05:00
< label className = "cursor-pointer mr-1" >
< input
type = "checkbox"
id = "canDelete"
className = "peer sr-only"
checked = { e . canDelete }
onChange = { ( ) = > {
const updatedMembers = collection . members . map (
( member ) = > {
if ( member . user . email === e . user . email ) {
return {
. . . member ,
canDelete : ! e . canDelete ,
} ;
}
return member ;
2023-05-26 23:11:29 -05:00
}
2023-05-28 12:22:01 -05:00
) ;
setCollection ( {
. . . collection ,
members : updatedMembers ,
} ) ;
} }
/ >
< span className = "text-sky-900 peer-checked:bg-sky-500 text-sm hover:bg-sky-200 duration-75 peer-checked:text-white rounded p-1 select-none" >
Delete
< / span >
< / label >
< / div >
2023-05-26 23:11:29 -05:00
< / div >
< / div >
2023-05-28 12:22:01 -05:00
) ;
} ) }
2023-05-26 23:11:29 -05:00
< / div >
< / >
) : null }
2023-04-26 15:40:48 -05:00
2023-05-26 23:29:45 -05:00
< div className = "flex flex-col justify-center items-center gap-2 mt-2" >
< div
className = "bg-sky-500 text-white flex items-center gap-2 py-2 px-5 rounded-md select-none font-bold cursor-pointer duration-100 hover:bg-sky-400"
onClick = { submit }
>
2023-05-28 00:55:49 -05:00
< FontAwesomeIcon icon = { faPenToSquare } className = "h-5" / >
Edit Collection
2023-05-26 23:29:45 -05:00
< / div >
2023-04-24 16:30:40 -05:00
< / div >
< / div >
) ;
}