Skip to content

Commit

Permalink
feat: add recent edits feed
Browse files Browse the repository at this point in the history
  • Loading branch information
viet nguyen committed Oct 25, 2023
1 parent 2b908aa commit d6d20bf
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 41 deletions.
25 changes: 25 additions & 0 deletions src/app/components/RecentEdits.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ArrowRightIcon } from '@heroicons/react/24/outline'

import { getChangeHistoryServerSide } from '@/js/graphql/contribAPI'
import { ChangesetRow } from '@/components/edit/RecentChangeHistory'
import Link from 'next/link'

export const RecentEdits: React.FC = async () => {
const history = await getChangeHistoryServerSide()
return (
<section className='px-4 2xl:px-0 w-full'>
<div className='flex items-center justify-between'>
<h2>Recent edits</h2>
<Link href='/edit' className='text-sm hover:underline'>See more</Link>
</div>
<hr className='mb-6 border-2 border-base-content' />
<div className='mt-4 flex justify-center flex-row flex-wrap gap-y-10 gap-x-2'>
{history.splice(0, 10).map(changetset =>
<ChangesetRow key={changetset.id} changeset={changetset} />)}
</div>
<div className='flex justify-center py-10'>
<Link href='/edit' className='btn btn-sm btn-outline'>See more <ArrowRightIcon className='w-4 h-4' /></Link>
</div>
</section>
)
}
2 changes: 1 addition & 1 deletion src/app/components/RecentTags.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const RecentTags: React.FC = async () => {
})

