Skip to content

Commit

Permalink
Add custom fields support for create ticket view (#346)
Browse files Browse the repository at this point in the history
* Add custom fields support for create ticket view

* Add changeset

* Restore changes in Select primitive
  • Loading branch information
nickrttn committed Apr 26, 2024
1 parent a580f78 commit 90c8df3
Show file tree
Hide file tree
Showing 6 changed files with 280 additions and 12 deletions.
8 changes: 8 additions & 0 deletions .changeset/angry-coins-chew.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@markprompt/react": minor
"@markprompt/css": minor
"@markprompt/docusaurus-theme-search": minor
"@markprompt/web": minor
---

Add custom fields support for create ticket view
47 changes: 47 additions & 0 deletions examples/with-markprompt-web/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,53 @@ if (el && el instanceof HTMLElement) {
},
form: {
hasFileUploadInput: true,
emailLabel: 'Email',
nameLabel: 'Name',
emailPlaceholder: 'jane@doe.com',
namePlaceholder: 'Jane Doe',
maxFileSizeError: 'File size should be less than 4.5MB',
submitLabel: 'Submit case',
summaryLabel: 'Summary',
summaryLoading: 'Generating summary…',
summaryPlaceholder: 'Please describe your issue',
ticketCreatedError: 'An error occurred while creating the case',
ticketCreatedOk: 'Thank you! We will get back to you shortly.',
uploadFileLabel: 'Attach files (optional)',
customFields: [
{
id: '12345678',
label: 'Case type',
items: [
{ value: 'Bug', label: 'Bug' },
{ value: 'Feature request', label: 'Feature request' },
{ value: 'Other', label: 'Other' },
],
},
{
id: '87654321',
label: 'Category',
items: [
{
label: 'Legal',
items: [
{ value: 'Contract', label: 'Contract' },
{ value: 'Compliance', label: 'Compliance' },
],
},
{
label: 'Account & Billing',
items: [
{ value: 'Payment', label: 'Payment' },
{ value: 'Invoice', label: 'Invoice' },
],
},
{
value: 'Other',
label: 'Other',
},
],
},
],
},
},
},
Expand Down
57 changes: 50 additions & 7 deletions packages/css/markprompt.css
Original file line number Diff line number Diff line change
Expand Up @@ -2091,6 +2091,15 @@
background-color: var(--markprompt-muted);
}

.MarkpromptSelectToggleWithIcon {
min-width: 8rem;
justify-content: space-between;
}

.MarkpromptSelectToggleMuted {
color: var(--markprompt-mutedForeground);
}

