Dashboards in Group about page
This commit is contained in:
parent
851cffd73e
commit
6372d262cb
|
@ -10,6 +10,7 @@ export type Group = {
|
|||
anyoneCanJoin: boolean
|
||||
contractIds: string[]
|
||||
|
||||
dashboardId?: string
|
||||
chatDisabled?: boolean
|
||||
mostRecentChatActivityTime?: number
|
||||
mostRecentContractAddedTime?: number
|
||||
|
|
|
@ -160,7 +160,7 @@ service cloud.firestore {
|
|||
allow update: if request.auth.uid == resource.data.creatorId
|
||||
&& request.resource.data.diff(resource.data)
|
||||
.affectedKeys()
|
||||
.hasOnly(['name', 'about', 'contractIds', 'memberIds', 'anyoneCanJoin' ]);
|
||||
.hasOnly(['name', 'about', 'contractIds', 'memberIds', 'anyoneCanJoin', 'dashboardId' ]);
|
||||
allow update: if (request.auth.uid in resource.data.memberIds || resource.data.anyoneCanJoin)
|
||||
&& request.resource.data.diff(resource.data)
|
||||
.affectedKeys()
|
||||
|
|
143
web/components/groups/group-dashboard.tsx
Normal file
143
web/components/groups/group-dashboard.tsx
Normal file
|
@ -0,0 +1,143 @@
|
|||
import { useAdmin } from 'web/hooks/use-admin'
|
||||
import { Row } from '../layout/row'
|
||||
import { Content } from '../editor'
|
||||
import { TextEditor, useTextEditor } from 'web/components/editor'
|
||||
import { Button } from '../button'
|
||||
import { Spacer } from '../layout/spacer'
|
||||
import { Group } from 'common/group'
|
||||
import { deleteFieldFromGroup, updateGroup } from 'web/lib/firebase/groups'
|
||||
import PencilIcon from '@heroicons/react/solid/PencilIcon'
|
||||
import { DocumentRemoveIcon } from '@heroicons/react/solid'
|
||||
import { createDashboard } from 'web/lib/firebase/api'
|
||||
import { Dashboard } from 'common/dashboard'
|
||||
import { deleteDashboard, updateDashboard } from 'web/lib/firebase/dashboards'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useState } from 'react'
|
||||
|
||||
export function GroupDashboard(props: {
|
||||
group: Group
|
||||
isCreator: boolean
|
||||
dashboard: Dashboard
|
||||
}) {
|
||||
const { group, isCreator, dashboard } = props
|
||||
const isAdmin = useAdmin()
|
||||
|
||||
if (group.dashboardId == null && !isCreator) {
|
||||
return <p className="text-center">No dashboard has been created </p>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rounded-md bg-white p-4">
|
||||
{isCreator || isAdmin ? (
|
||||
<RichEditGroupDashboard group={group} dashboard={dashboard} />
|
||||
) : (
|
||||
<Content content={dashboard.content} />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function RichEditGroupDashboard(props: { group: Group; dashboard: Dashboard }) {
|
||||
const { group, dashboard } = props
|
||||
const [editing, setEditing] = useState(false)
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
const router = useRouter()
|
||||
|
||||
const { editor, upload } = useTextEditor({
|
||||
defaultValue: dashboard.content,
|
||||
disabled: isSubmitting,
|
||||
})
|
||||
|
||||
async function saveDashboard() {
|
||||
if (!editor) return
|
||||
const newDashboard = {
|
||||
name: group.name,
|
||||
content: editor.getJSON(),
|
||||
}
|
||||
|
||||
if (group.dashboardId == null) {
|
||||
const result = await createDashboard(newDashboard).catch((e) => {
|
||||
console.error(e)
|
||||
return e
|
||||
})
|
||||
await updateGroup(group, {
|
||||
dashboardId: result.dashboard.id,
|
||||
})
|
||||
} else {
|
||||
await updateDashboard(dashboard, {
|
||||
content: newDashboard.content,
|
||||
})
|
||||
}
|
||||
await router.replace(router.asPath)
|
||||
}
|
||||
|
||||
async function deleteGroupDashboard() {
|
||||
await deleteDashboard(dashboard)
|
||||
await deleteFieldFromGroup(group, 'dashboardId')
|
||||
await router.replace(router.asPath)
|
||||
}
|
||||
|
||||
return editing ? (
|
||||
<>
|
||||
<TextEditor editor={editor} upload={upload} />
|
||||
<Spacer h={2} />
|
||||
<Row className="gap-2">
|
||||
<Button
|
||||
onClick={async () => {
|
||||
setIsSubmitting(true)
|
||||
await saveDashboard()
|
||||
setEditing(false)
|
||||
setIsSubmitting(false)
|
||||
}}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
<Button color="gray" onClick={() => setEditing(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
</Row>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{group.dashboardId == null ? (
|
||||
<div className="text-center text-gray-500">
|
||||
<p className="text-sm">
|
||||
No dashboard has been created yet.
|
||||
<Spacer h={2} />
|
||||
<Button onClick={() => setEditing(true)}>Create a dashboard</Button>
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="relative">
|
||||
<div className="absolute top-0 right-0 z-10 space-x-2">
|
||||
<Button
|
||||
color="gray"
|
||||
size="xs"
|
||||
onClick={() => {
|
||||
setEditing(true)
|
||||
editor?.commands.focus('end')
|
||||
}}
|
||||
>
|
||||
<PencilIcon className="inline h-4 w-4" />
|
||||
Edit
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
color="gray"
|
||||
size="xs"
|
||||
onClick={() => {
|
||||
deleteGroupDashboard()
|
||||
}}
|
||||
>
|
||||
<DocumentRemoveIcon className="inline h-4 w-4" />
|
||||
Delete
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Content content={dashboard.content} />
|
||||
<Spacer h={2} />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import {
|
||||
deleteDoc,
|
||||
deleteField,
|
||||
doc,
|
||||
getDocs,
|
||||
query,
|
||||
|
@ -17,6 +18,7 @@ import {
|
|||
} from './utils'
|
||||
import { Contract } from 'common/contract'
|
||||
import { updateContract } from 'web/lib/firebase/contracts'
|
||||
import * as admin from 'firebase-admin'
|
||||
|
||||
export const groups = coll<Group>('groups')
|
||||
|
||||
|
@ -28,6 +30,7 @@ export function groupPath(
|
|||
| 'about'
|
||||
| typeof GROUP_CHAT_SLUG
|
||||
| 'leaderboards'
|
||||
| 'dashboard'
|
||||
) {
|
||||
return `/group/${groupSlug}${subpath ? `/${subpath}` : ''}`
|
||||
}
|
||||
|
@ -36,6 +39,10 @@ export function updateGroup(group: Group, updates: Partial<Group>) {
|
|||
return updateDoc(doc(groups, group.id), updates)
|
||||
}
|
||||
|
||||
export function deleteFieldFromGroup(group: Group, field: string) {
|
||||
return updateDoc(doc(groups, group.id), { [field]: deleteField() })
|
||||
}
|
||||
|
||||
export function deleteGroup(group: Group) {
|
||||
return deleteDoc(doc(groups, group.id))
|
||||
}
|
||||
|
|
|
@ -45,6 +45,10 @@ import { Button } from 'web/components/button'
|
|||
import { listAllCommentsOnGroup } from 'web/lib/firebase/comments'
|
||||
import { GroupComment } from 'common/comment'
|
||||
import { REFERRAL_AMOUNT } from 'common/economy'
|
||||
import { GroupDashboard } from 'web/components/groups/group-dashboard'
|
||||
import { getDashboard } from 'web/lib/firebase/dashboards'
|
||||
import { Dashboard } from 'common/dashboard'
|
||||
import { Spacer } from 'web/components/layout/spacer'
|
||||
|
||||
export const getStaticProps = fromPropz(getStaticPropz)
|
||||
export async function getStaticPropz(props: { params: { slugs: string[] } }) {
|
||||
|
@ -57,6 +61,10 @@ export async function getStaticPropz(props: { params: { slugs: string[] } }) {
|
|||
const contracts =
|
||||
(group && (await listContractsByGroupSlug(group.slug))) ?? []
|
||||
|
||||
const dashboard =
|
||||
group &&
|
||||
group.dashboardId != null &&
|
||||
(await getDashboard(group.dashboardId))
|
||||
const bets = await Promise.all(
|
||||
contracts.map((contract: Contract) => listAllBets(contract.id))
|
||||
)
|
||||
|
@ -83,6 +91,7 @@ export async function getStaticPropz(props: { params: { slugs: string[] } }) {
|
|||
creatorScores,
|
||||
topCreators,
|
||||
messages,
|
||||
dashboard,
|
||||
},
|
||||
|
||||
revalidate: 60, // regenerate after a minute
|
||||
|
@ -121,6 +130,7 @@ export default function GroupPage(props: {
|
|||
creatorScores: { [userId: string]: number }
|
||||
topCreators: User[]
|
||||
messages: GroupComment[]
|
||||
dashboard: Dashboard
|
||||
}) {
|
||||
props = usePropz(props, getStaticPropz) ?? {
|
||||
group: null,
|
||||
|
@ -139,6 +149,7 @@ export default function GroupPage(props: {
|
|||
topTraders,
|
||||
creatorScores,
|
||||
topCreators,
|
||||
dashboard,
|
||||
} = props
|
||||
|
||||
const router = useRouter()
|
||||
|
@ -176,6 +187,16 @@ export default function GroupPage(props: {
|
|||
|
||||
const aboutTab = (
|
||||
<Col>
|
||||
{group.dashboardId != null || isCreator ? (
|
||||
<GroupDashboard
|
||||
group={group}
|
||||
isCreator={!!isCreator}
|
||||
dashboard={dashboard}
|
||||
/>
|
||||
) : (
|
||||
<div></div>
|
||||
)}
|
||||
<Spacer h={3} />
|
||||
<GroupOverview
|
||||
group={group}
|
||||
creator={creator}
|
||||
|
@ -292,7 +313,6 @@ function GroupOverview(props: {
|
|||
error: "Couldn't update group",
|
||||
})
|
||||
}
|
||||
|
||||
const postFix = user ? '?referrer=' + user.username : ''
|
||||
const shareUrl = `https://${ENV_CONFIG.domain}${groupPath(
|
||||
group.slug
|
||||
|
|
Loading…
Reference in New Issue
Block a user