Skip to content

Commit 002049c

Browse files
Copilotthegovind
andcommitted
Add Zava branding, quick actions, action drawer, and enhanced question input
Co-authored-by: thegovind <18152044+thegovind@users.noreply.github.com>
1 parent 7b2a963 commit 002049c

File tree

20 files changed

+1089
-123
lines changed

20 files changed

+1089
-123
lines changed

src/App/.env.sample

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@ AZURE_OPENAI_TEMPERATURE="0"
55
AZURE_OPENAI_TOP_P="1"
66
AZURE_OPENAI_MAX_TOKENS="1000"
77
AZURE_OPENAI_STOP_SEQUENCE=
8-
AZURE_OPENAI_SYSTEM_MESSAGE="You are a helpful Wealth Advisor assistant"
8+
AZURE_OPENAI_SYSTEM_MESSAGE="You are Zava, a helpful retail and support assistant. You help retail associates and support agents with product information, inventory checks, warranties, returns, and customer support tasks. You can execute quick actions like checking availability, creating backorders, processing warranties, and generating RMA labels."
99
AZURE_OPENAI_PREVIEW_API_VERSION="2025-01-01-preview"
1010
AZURE_OPENAI_STREAM="True"
1111
AZURE_OPENAI_ENDPOINT=
1212
AZURE_OPENAI_EMBEDDING_NAME="text-embedding-ada-002"
1313
AZURE_OPENAI_EMBEDDING_ENDPOINT=
1414

1515
# User Interface
16-
UI_TITLE=
16+
UI_TITLE="Zava Copilot"
1717
UI_LOGO=
1818
UI_CHAT_LOGO=
19-
UI_CHAT_TITLE=
20-
UI_CHAT_DESCRIPTION=
19+
UI_CHAT_TITLE="How can I help you today?"
20+
UI_CHAT_DESCRIPTION="I can help with product info, inventory checks, warranties, and returns"
2121
UI_FAVICON=
2222

2323
# Cosmos DB settings

src/App/backend/common/config.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ class Config:
1616
def __init__(self):
1717

