-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
45 changed files
with
4,055 additions
and
211 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,5 +3,6 @@ | |
{ | ||
"mode": "auto" | ||
} | ||
] | ||
], | ||
"editor.formatOnSave": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
'use server' | ||
|
||
import { ClaimedReward, RewardType } from '@latitude-data/core/browser' | ||
import { claimReward } from '@latitude-data/core/services/claimedRewards/claim' | ||
import { z } from 'zod' | ||
|
||
import { authProcedure } from '../procedures' | ||
|
||
export const claimRewardAction = authProcedure | ||
.createServerAction() | ||
.input( | ||
z.object({ | ||
type: z.enum(Object.values(RewardType) as [string, ...string[]]), | ||
reference: z.string(), | ||
}), | ||
) | ||
.handler(async ({ input, ctx }) => { | ||
const workspace = ctx.workspace | ||
const user = ctx.user | ||
const result = await claimReward({ | ||
workspace, | ||
user, | ||
type: input.type as RewardType, | ||
reference: input.reference, | ||
}) | ||
return result.unwrap() as ClaimedReward | undefined | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
'use server' | ||
|
||
import { ClaimedRewardsRepository } from '@latitude-data/core/repositories' | ||
|
||
import { authProcedure } from '../procedures' | ||
|
||
export const fetchClaimedRewardsAction = authProcedure | ||
.createServerAction() | ||
.handler(async ({ ctx }) => { | ||
const claimedRewardsScope = new ClaimedRewardsRepository(ctx.workspace.id) | ||
const result = await claimedRewardsScope.findAllValidOptimistic() | ||
return result.unwrap() | ||
}) |
17 changes: 17 additions & 0 deletions
17
apps/web/src/actions/rewards/fetchPendingRewardClaimsAction.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
'use server' | ||
|
||
import { findAllRewardClaimsPendingToValidate } from '@latitude-data/core/data-access' | ||
import { UnauthorizedError } from '@latitude-data/core/lib/errors' | ||
|
||
import { authProcedure } from '../procedures' | ||
|
||
export const fetchPendingRewardClaimsAction = authProcedure | ||
.createServerAction() | ||
.handler(async ({ ctx }) => { | ||
if (!ctx.user.admin) { | ||
throw new UnauthorizedError('You must be an admin to see pending claims') | ||
} | ||
|
||
const result = await findAllRewardClaimsPendingToValidate() | ||
return result.unwrap() | ||
}) |
28 changes: 28 additions & 0 deletions
28
apps/web/src/actions/rewards/updateRewardClaimValidityAction.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
'use server' | ||
|
||
import { ClaimedReward } from '@latitude-data/core/browser' | ||
import { UnauthorizedError } from '@latitude-data/core/lib/errors' | ||
import { updateRewardClaim } from '@latitude-data/core/services/claimedRewards/update' | ||
import { z } from 'zod' | ||
|
||
import { authProcedure } from '../procedures' | ||
|
||
export const updateRewardClaimValidityAction = authProcedure | ||
.createServerAction() | ||
.input( | ||
z.object({ | ||
claimId: z.number(), | ||
isValid: z.boolean().nullable(), | ||
}), | ||
) | ||
.handler(async ({ input, ctx }) => { | ||
if (!ctx.user.admin) { | ||
throw new UnauthorizedError('You must be an admin to see pending claims') | ||
} | ||
|
||
const result = await updateRewardClaim({ | ||
claimId: input.claimId, | ||
isValid: input.isValid, | ||
}) | ||
return result.unwrap() as ClaimedReward | undefined | ||
}) |
37 changes: 37 additions & 0 deletions
37
apps/web/src/app/(admin)/backoffice/_components/BackofficeTabs.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
'use client' | ||
|
||
import { ReactNode } from 'react' | ||
|
||
import { TabSelector } from '@latitude-data/web-ui' | ||
import { useNavigate } from '$/hooks/useNavigate' | ||
import { BackofficeRoutes, ROUTES } from '$/services/routes' | ||
import { useSelectedLayoutSegment } from 'next/navigation' | ||
|
||
export function BackofficeTabs({ children }: { children: ReactNode }) { | ||
const router = useNavigate() | ||
const selected = useSelectedLayoutSegment() as BackofficeRoutes | ||
return ( | ||
<div className='flex flex-col w-full gap-4'> | ||
<div className='w-full p-4 pb-0'> | ||
<TabSelector | ||
showSelectedOnSubroutes | ||
options={[ | ||
{ | ||
label: 'Templates', | ||
value: BackofficeRoutes.templates, | ||
}, | ||
{ | ||
label: 'Rewards', | ||
value: BackofficeRoutes.rewards, | ||
}, | ||
]} | ||
selected={selected} | ||
onSelect={(value) => { | ||
router.push(ROUTES.backoffice[value].root) | ||
}} | ||
/> | ||
</div> | ||
{children} | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,196 +1,6 @@ | ||
'use client' | ||
import { BackofficeRoutes, ROUTES } from '$/services/routes' | ||
import { redirect } from 'next/navigation' | ||
|
||
import { FormEvent } from 'react' | ||
|
||
import { | ||
EvaluationResultableType, | ||
EvaluationTemplateWithCategory, | ||
} from '@latitude-data/core/browser' | ||
import { | ||
Button, | ||
FormField, | ||
FormWrapper, | ||
Icon, | ||
Input, | ||
Table, | ||
TableBody, | ||
TableCell, | ||
TableHead, | ||
TableHeader, | ||
TableRow, | ||
TableWithHeader, | ||
TabSelector, | ||
Text, | ||
TextArea, | ||
} from '@latitude-data/web-ui' | ||
import useEvaluationTemplates from '$/stores/evaluationTemplates' | ||
|
||
import { useEvaluationConfiguration } from '../../(private)/evaluations/_components/CreateEvaluationModal' | ||
|
||
export default function AdminPage() { | ||
const { data: evaluationTemplates } = useEvaluationTemplates() | ||
|
||
return ( | ||
<div className='max-w-[1250px] m-auto py-8 flex flex-col gap-8'> | ||
<NewEvaluationTemplate /> | ||
<EvaluationTemplatesTable evaluationTemplates={evaluationTemplates} /> | ||
</div> | ||
) | ||
} | ||
|
||
function EvaluationTemplatesTable({ | ||
evaluationTemplates, | ||
}: { | ||
evaluationTemplates: EvaluationTemplateWithCategory[] | ||
}) { | ||
const { destroy } = useEvaluationTemplates() | ||
if (!evaluationTemplates.length) return null | ||
|
||
return ( | ||
<TableWithHeader | ||
title='Evaluation Templates' | ||
table={ | ||
<Table> | ||
<TableHeader> | ||
<TableRow> | ||
<TableHead>Name</TableHead> | ||
<TableHead>Category</TableHead> | ||
<TableHead>Description</TableHead> | ||
<TableHead>Configuration</TableHead> | ||
<TableHead /> | ||
</TableRow> | ||
</TableHeader> | ||
<TableBody> | ||
{evaluationTemplates.map((template) => ( | ||
<TableRow | ||
key={template.id} | ||
className='cursor-pointer border-b-[0.5px] h-12 max-h-12 border-border' | ||
> | ||
<TableCell> | ||
<Text.H4 noWrap>{template.name}</Text.H4> | ||
</TableCell> | ||
<TableCell> | ||
<Text.H4 noWrap>{template.category}</Text.H4> | ||
</TableCell> | ||
<TableCell> | ||
<div className='flex flex-row gap-1 justify-between items-center'> | ||
<div className='flex-auto'> | ||
<Text.H4>{template.description}</Text.H4> | ||
</div> | ||
</div> | ||
</TableCell> | ||
<TableCell> | ||
<Text.H4 noWrap> | ||
{JSON.stringify(template.configuration)} | ||
</Text.H4> | ||
</TableCell> | ||
<TableCell> | ||
<Button | ||
variant='outline' | ||
onClick={() => destroy({ id: template.id })} | ||
> | ||
<Icon name='trash' /> | ||
</Button> | ||
</TableCell> | ||
</TableRow> | ||
))} | ||
</TableBody> | ||
</Table> | ||
} | ||
/> | ||
) | ||
} | ||
|
||
function NewEvaluationTemplate() { | ||
const { create } = useEvaluationTemplates() | ||
|
||
const handleSubmit = (ev: FormEvent<HTMLFormElement>) => { | ||
ev.preventDefault() // This line prevents the default form submission | ||
|
||
const formData = new FormData(ev.currentTarget) | ||
const name = formData.get('name') as string | ||
const description = formData.get('description') as string | ||
const prompt = formData.get('prompt') as string | ||
|
||
create({ | ||
name, | ||
description, | ||
prompt, | ||
configuration, | ||
}) | ||
} | ||
|
||
const { | ||
configuration, | ||
handleTypeChange, | ||
handleRangeFromChange, | ||
handleRangeToChange, | ||
} = useEvaluationConfiguration() | ||
|
||
return ( | ||
<div className='w-full flex flex-col gap-4'> | ||
<form onSubmit={handleSubmit}> | ||
<FormWrapper> | ||
<FormField label='Name'> | ||
<Input | ||
required | ||
name='name' | ||
placeholder='Enter title' | ||
className='w-full' | ||
/> | ||
</FormField> | ||
<FormField label='Description'> | ||
<TextArea | ||
required | ||
name='description' | ||
minRows={4} | ||
maxRows={6} | ||
placeholder='Describe what is the purpose of this template' | ||
className='w-full' | ||
/> | ||
</FormField> | ||
<FormField label='Prompt'> | ||
<TextArea | ||
required | ||
name='prompt' | ||
minRows={4} | ||
maxRows={6} | ||
placeholder='Write your template prompt' | ||
className='w-full' | ||
/> | ||
</FormField> | ||
<TabSelector | ||
options={[ | ||
{ label: 'Text', value: EvaluationResultableType.Text }, | ||
{ label: 'Number', value: EvaluationResultableType.Number }, | ||
{ label: 'Boolean', value: EvaluationResultableType.Boolean }, | ||
]} | ||
onSelect={handleTypeChange} | ||
selected={configuration.type} | ||
/> | ||
{configuration.type === EvaluationResultableType.Number && ( | ||
<FormField label='Range'> | ||
<div className='flex flex-row items-center flex-1 gap-4'> | ||
<Input | ||
type='number' | ||
min={0} | ||
value={configuration.detail?.range.from.toString() || ''} | ||
placeholder='From' | ||
onChange={handleRangeFromChange} | ||
/> | ||
<Input | ||
type='number' | ||
min={0} | ||
value={configuration.detail?.range.to.toString() || ''} | ||
placeholder='To' | ||
onChange={handleRangeToChange} | ||
/> | ||
</div> | ||
</FormField> | ||
)} | ||
<Button type='submit'>Create Template</Button> | ||
</FormWrapper> | ||
</form> | ||
</div> | ||
) | ||
export default async function AdminPage() { | ||
redirect(ROUTES.backoffice[BackofficeRoutes.templates].root) | ||
} |
Oops, something went wrong.