return (
<section className='w-full py-8'>
<section className='w-full'>
<div className='px-4 2xl:px-0 mx-auto max-w-5xl xl:max-w-7xl'>
<h2>Recent Tags</h2>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/USAToC.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { getUSATableOfContent } from '@/js/graphql/getPopularAreasUSA'
export const USAToC: React.FC = async () => {
const toc = await getUSATableOfContent()
return (
<section className='mt-16 px-4 2xl:px-0 mx-auto max-w-5xl xl:max-w-7xl'>
<section className='block w-full px-4 2xl:px-0 mx-auto max-w-5xl xl:max-w-7xl'>
<Link href='/crag/1db1e8ba-a40e-587c-88a4-64f5ea814b8e' className='flex flex-row items-center gap-2'><h2>USA</h2><ArrowRightCircleIcon className='w-4 h-4' /></Link>
<hr className='mb-6 border-2 border-base-content' />
<div className='columns-3xs gap-x-10'>
Expand Down
14 changes: 13 additions & 1 deletion src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
import { RecentEdits } from './components/RecentEdits'
import { RecentTags } from './components/RecentTags'
import { USAToC } from './components/USAToC'

export default async function Home (): Promise<any> {
return (
<div className='mt-32 w-full'>
<div className='mt-16 w-full flex flex-col gap-y-24'>
<div className='pl-4 lg:grid lg:grid-cols-3'>
<div className='col-span-2 bg-blue-200 rounded-box p-10'>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>

</div>
<div className='lg:overflow-y-auto lg:h-[800px] w-full'>
<RecentEdits />
</div>
</div>
<RecentTags />
<USAToC />
</div>
Expand Down
81 changes: 48 additions & 33 deletions src/components/edit/RecentChangeHistory.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react'
import Link from 'next/link'
import { PlusIcon, UserCircleIcon, MinusIcon, PencilIcon, PencilSquareIcon, MinusCircleIcon, PlusCircleIcon } from '@heroicons/react/24/outline'
import { PlusIcon, MinusIcon, PencilIcon, PencilSquareIcon, MinusCircleIcon, PlusCircleIcon } from '@heroicons/react/24/outline'
import { formatDistanceToNow } from 'date-fns'
import clx from 'classnames'

import { ChangesetType, ChangeType, AreaType, ClimbType, OrganizationType, DocumentTypeName } from '../../js/types'

Expand All @@ -10,7 +11,7 @@ export interface RecentChangeHistoryProps {
}
export default function RecentChangeHistory ({ history }: RecentChangeHistoryProps): JSX.Element {
return (
<div className='flex flex-col gap-y-4 w-full'>
<div className='mt-4 flex flex-col gap-y-10 w-full'>
{history.map(changetset => <ChangesetRow key={changetset.id} changeset={changetset} />)}
</div>
)
Expand All @@ -20,37 +21,44 @@ interface ChangsetRowProps {
changeset: ChangesetType
}

const ChangesetRow = ({ changeset }: ChangsetRowProps): JSX.Element => {
export const ChangesetRow = ({ changeset }: ChangsetRowProps): JSX.Element => {
const { createdAt, editedByUser, operation, changes } = changeset

// @ts-expect-error
const op = operationLabelMap[operation]
if (op == null) console.log('#op', operation, changes)
return (
<div className='card card-compact w-full bg-base-100 shadow-xl'>
<div className='card-body'>
<div className='mx-4 card-actions justify-between items-center align-middle'>
{op?.icon}
{op?.badge}
<div className='text-xs text-base-300'>
{formatDistanceToNow(createdAt, { addSuffix: true })}
</div>
<Link className='w-8 h-8' href={`/u/${editedByUser}`}>

<UserCircleIcon className='w-6 h-6' />

<div className='block w-full max-w-md'>
<div className='mb-2 flex items-center justify-between flex-wrap gap-y-1.5'>
<div className='flex items-center gap-1'>
<Link className='flex items-center gap-2' href={`/u/${editedByUser}`}>
<div className='avatar placeholder'>
<div className='bg-neutral-focus text-neutral-content h-6 rounded-full'>
{editedByUser[0].toUpperCase()}
</div>
</div>
<span className='text-sm text-base-content/70'>{editedByUser}</span>
</Link>
<div className='pl-0.5 text-sm'>{op.badge}</div>
</div>

<div className='text-sm text-base-content/70 italic mr-2'>
{formatDistanceToNow(createdAt, { addSuffix: true })}
</div>
<div className='mt-4 ml-6'>
{changes.map(change => (
<React.Fragment key={change.changeId}>
<AreaChange {...change} />
<ClimbChange {...change} />
<OrganizationChange {...change} />
</React.Fragment>))}
</div>
<div className={clx('border-l-8 card card-compact w-full bg-base-100 border shadow-lg', op.borderCue)}>
<div className='card-body'>
<div className='px-2'>
{changes.map(change => (
<React.Fragment key={change.changeId}>
<AreaChange {...change} />
<ClimbChange {...change} />
<OrganizationChange {...change} />
</React.Fragment>))}
</div>
</div>
</div>
</div>

)
}

Expand All @@ -61,7 +69,7 @@ const ClimbChange = ({ changeId, fullDocument, updateDescription, dbOp }: Change
// @ts-expect-error
const icon = dbOpIcon[dbOp]
return (
<div className='py-2 ml-2 flex gap-x-2'>
<div className='ml-2 flex gap-x-2'>
<div className='flex gap-2'><span>{icon}</span><span className='badge badge-sm badge-info'>Climb</span></div>

<div className=''>
Expand Down Expand Up @@ -92,7 +100,7 @@ const AreaChange = ({ changeId, fullDocument, updateDescription, dbOp }: ChangeT
// @ts-expect-error
const icon = dbOpIcon[dbOp]
return (
<div className='py-2 ml-2 flex gap-x-2'>
<div className='ml-2 flex gap-x-2'>
<div className='flex gap-2'>{icon} <span className='badge badge-sm badge-warning'>Area</span></div>

<div className=''>
Expand Down Expand Up @@ -187,36 +195,43 @@ const OpBadge = ({ label, clz = 'badge-outline' }: OpBadgeProps): JSX.Element =>

const operationLabelMap = {
addArea: {
badge: <OpBadge label='Add Area' clz='badge-warning' />,
borderCue: 'border-l-green-500',
badge: 'added an area',
icon: <ActionIcon icon={<PlusIcon className='w-6 h-6 stroke-base-300 stroke-2' />} clz='bg-success' />
},
updateArea: {
badge: <OpBadge label='Update Area' clz='badge-warning' />,
borderCue: 'border-l-black',
badge: 'edited an area',
icon: <ActionIcon icon={<PencilIcon className='w-6 h-6 stroke-base-300' />} />
},
addCountry: {
badge: <OpBadge label='Add Country' clz='badge-primary' />,
borderCue: 'border-l-green-500',
badge: 'added a country',
icon: <ActionIcon icon={<PlusIcon className='w-6 h-6 stroke-base-300' />} />
},
deleteArea: {
badge: <OpBadge label='Delete Area' clz='badge-warning' />,
borderCue: 'border-l-pink-500',
badge: 'deleted an area',
icon: <ActionIcon icon={<MinusIcon className='w-6 h-6 stroke-base-300' />} clz='bg-error' />
},
updateDestination: {
badge: <OpBadge label='Area' clz='badge-warning' />,
badge: 'badge-warning',
icon: <ActionIcon icon={<PencilIcon className='w-6 h-6 stroke-base-300' />} />
},

addClimb: {
badge: <OpBadge label='Add Climb' clz='badge-info' />,
borderCue: 'border-l-green-500',
badge: 'added a climb',
icon: <ActionIcon icon={<PlusIcon className='w-6 h-6 stroke-base-300 stroke-2' />} clz='bg-success' />
},
deleteClimb: {
badge: <OpBadge label='Delete Climb' clz='badge-info' />,
borderCue: 'border-l-pink-500',
badge: 'deleted a climb',
icon: <ActionIcon icon={<PencilIcon className='w-6 h-6 stroke-base-300' />} clz='bg-error' />
},
updateClimb: {
badge: <OpBadge label='Update Climb' clz='badge-info' />,
borderCue: 'border-l-black',
badge: 'updated a climb',
icon: <ActionIcon icon={<PencilIcon className='w-6 h-6 stroke-base-300' />} />
},
addOrganization: {
Expand Down
3 changes: 1 addition & 2 deletions src/components/maps/BaseMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@ export const DEFAULT_INITIAL_VIEWSTATE: XViewStateType = {
}

export const MAP_STYLES = {
light: 'mapbox://styles/mappandas/ckx5ksor56x3z15qavm57edp9',
light: 'mapbox://styles/mappandas/ckf8bb0qv18be19npofybx7yq',
dark: 'mapbox://styles/mappandas/cl0u44wo8008415pedsbgtml7'
}

interface BaseMapProps {
height: number
viewstate: XViewStateType
Expand Down
7 changes: 4 additions & 3 deletions src/js/graphql/contribAPI.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { QUERY_RECENT_CHANGE_HISTORY } from './gql/contribs'
import { graphqlClient } from './Client'
import { ChangesetType } from '../types'

export const getChangeHistoryServerSide = async (): Promise<any> => {
export const getChangeHistoryServerSide = async (): Promise<ChangesetType[]> => {
try {
const rs = await graphqlClient.query<{ getChangeHistory: any[] }>({
const rs = await graphqlClient.query<{ getChangeHistory: ChangesetType[] }>({
query: QUERY_RECENT_CHANGE_HISTORY,
fetchPolicy: 'no-cache'
})

if (Array.isArray(rs.data?.getChangeHistory)) {
return rs.data?.getChangeHistory
return rs.data?.getChangeHistory.splice(0, 50)
}
console.log('WARNING: getChangeHistory() returns non-array data')
return []
Expand Down

0 comments on commit d6d20bf

Please sign in to comment.