1818
# UI configuration (optional)
19-
self.UI_TITLE = os.environ.get("UI_TITLE") or "Woodgrove Bank"
19+
self.UI_TITLE = os.environ.get("UI_TITLE") or "Zava Copilot"
2020
self.UI_LOGO = os.environ.get("UI_LOGO")
2121
self.UI_CHAT_LOGO = os.environ.get("UI_CHAT_LOGO")
22-
self.UI_CHAT_TITLE = os.environ.get("UI_CHAT_TITLE") or "Start chatting"
22+
self.UI_CHAT_TITLE = os.environ.get("UI_CHAT_TITLE") or "How can I help you today?"
2323
self.UI_CHAT_DESCRIPTION = (
2424
os.environ.get("UI_CHAT_DESCRIPTION")
25-
or "This chatbot is configured to answer your questions"
25+
or "I can help with product info, inventory checks, warranties, and returns"
2626
)
2727
self.UI_FAVICON = os.environ.get("UI_FAVICON") or "/favicon.ico"
2828
self.UI_SHOW_SHARE_BUTTON = (
Lines changed: 8 additions & 0 deletions
Loading
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
.actionPanel {
2+
font-family: 'Segoe UI', sans-serif;
3+
}
4+
5+
.panelContent {
6+
padding: 20px;
7+
display: flex;
8+
flex-direction: column;
9+
gap: 20px;
10+
height: 100%;
11+
}
12+
13+
.description {
14+
color: var(--zava-dark-gray);
15+
line-height: 1.5;
16+
}
17+
18+
.progressContainer {
19+
background-color: var(--zava-light-gray);
20+
padding: 16px;
21+
border-radius: 8px;
22+
border-left: 4px solid var(--zava-accent);
23+
}
24+
25+
.progressTitle {
26+
font-weight: 600;
27+
margin-bottom: 12px;
28+
color: var(--zava-primary);
29+
}
30+
31+
.progressSteps {
32+
display: flex;
33+
gap: 20px;
34+
overflow-x: auto;
35+
padding-bottom: 4px;
36+
}
37+
38+
.progressStep {
39+
display: flex;
40+
flex-direction: column;
41+
align-items: center;
42+
gap: 6px;
43+
min-width: 80px;
44+
text-align: center;
45+
}
46+
47+
.progressDot {
48+
width: 32px;
49+
height: 32px;
50+
border-radius: 50%;
51+
display: flex;
52+
align-items: center;
53+
justify-content: center;
54+
font-size: 12px;
55+
font-weight: 600;
56+
background-color: var(--zava-medium-gray);
57+
color: var(--zava-dark-gray);
58+
transition: all 0.3s ease;
59+
}
60+
61+
.progressDot.completed {
62+
background-color: var(--zava-accent);
63+
color: var(--zava-white);
64+
}
65+
66+
.progressLabel {
67+
color: var(--zava-dark-gray);
68+
max-width: 80px;
69+
word-wrap: break-word;
70+
}
71+
72+
.messageBar {
73+
margin-bottom: 16px;
74+
}
75+
76+
.fieldsContainer {
77+
flex: 1;
78+
overflow-y: auto;
79+
}
80+
81+
.selectField {
82+
width: 100%;
83+
padding: 8px 12px;
84+
border: 1px solid var(--zava-medium-gray);
85+
border-radius: 4px;
86+
font-size: 14px;
87+
font-family: 'Segoe UI', sans-serif;
88+
background-color: var(--zava-white);
89+
}
90+
91+
.selectField:focus {
92+
outline: none;
93+
border-color: var(--zava-accent);
94+
box-shadow: 0 0 0 1px var(--zava-accent);
95+
}
96+
97+
.fieldDescription {
98+
color: var(--zava-dark-gray);
99+
font-style: italic;
100+
}
101+
102+
.actions {
103+
display: flex;
104+
gap: 12px;
105+
align-items: center;
106+
padding-top: 16px;
107+
border-top: 1px solid var(--zava-medium-gray);
108+
margin-top: auto;
109+
}
110+
111+
.submitButton {
112+
background-color: var(--zava-accent) !important;
113+
border-color: var(--zava-accent) !important;
114+
color: var(--zava-white) !important;
115+
}
116+
117+
.submitButton:hover {
118+
background-color: var(--zava-accent-dark) !important;
119+
border-color: var(--zava-accent-dark) !important;
120+
}
121+
122+
.submitButton:disabled {
123+
background-color: var(--zava-medium-gray) !important;
124+
border-color: var(--zava-medium-gray) !important;
125+
color: var(--zava-dark-gray) !important;
126+
}
127+
128+
.spinner {
129+
margin-left: 8px;
130+
}
131+
132+
/* Mobile responsive */
133+
@media (max-width: 768px) {
134+
.panelContent {
135+
padding: 16px;
136+
}
137+
138+
.progressSteps {
139+
gap: 12px;
140+
}
141+
142+
.progressStep {
143+
min-width: 60px;
144+
}
145+
146+
.progressDot {
147+
width: 28px;
148+
height: 28px;
149+
font-size: 11px;
150+
}
151+
152+
.actions {
153+
flex-direction: column;
154+
align-items: stretch;
155+
}
156+
}
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import React, { useState } from 'react'
2+
import { Panel, PanelType, PrimaryButton, DefaultButton, TextField, Stack, Spinner, Text, MessageBar, MessageBarType } from '@fluentui/react'
3+
import styles from './ActionDrawer.module.css'
4+
5+
export interface ActionField {
6+
key: string
7+
label: string
8+
type: 'text' | 'number' | 'email' | 'select'
9+
value: string
10+
required?: boolean
11+
options?: { key: string; text: string }[]
12+
description?: string
13+
}
14+
15+
export interface ActionDrawerProps {
16+
isOpen: boolean
17+
onDismiss: () => void
18+
title: string
19+
description?: string
20+
fields: ActionField[]
21+
onFieldChange: (key: string, value: string) => void
22+
onSubmit: () => void
23+
isSubmitting?: boolean
24+
error?: string
25+
success?: string
26+
submitLabel?: string
27+
progressSteps?: string[]
28+
currentStep?: number
29+
}
30+
31+
export const ActionDrawer: React.FC<ActionDrawerProps> = ({
32+
isOpen,
33+
onDismiss,
34+
title,
35+
description,
36+
fields,
37+
onFieldChange,
38+
onSubmit,
39+
isSubmitting = false,
40+
error,
41+
success,
42+
submitLabel = 'Submit',
43+
progressSteps,
44+
currentStep = 0
45+
}) => {
46+
const renderProgressIndicator = () => {
47+
if (!progressSteps) return null
48+
49+
return (
50+
<div className={styles.progressContainer}>
51+
<Text variant="small" className={styles.progressTitle}>Progress</Text>
52+
<div className={styles.progressSteps}>
53+
{progressSteps.map((step, index) => (
54+
<div key={index} className={styles.progressStep}>
55+
<div className={`${styles.progressDot} ${index <= currentStep ? styles.completed : ''}`}>
56+
{index < currentStep ? '✓' : index + 1}
57+
</div>
58+
<Text variant="small" className={styles.progressLabel}>{step}</Text>
59+
</div>
60+
))}
61+
</div>
62+
</div>
63+
)
64+
}
65+
66+
const renderField = (field: ActionField) => {
67+
if (field.type === 'select') {
68+
return (
69+
<Stack key={field.key} tokens={{ childrenGap: 4 }}>
70+
<Text variant="medium">{field.label} {field.required && '*'}</Text>
71+
<select
72+
value={field.value}
73+
onChange={(e) => onFieldChange(field.key, e.target.value)}
74+
className={styles.selectField}
75+
required={field.required}
76+
>
77+
<option value="">Select...</option>
78+
{field.options?.map(option => (
79+
<option key={option.key} value={option.key}>{option.text}</option>
80+
))}
81+
</select>
82+
{field.description && <Text variant="small" className={styles.fieldDescription}>{field.description}</Text>}
83+
</Stack>
84+
)
85+
}
86+
87+
return (
88+
<Stack key={field.key} tokens={{ childrenGap: 4 }}>
89+
<TextField
90+
label={field.label}
91+
value={field.value}
92+
onChange={(_, newValue) => onFieldChange(field.key, newValue || '')}
93+
type={field.type}
94+
required={field.required}
95+
description={field.description}
96+
/>
97+
</Stack>
98+
)
99+
}
100+
101+
const canSubmit = fields.filter(f => f.required).every(f => f.value.trim()) && !isSubmitting
102+
103+
return (
104+
<Panel
105+
isOpen={isOpen}
106+
onDismiss={onDismiss}
107+
type={PanelType.medium}
108+
headerText={title}
109+
className={styles.actionPanel}
110+
closeButtonAriaLabel="Close"
111+
>
112+
<div className={styles.panelContent}>
113+
{description && (
114+
<Text variant="medium" className={styles.description}>
115+
{description}
116+
</Text>
117+
)}
118+
119+
{renderProgressIndicator()}
120+
121+
{error && (
122+
<MessageBar messageBarType={MessageBarType.error} className={styles.messageBar}>
123+
{error}
124+
</MessageBar>
125+
)}
126+
127+
{success && (
128+
<MessageBar messageBarType={MessageBarType.success} className={styles.messageBar}>
129+
{success}
130+
</MessageBar>
131+
)}
132+
133+
<Stack tokens={{ childrenGap: 16 }} className={styles.fieldsContainer}>
134+
{fields.map(renderField)}
135+
</Stack>
136+
137+
<div className={styles.actions}>
138+
<PrimaryButton
139+
text={isSubmitting ? 'Processing...' : submitLabel}
140+
onClick={onSubmit}
141+
disabled={!canSubmit}
142+
className={styles.submitButton}
143+
/>
144+
<DefaultButton text="Cancel" onClick={onDismiss} />
145+
{isSubmitting && <Spinner className={styles.spinner} />}
146+
</div>
147+
</div>
148+
</Panel>
149+
)
150+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { ActionDrawer } from './ActionDrawer'
2+
export type { ActionDrawerProps, ActionField } from './ActionDrawer'

0 commit comments

Comments
 (0)