Skip to content

Commit

Permalink
feat(dashboard): add rewards history
Browse files Browse the repository at this point in the history
  • Loading branch information
Satont committed Dec 22, 2024
1 parent 84a7909 commit d37d115
Show file tree
Hide file tree
Showing 10 changed files with 273 additions and 9 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/eventsub/internal/handler/redemption.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (c *Handler) handleChannelPointsRewardRedemptionAdd(
UserID: event.UserID,
RewardID: uuid.MustParse(event.Reward.ID),
RewardTitle: event.Reward.Title,
RewardPrompt: null.StringFrom(event.Reward.Prompt),
RewardPrompt: null.StringFrom(event.UserInput),
RewardCost: event.Reward.Cost,
RedeemedAt: time.Now().UTC(),
},
Expand Down
50 changes: 50 additions & 0 deletions frontend/dashboard/src/api/community-rewards.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { useQuery } from '@urql/vue'
import { createGlobalState } from '@vueuse/core'
import { unref } from 'vue'

import type { RewardsRedemptionsHistoryQuery, TwitchRedemptionsOpts } from '@/gql/graphql'
import type { MaybeRef } from 'vue'

import { graphql } from '@/gql/gql.js'

export type Redemption = RewardsRedemptionsHistoryQuery['rewardsRedemptionsHistory']['redemptions'][0]