.MarkpromptSelectMenu {
display: none;
background-color: var(--markprompt-background);
Expand All @@ -2105,6 +2114,7 @@
var(--markprompt-ring-shadow, 0 0 #0000), var(--markprompt-shadow);
max-width: 30ch;
overflow: hidden;
will-change: auto;
}

.MarkpromptSelectMenu[data-open='true'] {
Expand Down Expand Up @@ -2135,6 +2145,19 @@
font-weight: 600;
}

.MarkpromptSelectMenu ul {
padding-left: 0;
}

.MarkpromptSelectMenu li:has(.MarkpromptSelectGroupLabel) {
padding-bottom: 0;
}

.MarkpromptSelectGroupLabel {
display: flex;
margin-block-end: 0.25rem;
}

.MarkpromptNewChatOption {
display: flex;
align-items: center;
Expand Down Expand Up @@ -2563,30 +2586,46 @@
border-color: var(--markprompt-border-accent);
}

.MarkpromptCreateTicketForm :nth-child(1) {
.MarkpromptCreateTicketForm > *:nth-child(1) {
--form-group-index: 1;
}

.MarkpromptCreateTicketForm :nth-child(2) {
.MarkpromptCreateTicketForm > *:nth-child(2) {
--form-group-index: 2;
}

.MarkpromptCreateTicketForm :nth-child(3) {
.MarkpromptCreateTicketForm > *:nth-child(3) {
--form-group-index: 3;
}

.MarkpromptCreateTicketForm :nth-child(4) {
.MarkpromptCreateTicketForm > *:nth-child(4) {
--form-group-index: 4;
}

.MarkpromptCreateTicketForm :nth-child(5) {
.MarkpromptCreateTicketForm > *:nth-child(5) {
--form-group-index: 5;
}

.MarkpromptCreateTicketForm :nth-child(6) {
.MarkpromptCreateTicketForm > *:nth-child(6) {
--form-group-index: 6;
}

.MarkpromptCreateTicketForm > *:nth-child(7) {
--form-group-index: 7;
}

.MarkpromptCreateTicketForm > *:nth-child(8) {
--form-group-index: 8;
}

.MarkpromptCreateTicketForm > *:nth-child(9) {
--form-group-index: 9;
}

.MarkpromptCreateTicketForm > *:nth-child(10) {
--form-group-index: 10;
}

.MarkpromptCreateTicketForm > div {
--base-delay: 0.05s;

Expand Down Expand Up @@ -3051,10 +3090,14 @@
transform: translateY(10px);
}

100% {
99% {
opacity: 1;
transform: translateY(0);
}

100% {
transform: unset;
}
}

@keyframes markprompt-slide-down-subtle {
Expand Down
132 changes: 129 additions & 3 deletions packages/react/src/CreateTicketView.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
import { useMemo, useRef, useState, type FormEvent } from 'react';
import {
autoUpdate,
flip,
offset,
shift,
useFloating,
} from '@floating-ui/react-dom';
import clsx from 'clsx';
import { useSelect } from 'downshift';
import { useId, useMemo, useRef, useState, type FormEvent } from 'react';

import { toApiMessages } from './chat/utils.js';
import { ChevronLeftIcon, LoadingIcon } from './icons.js';
import { useChatStore, type MarkpromptOptions } from './index.js';
import { ChevronDownIcon, ChevronLeftIcon, LoadingIcon } from './icons.js';
import {
useChatStore,
type CustomField,
type MarkpromptOptions,
} from './index.js';
import { useGlobalStore } from './store.js';

export interface CreateTicketViewProps {
Expand Down Expand Up @@ -184,6 +197,10 @@ export function CreateTicketView(props: CreateTicketViewProps): JSX.Element {
}}
/>
</div>
{createTicketOptions?.form?.customFields &&
createTicketOptions?.form?.customFields.map((field) => (
<CustomFieldSelect key={field.id} customField={field} />
))}
{createTicketOptions?.form?.hasFileUploadInput && (
<div className="MarkpromptFormGroup">
<label htmlFor="files">
Expand Down Expand Up @@ -246,3 +263,112 @@ export function CreateTicketView(props: CreateTicketViewProps): JSX.Element {
</div>
);
}

interface CustomFieldSelectProps {
customField: CustomField;
}

function CustomFieldSelect(props: CustomFieldSelectProps): JSX.Element {
const { customField } = props;

// refactor this to use flatMap instead of reduce
const flatItems = useMemo(
() => customField.items.flatMap((x) => ('items' in x ? x.items : x)),
[customField.items],
);

const {
isOpen,
selectedItem,
getToggleButtonProps,
getMenuProps,
highlightedIndex,
getItemProps,
} = useSelect({
items: flatItems,
});

const { refs, floatingStyles } = useFloating({
open: isOpen,
placement: 'bottom-start',
middleware: [offset(8), flip(), shift()],
whileElementsMounted: autoUpdate,
});

const id = useId();

return (
<div className="MarkpromptFormGroup" style={isOpen ? { zIndex: 10 } : {}}>
<label htmlFor={`custom_field_${id}`}>{customField.label}</label>
<input
type="hidden"
id={`custom_field_${id}`}
name="customFields"
value={
selectedItem
? JSON.stringify({ id: customField.id, value: selectedItem.value })
: undefined
}
/>

<div className="MarkpromptSelect">
<button
type="button"
className={clsx(
'MarkpromptSelectToggle',
'MarkpromptSelectToggleWithIcon',
{ MarkpromptSelectToggleMuted: !selectedItem },
)}
{...getToggleButtonProps({ ref: refs.setReference })}
>
{selectedItem?.label || 'Select…'}{' '}
<ChevronDownIcon width={16} height={16} aria-hidden />
</button>

<ul
{...getMenuProps({ ref: refs.setFloating })}
className="MarkpromptSelectMenu"
data-open={isOpen}
style={floatingStyles}
>
{customField.items.map((item) => {
if ('items' in item) {
return (
<li key={item.label}>
<strong className="MarkpromptSelectGroupLabel">
{item.label}
</strong>
<ul>
{item.items.map((option) => (
<li
key={option.value}
{...getItemProps({ item: option })}
data-highlighted={
highlightedIndex === flatItems.indexOf(option)
}
>
{option.label}
</li>
))}
</ul>
</li>
);
} else {
return (
<li
key={item.value}
{...getItemProps({ item })}
data-highlighted={
highlightedIndex === flatItems.indexOf(item)
}
>
{item.label}
</li>
);
}
})}
</ul>
</div>
</div>
);
}
2 changes: 1 addition & 1 deletion packages/react/src/chat/ConversationSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function ConversationSelect({
items={[
...conversations.map(([conversationId, { messages }]) => ({
value: conversationId,
label: messages[0]?.content,
label: messages[0]?.content ?? '',
})),
{
value: 'new',
Expand Down

0 comments on commit 90c8df3

Please sign in to comment.