export const useCommunityRewardsApi = createGlobalState(() => {
const useHistory = (opts: MaybeRef<TwitchRedemptionsOpts>) => useQuery({
query: graphql(`
query RewardsRedemptionsHistory($opts: TwitchRedemptionsOpts!) {
rewardsRedemptionsHistory(opts: $opts) {
redemptions {
id
channelId
user {
id
displayName
login
profileImageUrl
}
reward {
id
cost
imageUrls
title
usedTimes
}
redeemedAt
prompt
}
total
}
}
`),
get variables() {
return {
opts: unref(opts),
}
},
})

return {
useHistory,
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script setup lang="ts">
import { useCommunityRewardsTable } from './composables/community-rewards-history-table'
import CommunityRewardsPage from './ui/community-rewards-history-page.vue'
import Pagination from '@/components/pagination.vue'
const rewardsTable = useCommunityRewardsTable()
</script>

<template>
<CommunityRewardsPage>
<template #pagination>
<Pagination
:total="rewardsTable.total.value"
:table="rewardsTable.table"
:pagination="rewardsTable.pagination.value"
@update:page="(page) => rewardsTable.pagination.value.pageIndex = page"
@update:page-size="(pageSize) => rewardsTable.pagination.value.pageSize = pageSize"
/>
</template>
</CommunityRewardsPage>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import {
type ColumnDef,
getCoreRowModel,
getFacetedRowModel,
getFacetedUniqueValues,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useVueTable,
} from '@tanstack/vue-table'
import { createGlobalState } from '@vueuse/core'
import { computed, h } from 'vue'

import CommunityRewardsTableRewardCell from '../ui/cells/community-rewards-history-table-reward-cell.vue'

import type { Redemption } from '@/api/community-rewards'
import type { TwitchRedemptionsOpts } from '@/gql/graphql'

import { useProfile } from '@/api/auth.js'
import { useCommunityRewardsApi } from '@/api/community-rewards'
import { usePagination } from '@/composables/use-pagination'
import UsersTableCellUser from '@/features/admin-panel/manage-users/ui/users-table-cell-user.vue'
import { valueUpdater } from '@/helpers/value-updater'

export const useCommunityRewardsTable = createGlobalState(() => {
const communityRewardsApi = useCommunityRewardsApi()
const { data: profile } = useProfile()

const { pagination, setPagination } = usePagination()
const params = computed<TwitchRedemptionsOpts>(() => {
return {
byChannelId: profile.value?.selectedDashboardId,
userSearch: undefined,
page: pagination.value.pageIndex,
perPage: pagination.value.pageSize,
rewardsIds: [],
}
})
const historyResult = communityRewardsApi.useHistory(params)

const history = computed<Redemption[]>(() => {
return historyResult.data.value?.rewardsRedemptionsHistory.redemptions ?? []
})
const total = computed(() => {
return historyResult.data.value?.rewardsRedemptionsHistory.total ?? 0
})
const pageCount = computed(() => {
return Math.ceil(total.value / pagination.value.pageSize)
})

const tableColumns = computed<ColumnDef<Redemption>[]>(() => [
{
accessorKey: 'reward',
size: 20,
header: () => 'Reward',
cell: ({ row }) => {
return h(CommunityRewardsTableRewardCell, {
name: row.original.reward.title,
imageUrl: row.original.reward.imageUrls?.at(-1),
})
},
},
{
accessorKey: 'user',
size: 20,
header: () => 'User',
cell: ({ row }) => {
return h('a', {
class: 'flex flex-col',
href: `https://twitch.tv/${row.original.user.login}`,
target: '_blank',
}, h(UsersTableCellUser, {
avatar: row.original.user.profileImageUrl,
name: row.original.user.login,
displayName: row.original.user.displayName,
}))
},
},
{
accessorKey: 'cost',
size: 5,
header: () => 'Cost',
cell: ({ row }) => row.original.reward.cost,
},
{
accessorKey: 'input',
size: 65,
header: () => 'User input',
cell: ({ row }) => row.original.prompt,
},
])

const table = useVueTable({
get pageCount() {
return pageCount.value
},
get data() {
return history.value
},
get columns() {
return tableColumns.value
},
manualPagination: true,
enableRowSelection: true,
onPaginationChange: (updaterOrValue) => valueUpdater(updaterOrValue, pagination),
// onSortingChange: updaterOrValue => valueUpdater(updaterOrValue, sorting),
// onColumnFiltersChange: updaterOrValue => valueUpdater(updaterOrValue, columnFilters),
// onColumnVisibilityChange: updaterOrValue => valueUpdater(updaterOrValue, columnVisibility),
// onRowSelectionChange: updaterOrValue => valueUpdater(updaterOrValue, rowSelection),
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFacetedRowModel: getFacetedRowModel(),
getFacetedUniqueValues: getFacetedUniqueValues(),
})

return {
table,
total,
pageCount,
pagination,
setPagination,
isLoading: historyResult.fetching,
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script setup lang="ts">
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
defineProps<{
imageUrl?: string
name: string
}>()
</script>

<template>
<div class="flex items-center gap-4 max-sm:justify-start">
<Avatar class="size-9">
<AvatarImage v-if="imageUrl" :src="imageUrl" :alt="name" loading="lazy" />
<AvatarFallback>{{ name }}</AvatarFallback>
</Avatar>
{{ name }}
</div>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script setup lang="ts">
import CommunityRewardsTable from './community-rewards-history-table.vue'
</script>

<template>
<div class="flex flex-col w-full gap-4">
<slot name="pagination" />
<CommunityRewardsTable />
<slot name="pagination" />
</div>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script setup lang="ts">
import { useCommunityRewardsTable } from '../composables/community-rewards-history-table'
import Table from '@/components/table.vue'
const rewardsTable = useCommunityRewardsTable()
</script>

<template>
<Table
:table="rewardsTable.table"
:is-loading="rewardsTable.isLoading.value"
/>
</template>
6 changes: 6 additions & 0 deletions frontend/dashboard/src/layout/sidebar/sidebar-navigation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
PackagePlus,
Shield,
Smile,
SparklesIcon,
Timer,
UserCog,
Users,
Expand Down Expand Up @@ -159,6 +160,11 @@ const links = computed(() => {
icon: Smile,
path: '/dashboard/community?tab=emotes-stats',
},
{
name: 'Rewards history',
icon: SparklesIcon,
path: '/dashboard/community?tab=rewards-history',
},
],
},
{
Expand Down
14 changes: 10 additions & 4 deletions frontend/dashboard/src/pages/community.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { PageLayoutTab } from '@/layout/page-layout.vue'
import { useUserAccessFlagChecker } from '@/api'
import CommunityEmotesStatistic
from '@/features/community-emotes-statistic/community-emotes-statistic.vue'
import CommunityRewardsHistory from '@/features/community-rewards-history/community-rewards-history.vue'
import CommunityRoles from '@/features/community-roles/community-roles.vue'
import CommunityUsers from '@/features/community-users/community-users.vue'
import { ChannelRolePermissionEnum } from '@/gql/graphql'
Expand All @@ -20,19 +21,24 @@ const tabs = computed<PageLayoutTab[]>(() => ([
{
title: t('community.users.title'),
component: CommunityUsers,
name: 'users'
name: 'users',
},
{
title: t('sidebar.roles'),
component: CommunityRoles,
name: 'permissions',
disabled: !canViewRoles.value
disabled: !canViewRoles.value,
},
{
title: t('community.emotesStatistic.title'),
component: CommunityEmotesStatistic,
name: 'emotes-stats'
}
name: 'emotes-stats',
},
{
title: 'Rewards history',
component: CommunityRewardsHistory,
name: 'rewards-history',
},
]))
</script>

Expand Down

0 comments on commit d37d115

Please sign in to comment.