#
tokens: 48964/50000 83/97 files (page 1/2)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 1 of 2. Use http://codebase.md/patrice-truong/cosmosdb-mcp?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .gitignore
├── assets
│   ├── architecture.drawio
│   ├── architecture.png
│   ├── constants_email.png
│   ├── cosmos-add-australia-east.png
│   ├── cosmos-add-region.png
│   ├── cosmos-backup-policy.png
│   ├── cosmos-basics.png
│   ├── cosmos-create-carts.png
│   ├── cosmos-create-products.png
│   ├── cosmos-create.png
│   ├── cosmos-enable-vector-search.png
│   ├── cosmos-encryption.png
│   ├── cosmos-global-distribution.png
│   ├── cosmos-helper-australia.png
│   ├── cosmos-multi-regions-write.png
│   ├── cosmos-networking.png
│   ├── cosmos-new-container.png
│   ├── cosmos-populate-products.png
│   ├── cosmos-products.png
│   ├── cosmos-rbac.png
│   ├── cosmos-validation.png
│   ├── demo.gif
│   ├── demo.png
│   ├── dotnet_build.png
│   ├── npm_run_build.png
│   ├── socket_server_ip.png
│   ├── storage-access-control.png
│   ├── storage-advanced.png
│   ├── storage-basics.png
│   ├── storage-blob-data-contributor.png
│   ├── storage-create-container.png
│   ├── storage-data-protection.png
│   ├── storage-encryption.png
│   ├── storage-files-uploaded.png
│   ├── storage-networking.png
│   ├── storage-review.png
│   ├── storage-role-assignment.png
│   ├── storage-upload-files.png
│   ├── storage-upload.png
│   ├── storage-validation.png
│   ├── vm-advanced.png
│   ├── vm-basics.png
│   ├── vm-disks.png
│   ├── vm-management.png
│   ├── vm-monitoring.png
│   ├── vm-networking.png
│   ├── vm-title.png
│   ├── vm-validation.png
│   └── vm-workload.png
├── LICENSE
├── mcp-server
│   ├── .env.template
│   ├── package-lock.json
│   ├── package.json
│   ├── run_mcp_server.cmd
│   ├── src
│   │   ├── aoai.ts
│   │   ├── cosmosdb-mcp-server.ts
│   │   ├── cosmosdb.ts
│   │   └── server.ts
│   └── tsconfig.json
├── nextjs
│   ├── .env.template
│   ├── .eslintrc.json
│   ├── app
│   │   ├── api
│   │   │   ├── blob-url
│   │   │   │   └── route.ts
│   │   │   ├── cart
│   │   │   │   └── route.ts
│   │   │   ├── chat
│   │   │   │   └── route.ts
│   │   │   ├── orders
│   │   │   │   ├── [id]
│   │   │   │   │   └── route.ts
│   │   │   │   └── route.ts
│   │   │   └── products
│   │   │       └── route.ts
│   │   ├── cart
│   │   │   ├── layout.tsx
│   │   │   └── page.tsx
│   │   ├── globals.css
│   │   ├── layout.tsx
│   │   ├── orders
│   │   │   └── [id]
│   │   │       └── page.tsx
│   │   ├── page.tsx
│   │   └── products
│   │       └── page.tsx
│   ├── components
│   │   ├── AIAssistantDrawer.tsx
│   │   ├── CartItemCount.tsx
│   │   ├── Products.tsx
│   │   └── ui
│   │       ├── accordion.tsx
│   │       ├── alert-dialog.tsx
│   │       ├── alert.tsx
│   │       ├── aspect-ratio.tsx
│   │       ├── avatar.tsx
│   │       ├── badge.tsx
│   │       ├── breadcrumb.tsx
│   │       ├── button.tsx
│   │       ├── calendar.tsx
│   │       ├── card.tsx
│   │       ├── carousel.tsx
│   │       ├── chart.tsx
│   │       ├── checkbox.tsx
│   │       ├── collapsible.tsx
│   │       ├── command.tsx
│   │       ├── context-menu.tsx
│   │       ├── dialog.tsx
│   │       ├── drawer.tsx
│   │       ├── dropdown-menu.tsx
│   │       ├── form.tsx
│   │       ├── hover-card.tsx
│   │       ├── input-otp.tsx
│   │       ├── input.tsx
│   │       ├── label.tsx
│   │       ├── menubar.tsx
│   │       ├── navigation-menu.tsx
│   │       ├── pagination.tsx
│   │       ├── popover.tsx
│   │       ├── progress.tsx
│   │       ├── radio-group.tsx
│   │       ├── resizable.tsx
│   │       ├── scroll-area.tsx
│   │       ├── select.tsx
│   │       ├── separator.tsx
│   │       ├── sheet.tsx
│   │       ├── skeleton.tsx
│   │       ├── slider.tsx
│   │       ├── sonner.tsx
│   │       ├── switch.tsx
│   │       ├── table.tsx
│   │       ├── tabs.tsx
│   │       ├── textarea.tsx
│   │       ├── toast.tsx
│   │       ├── toaster.tsx
│   │       ├── toggle-group.tsx
│   │       ├── toggle.tsx
│   │       └── tooltip.tsx
│   ├── components.json
│   ├── context
│   │   └── CartContext.tsx
│   ├── hooks
│   │   └── use-toast.ts
│   ├── lib
│   │   ├── cosmosdb.ts
│   │   ├── mcp-client.ts
│   │   └── utils.ts
│   ├── models
│   │   ├── cart.ts
│   │   ├── cartContextType.ts
│   │   ├── cartItem.ts
│   │   ├── constants.ts
│   │   └── product.ts
│   ├── next-env.d.ts
│   ├── next.config.js
│   ├── package-lock.json
│   ├── package.json
│   ├── postcss.config.js
│   ├── public
│   │   └── placeholder-300x300.png
│   ├── tailwind.config.ts
│   └── tsconfig.json
├── package-lock.json
├── package.json
├── populate
│   ├── catalog.json
│   ├── populate.csproj
│   ├── product.cs
│   ├── program.cs
│   └── set_rbac.ps1
└── README.md
```

# Files

--------------------------------------------------------------------------------
/nextjs/.eslintrc.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "extends": "next/core-web-vitals"
3 | }
4 | 
```

--------------------------------------------------------------------------------
/mcp-server/.env.template:
--------------------------------------------------------------------------------

```
 1 | AZURE_COSMOSDB_NOSQL_ENDPOINT=https://<cosmosdb_account>.documents.azure.com:443/
 2 | AZURE_COSMOSDB_NOSQL_DATABASE=eshop
 3 | AZURE_COSMOSDB_NOSQL_PRODUCTS_CONTAINER=products
 4 | AZURE_COSMOSDB_NOSQL_CARTS_CONTAINER=carts
 5 | AZURE_COSMOSDB_NOSQL_ORDERS_CONTAINER=orders
 6 | 
 7 | NEXT_PUBLIC_AZURE_TENANT_ID=<tenant_id>
 8 | NEXT_PUBLIC_AZURE_CLIENT_ID=<client_id>
 9 | NEXT_PUBLIC_AZURE_CLIENT_SECRET=<client_secret>
10 | 
11 | NEXT_PUBLIC_AZURE_STORAGE_ACCOUNT_NAME=<storage_account_name>
12 | NEXT_PUBLIC_AZURE_STORAGE_CONTAINER_NAME=img
13 | 
14 | AZURE_OPENAI_ENDPOINT=https://<azure_openai_account>.openai.azure.com/
15 | AZURE_OPENAI_API_KEY=<azure_openai_key>
16 | AZURE_OPENAI_EMBEDDING_MODEL=text-embedding-3-small
17 | AZURE_OPENAI_API_VERSION=2024-05-01-preview
```

--------------------------------------------------------------------------------
/nextjs/.env.template:
--------------------------------------------------------------------------------

```
 1 | AZURE_COSMOSDB_NOSQL_ENDPOINT=https://<cosmosdb_account>.documents.azure.com:443/
 2 | AZURE_COSMOSDB_NOSQL_DATABASE=eshop
 3 | AZURE_COSMOSDB_NOSQL_PRODUCTS_CONTAINER=products
 4 | AZURE_COSMOSDB_NOSQL_CARTS_CONTAINER=carts
 5 | AZURE_COSMOSDB_NOSQL_ORDERS_CONTAINER=orders
 6 | 
 7 | NEXT_PUBLIC_AZURE_TENANT_ID=<tenant_id>
 8 | NEXT_PUBLIC_AZURE_CLIENT_ID=<client_id>
 9 | NEXT_PUBLIC_AZURE_CLIENT_SECRET=<client_secret>
10 | 
11 | NEXT_PUBLIC_AZURE_STORAGE_ACCOUNT_NAME=<storage_account_name>
12 | NEXT_PUBLIC_AZURE_STORAGE_CONTAINER_NAME=img
13 | 
14 | AZURE_OPENAI_ENDPOINT=https://<azure_openai_account>.openai.azure.com/
15 | AZURE_OPENAI_API_KEY=<azure_openai_key>
16 | AZURE_OPENAI_EMBEDDING_MODEL=text-embedding-3-small
17 | AZURE_OPENAI_API_VERSION=2024-05-01-preview
```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
  1 | 
  2 | # Created by https://www.gitignore.io/api/visualstudio
  3 | 
  4 | ### VisualStudio ###
  5 | ## Ignore Visual Studio temporary files, build results, and
  6 | ## files generated by popular Visual Studio add-ons.
  7 | ##
  8 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
  9 | 
 10 | *.dll
 11 | *.pdb
 12 | *.cachefile
 13 | *.bak
 14 | *.ide*
 15 | .terraform/
 16 | .angular
 17 | .next
 18 | cache
 19 | 
 20 | # User-specific files
 21 | *.suo
 22 | *.user
 23 | *.userosscache
 24 | *.sln.docstates
 25 | *.cache
 26 | .angular
 27 | .env
 28 | .venv
 29 | no_commit
 30 | appsettings.json
 31 | 
 32 | Tags/
 33 | tmp/
 34 | deploy/
 35 | patoche/
 36 | 
 37 | # User-specific files (MonoDevelop/Xamarin Studio)
 38 | *.userprefs
 39 | 
 40 | # Build results
 41 | [Dd]ebug/
 42 | [Dd]ebugPublic/
 43 | [Rr]elease/
 44 | [Rr]eleases/
 45 | x64/
 46 | x86/
 47 | bld/
 48 | [Bb]in/
 49 | [Oo]bj/
 50 | [Ll]og/
 51 | dist/
 52 | 
 53 | # Visual Studio 2015 cache/options directory
 54 | .vs/
 55 | # Uncomment if you have tasks that create the project's static files in wwwroot
 56 | #wwwroot/
 57 | 
 58 | # MSTest test Results
 59 | [Tt]est[Rr]esult*/
 60 | [Bb]uild[Ll]og.*
 61 | 
 62 | # NUNIT
 63 | *.VisualState.xml
 64 | TestResult.xml
 65 | 
 66 | # Build Results of an ATL Project
 67 | [Dd]ebugPS/
 68 | [Rr]eleasePS/
 69 | dlldata.c
 70 | 
 71 | # .NET Core
 72 | project.lock.json
 73 | project.fragment.lock.json
 74 | artifacts/
 75 | **/Properties/launchSettings.json
 76 | 
 77 | *_i.c
 78 | *_p.c
 79 | *_i.h
 80 | *.ilk
 81 | *.meta
 82 | *.obj
 83 | *.pch
 84 | *.pdb
 85 | *.pgc
 86 | *.pgd
 87 | *.rsp
 88 | *.sbr
 89 | *.tlb
 90 | *.tli
 91 | *.tlh
 92 | *.tmp
 93 | *.tmp_proj
 94 | *.log
 95 | *.vspscc
 96 | *.vssscc
 97 | .builds
 98 | *.pidb
 99 | *.svclog
100 | *.scc
101 | 
102 | # Chutzpah Test files
103 | _Chutzpah*
104 | 
105 | # Visual C++ cache files
106 | ipch/
107 | *.aps
108 | *.ncb
109 | *.opendb
110 | *.opensdf
111 | *.sdf
112 | *.cachefile
113 | *.VC.db
114 | *.VC.VC.opendb
115 | 
116 | # Visual Studio profiler
117 | *.psess
118 | *.vsp
119 | *.vspx
120 | *.sap
121 | 
122 | # TFS 2012 Local Workspace
123 | $tf/
124 | 
125 | # Guidance Automation Toolkit
126 | *.gpState
127 | 
128 | # ReSharper is a .NET coding add-in
129 | _ReSharper*/
130 | *.[Rr]e[Ss]harper
131 | *.DotSettings.user
132 | 
133 | # JustCode is a .NET coding add-in
134 | .JustCode
135 | 
136 | # TeamCity is a build add-in
137 | _TeamCity*
138 | 
139 | # DotCover is a Code Coverage Tool
140 | *.dotCover
141 | 
142 | # Visual Studio code coverage results
143 | *.coverage
144 | *.coveragexml
145 | 
146 | # NCrunch
147 | _NCrunch_*
148 | .*crunch*.local.xml
149 | nCrunchTemp_*
150 | 
151 | # MightyMoose
152 | *.mm.*
153 | AutoTest.Net/
154 | 
155 | # Web workbench (sass)
156 | .sass-cache/
157 | 
158 | # Installshield output folder
159 | [Ee]xpress/
160 | 
161 | # DocProject is a documentation generator add-in
162 | DocProject/buildhelp/
163 | DocProject/Help/*.HxT
164 | DocProject/Help/*.HxC
165 | DocProject/Help/*.hhc
166 | DocProject/Help/*.hhk
167 | DocProject/Help/*.hhp
168 | DocProject/Help/Html2
169 | DocProject/Help/html
170 | 
171 | # Click-Once directory
172 | publish/
173 | 
174 | # Publish Web Output
175 | *.[Pp]ublish.xml
176 | *.azurePubxml
177 | # TODO: Uncomment the next line to ignore your web deploy settings.
178 | # By default, sensitive information, such as encrypted password
179 | # should be stored in the .pubxml.user file.
180 | #*.pubxml
181 | *.pubxml.user
182 | *.publishproj
183 | 
184 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
185 | # checkin your Azure Web App publish settings, but sensitive information contained
186 | # in these scripts will be unencrypted
187 | PublishScripts/
188 | 
189 | # NuGet Packages
190 | *.nupkg
191 | # The packages folder can be ignored because of Package Restore
192 | **/packages/*
193 | # except build/, which is used as an MSBuild target.
194 | !**/packages/build/
195 | # Uncomment if necessary however generally it will be regenerated when needed
196 | #!**/packages/repositories.config
197 | # NuGet v3's project.json files produces more ignorable files
198 | *.nuget.props
199 | *.nuget.targets
200 | 
201 | # Microsoft Azure Build Output
202 | csx/
203 | *.build.csdef
204 | 
205 | # Microsoft Azure Emulator
206 | ecf/
207 | rcf/
208 | 
209 | # Windows Store app package directories and files
210 | AppPackages/
211 | BundleArtifacts/
212 | Package.StoreAssociation.xml
213 | _pkginfo.txt
214 | 
215 | # Visual Studio cache files
216 | # files ending in .cache can be ignored
217 | *.[Cc]ache
218 | # but keep track of directories ending in .cache
219 | !*.[Cc]ache/
220 | 
221 | # Others
222 | ClientBin/
223 | ~$*
224 | *~
225 | *.dbmdl
226 | *.dbproj.schemaview
227 | *.jfm
228 | *.pfx
229 | *.publishsettings
230 | orleans.codegen.cs
231 | 
232 | # Since there are multiple workflows, uncomment next line to ignore bower_components
233 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
234 | #bower_components/
235 | 
236 | # RIA/Silverlight projects
237 | Generated_Code/
238 | 
239 | # Backup & report files from converting an old project file
240 | # to a newer Visual Studio version. Backup files are not needed,
241 | # because we have git ;-)
242 | _UpgradeReport_Files/
243 | Backup*/
244 | UpgradeLog*.XML
245 | UpgradeLog*.htm
246 | 
247 | # SQL Server files
248 | *.mdf
249 | *.ldf
250 | *.ndf
251 | 
252 | # Business Intelligence projects
253 | *.rdl.data
254 | *.bim.layout
255 | *.bim_*.settings
256 | 
257 | # Microsoft Fakes
258 | FakesAssemblies/
259 | 
260 | # GhostDoc plugin setting file
261 | *.GhostDoc.xml
262 | 
263 | # Node.js Tools for Visual Studio
264 | .ntvs_analysis.dat
265 | node_modules/
266 | 
267 | # Typescript v1 declaration files
268 | typings/
269 | 
270 | # Visual Studio 6 build log
271 | *.plg
272 | 
273 | # Visual Studio 6 workspace options file
274 | *.opt
275 | 
276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
277 | *.vbw
278 | 
279 | # Visual Studio LightSwitch build output
280 | **/*.HTMLClient/GeneratedArtifacts
281 | **/*.DesktopClient/GeneratedArtifacts
282 | **/*.DesktopClient/ModelManifest.xml
283 | **/*.Server/GeneratedArtifacts
284 | **/*.Server/ModelManifest.xml
285 | _Pvt_Extensions
286 | 
287 | # Paket dependency manager
288 | .paket/paket.exe
289 | paket-files/
290 | 
291 | # FAKE - F# Make
292 | .fake/
293 | 
294 | # JetBrains Rider
295 | .idea/
296 | *.sln.iml
297 | 
298 | # CodeRush
299 | .cr/
300 | 
301 | # Python Tools for Visual Studio (PTVS)
302 | __pycache__/
303 | *.pyc
304 | 
305 | # Cake - Uncomment if you are using it
306 | # tools/**
307 | # !tools/packages.config
308 | 
309 | # Telerik's JustMock configuration file
310 | *.jmconfig
311 | 
312 | # BizTalk build output
313 | *.btp.cs
314 | *.btm.cs
315 | *.odx.cs
316 | *.xsd.cs
317 | 
318 | ### VisualStudio Patch ###
319 | # By default, sensitive information, such as encrypted password
320 | # should be stored in the .pubxml.user file.
321 | 
322 | 
323 | # End of https://www.gitignore.io/api/visualstudio
324 | TestsWeb/debug.log
325 | 
326 | venv.ps1
327 | *.code-workspace
328 | run.cmd
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Azure Cosmos DB MCP CLient & Server
  2 | 
  3 | This repository contains a project that shows how to create an MCP Server and client for Azure Cosmos DB. The project is divided into 2 parts:
  4 | 
  5 | - Frontend application: NextJS 15 application that displays a products catalog and features an AI Assistant that helps users to find products in the catalog and get past orders
  6 | - an MCP Server component, connected to the Azure Cosmos DB NoSQL database and responsible for reading products and orders from the database.
  7 | 
  8 | 
  9 | ![Demo](assets/demo.gif)
 10 | 
 11 | ## Azure Architecture
 12 | 
 13 | - an Azure Cosmos DB NoSQL database that stores the product catalog
 14 | - a node.js server that serves as the MCP Server component
 15 | 
 16 | 
 17 | ## References
 18 | 
 19 | - [Create an Azure Cosmos DB for NoSQL account](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/quickstart-portal)
 20 | - [Create an Azure Storage account](https://learn.microsoft.com/en-us/azure/storage/common/storage-account-create?tabs=azure-portal)
 21 | - [Create a Windows virtual machine](https://learn.microsoft.com/en-us/azure/virtual-machines/windows/quick-create-portal)
 22 | - [Windows execution policies](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-executionpolicy?view=powershell-7.5)
 23 | 
 24 | ## Step-by-step walkthrough
 25 | 
 26 | ### Installation
 27 | 
 28 | **Azure Cosmos DB**
 29 | 
 30 | In the Azure portal, create an Azure Cosmos DB for NoSQL account.
 31 | 
 32 | - Give a unique name for your Azure Cosmos DB account. We will be using cosmos-eastus2-nosql-2 in the rest of this walkthrough.
 33 | 
 34 | ![Cosmos DB - Basics](assets/cosmos-basics.png)
 35 | 
 36 | - Click on "Next: Global distribution"
 37 | 
 38 | ![Cosmos DB - Global distribution](assets/cosmos-global-distribution.png)
 39 | 
 40 | - Accept the default values and click on "Next: Networking"
 41 | 
 42 | ![Cosmos DB - Networking](assets/cosmos-networking.png)
 43 | 
 44 | - Accept the default values and click on "Next: Backup Policy"
 45 | - Select "Periodic" backup policy
 46 | - Select "Locally-redundant backup storage"
 47 | 
 48 | ![Cosmos DB - Backup Policy](assets/cosmos-backup-policy.png)
 49 | 
 50 | - Click on "Next: Encryption"
 51 | 
 52 | ![Cosmos DB - Encryption](assets/cosmos-encryption.png)
 53 | 
 54 | - Click on "Review and Create" to start validation
 55 | 
 56 | ![Cosmos DB - Validation](assets/cosmos-validation.png)
 57 | 
 58 | - Click on "Create" to start the creation of the Azure Cosmos DB for NoSQL account
 59 | 
 60 | For this project, you will need to enable vector support on the Azure Cosmos DB account.
 61 | - In the settings section, select Features, then "Vector Search for NoSQL API"
 62 | 
 63 | - In the panel that opens, click on the Enable button
 64 | 
 65 | ![Cosmos DB - Validation](assets/cosmos-enable-vector-search.png)
 66 | 
 67 | - Create the Azure Cosmos DB eShop database and the Products container
 68 | 
 69 | - Click on "..." next to eShop to display the contextual menu and select "New container" to create the "carts" container in the eShop database.
 70 | 
 71 | Make sure that the partition key is **_"/id"_** (the partition key is case-sensitive)
 72 | 
 73 | Expand "Container Vector Policy" and click on the "Add vector embedding" button
 74 | 
 75 | ![Cosmos DB - Create database](assets/cosmos-create-products.png)
 76 | 
 77 | - Create the carts container
 78 | 
 79 | ![Cosmos DB - Create database](assets/cosmos-create-carts.png)
 80 | 
 81 | **Storage account**
 82 | 
 83 | 1. Create a storage account to store the product images
 84 | 
 85 | For more details, refer to the documentation: https://learn.microsoft.com/en-us/azure/storage/common/storage-account-create?tabs=azure-portal
 86 | 
 87 | ![Storage - Basics](assets/storage-basics.png)
 88 | 
 89 | ![Storage - Advanced](assets/storage-advanced.png)
 90 | 
 91 | ![Storage - Networking](assets/storage-networking.png)
 92 | 
 93 | ![Storage - Data protection](assets/storage-data-protection.png)
 94 | 
 95 | ![Storage - Encryption](assets/storage-encryption.png)
 96 | 
 97 | ![Storage - Validation](assets/storage-validation.png)
 98 | 
 99 | 
100 | **Install software pre-requisites **
101 | 
102 | 1. Create a virtual machine in Azure or use your local computer
103 | 2. Install node.js v22.13.1 (LTS) from https://nodejs.org/en/download
104 | 3. Install Visual Studio Code x64 1.97.0 from https://code.visualstudio.com/download
105 | 4. Install Git 2.47.12 x64 from https://git-scm.com/downloads
106 | 5. Install .NET SDK x64 v9.0.102 from https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/sdk-9.0.102-windows-x64-installer
107 | 6. Open a terminal window and add nuget source with
108 | 
109 | ```sh
110 | dotnet nuget add source https://api.nuget.org/v3/index.json -n nuget.org
111 | ```
112 | 
113 | 7. If necessary, change PowerShell execution policies for Windows computers. Open a Powershell window **in administrator mode** and run this command
114 | 
115 | ```sh
116 | Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
117 | ```
118 | 
119 | 8. If necessary, install nuget, powershell, az cli and az modules
120 | 
121 | ```sh
122 | # install az cli
123 | winget install -e --id Microsoft.AzureCLI
124 | 
125 | # install nuget and reference nuget source
126 | Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
127 | 
128 | # update to latest Powershell release (7.5 as of writing)
129 | winget install --id Microsoft.PowerShell --source winget
130 | 
131 | # install az modules
132 | Install-Module -Name Az -Repository PSGallery -Force -AllowClobber
133 | ```
134 | 
135 | 9. Open a terminal window and clone the repository:
136 | 
137 | ```sh
138 | git clone https://github.com/patrice-truong/cosmosdb-mcp.git
139 | cd cosmosdb-mcp
140 | ```
141 | 
142 | 10. Navigate to the nextjs folder and install dependencies
143 | 
144 | ```sh
145 | cd cosmosdb-mcp/nextjs
146 | npm install  --legacy-peer-deps
147 | ```
148 | 
149 | 11. In the nextjs folder, create and configure an .env file with the following values:
150 | 
151 | ```sh
152 | AZURE_COSMOSDB_NOSQL_ENDPOINT=https://<cosmosdb_account_name>.documents.azure.com:443/
153 | AZURE_COSMOSDB_NOSQL_DATABASE=eshop
154 | AZURE_COSMOSDB_NOSQL_PRODUCTS_CONTAINER=products
155 | AZURE_COSMOSDB_NOSQL_CARTS_CONTAINER=carts
156 | AZURE_COSMOSDB_NOSQL_ORDERS_CONTAINER=orders
157 | AZURE_STORAGE_ACCOUNT_NAME=<storage_account_name>
158 | AZURE_STORAGE_CONTAINER_NAME=<container_name>
159 | ```
160 | 
161 | 12. Get your tenant ID. The tenant ID can be retrieved with this command:
162 | 
163 | ```sh
164 | az login
165 | az account show --query tenantId -o tsv
166 | ```
167 | 
168 | 13. In the webapi folder, configure the appsettings.json file and replace the tenant_id with the value obtained in the previous step:
169 | 
170 | ```sh
171 | {
172 |   "CosmosDb": {
173 |     "Endpoint": "https:/<cosmosdb_account_name>.documents.azure.com:443/",
174 |     "TenantId": "<tenant_id>",
175 |     "DatabaseName": "eshop",
176 |     "ProductsContainerName": "products",
177 |     "CartsContainerName": "carts",
178 |     "OrdersContainerName": "orders"
179 |   },
180 |   "AzureBlobStorage": {
181 |     "AccountName": "<storage_account_name>"
182 |   }
183 | }
184 | ```
185 | 14. Create an app registration in the Azure Portal
186 | 15. Create an app secret in the Azure Portal
187 | 16. You will need to allow your app to get access to Azure Cosmos DB. Retrieve the 4 ids mentioned below and modify the file "populate/set_rbac.ps1".
188 | 
189 | | Variable                     | Reference                                         |
190 | | ---------------------------- | ------------------------------------------------- |
191 | | Subscription Id              | Cosmos DB > Overview > Subscription Id            |
192 | | Azure Cosmos DB account name | cosmos-eastus2-nosql-2                   |
193 | | Resource group name          | Cosmos DB > Overview > Resource group name        |
194 | | Principal Id                 | App registration Object Id |
195 | 
196 | ```sh
197 | $SubscriptionId = "<subscription-id>"   # Azure subscription id
198 | $AccountName = "<cosmosdb-account-name>"    # cosmos db account name
199 | $ResourceGroupName = "<resource-group-name>" # resource group name of the Cosmos DB account
200 | $PrincipalId = "<principal-id>"   # object id of the app registered in Entra ID
201 | ```
202 | 
203 | 17. Open a Powershell prompt, run Connect-AzAccount and execute ./set_rbac.ps1
204 | 
205 | ![Cosmos DB - RBAC](assets/cosmos-rbac.png)
206 | 
207 | 18. Allow your app (or virtual machine) to access the storage account
208 | 
209 | - In the Azure portal, goto your storage account
210 | - Select Access Control (IAM) in the menu
211 | 
212 | ![Storage - Access Control](assets/storage-access-control.png)
213 | 
214 | - Click on "Add role assignment"
215 | - In the filter textbox, type "Storage Blob Data Contributor"
216 | 
217 | ![Storage - Blob Data contributor](assets/storage-blob-data-contributor.png)
218 | 
219 | - Click on "Members"
220 | - Select the name of your application
221 | 
222 | ![Storage - Role assignment](assets/storage-role-assignment.png)
223 | 
224 | - Click on the "Select" button
225 | - Click on "Review and assign"
226 | 
227 | ![Storage - Role assignment](assets/storage-review.png)
228 | 
229 | 19. Create a container and copy the content of the "azure-storage" folder to your storage account
230 | 
231 | ![Storage - Create container](assets/storage-create-container.png)
232 | 
233 | ![Storage - Upload files](assets/storage-upload-files.png)
234 | 
235 | ![Storage - Files uploaded](assets/storage-files-uploaded.png)
236 | 
237 | 20. Build webapi backend project with dotnet build
238 | 
239 | ```sh
240 | cd webapi
241 | dotnet build
242 | ```
243 | 
244 | ![Dotnet build](assets/dotnet_build.png) 18. On your secondary region VM (Australia East), modify the .env file with the IP address of the socket server in your primary region (East US 2)
245 | 
246 | ![socket_server_ip](assets/socket_server_ip.png)
247 | 
248 | 19. There is no authentication built into this project. The user email is hard-coded in /nextjs/models/constants.ts. Change it to suit your demo needs
249 | 
250 | ![npm run build](assets/constants_email.png)
251 | 
252 | 19. In mcp-server and nextjs folders, copy .env.template to .env and modify the values to suit your demo needs
253 | 
254 | ```json
255 | AZURE_COSMOSDB_NOSQL_ENDPOINT=https://<cosmosdb_account>.documents.azure.com:443/
256 | AZURE_COSMOSDB_NOSQL_DATABASE=eshop
257 | AZURE_COSMOSDB_NOSQL_PRODUCTS_CONTAINER=products
258 | AZURE_COSMOSDB_NOSQL_CARTS_CONTAINER=carts
259 | AZURE_COSMOSDB_NOSQL_ORDERS_CONTAINER=orders
260 | 
261 | NEXT_PUBLIC_AZURE_TENANT_ID=<tenant_id>
262 | NEXT_PUBLIC_AZURE_CLIENT_ID=<client_id>
263 | NEXT_PUBLIC_AZURE_CLIENT_SECRET=<client_secret>
264 | 
265 | NEXT_PUBLIC_AZURE_STORAGE_ACCOUNT_NAME=<storage_account_name>
266 | NEXT_PUBLIC_AZURE_STORAGE_CONTAINER_NAME=img
267 | 
268 | AZURE_OPENAI_ENDPOINT=https://<azure_openai_account>.openai.azure.com/
269 | AZURE_OPENAI_API_KEY=<azure_openai_key>
270 | AZURE_OPENAI_EMBEDDING_MODEL=text-embedding-3-small
271 | AZURE_OPENAI_API_VERSION=2024-05-01-preview
272 | ```
273 | 
274 | 20. Build nextjs frontend project
275 | 
276 | ```sh
277 | cd nextjs
278 | npm run build
279 | ```
280 | 
281 | ![npm run build](assets/npm_run_build.png)
282 | 
283 | ## Populate the products catalog
284 | 
285 | In this section, we'll read the products catalog from the populate/catalog.json file and populate the Azure Cosmos DB for NoSQL database
286 | 
287 | 1. Modify appsettings.json with your cosmosdb account name and 
288 | 
289 | ```json
290 | {
291 |   "CosmosDb": {
292 |     "Endpoint": "https://<cosmosdb_account_name>.documents.azure.com:443/",
293 |     "TenantId": "<tenant_id>",
294 |     "DatabaseName": "eshop",
295 |     "ProductsContainerName": "products",
296 |     "OrdersContainerName": "orders",
297 |   }
298 | }
299 | ```
300 | 
301 | 2. Open a terminal window, navigate to the populate folder, execute az login, then dotnet run
302 | 
303 | ![Cosmos - Populate products](assets/cosmos-populate-products.png)
304 | 
305 | 3. Verify that the Azure Cosmos DB container has been properly populated
306 | 
307 | ![Cosmos - Products](assets/cosmos-products.png)
308 | 
309 | ## Demo script
310 | 
311 | **Demo initialization:**
312 | 
313 | 3. On your development computer, start the mcp server
314 | 
315 | ```sh
316 | cd mcp-server
317 | npx ts-node src/server.ts
318 | ```
319 | 
320 | 3. Start the front end project
321 | 
322 | - NextJS front end (store front)
323 |   - cd nextjs
324 |   - npm start
325 | 
326 | 4. Optionally, open a command prompt and start the MCP inspector with this command:
327 | npx -y @modelcontextprotocol/inspector
328 | 
329 | 
330 | **Demo steps:**
331 | 
332 | 1. Navigate to http://localhost:3002. 
333 | 2. 
334 | 2. Click on AI Assistant icon in the top right corner
335 | 3. Enter "I'm interested in backpacks" (the list of product refreshes with a list of backpacks)
336 | 4. Enter "Get my orders" (the list of orders refreshes with a list of orders)
337 | 
338 | 
339 | ![Demo](assets/demo.gif)
340 | 
```

--------------------------------------------------------------------------------
/mcp-server/run_mcp_server.cmd:
--------------------------------------------------------------------------------

```
1 | npx ts-node src/server.ts
```

--------------------------------------------------------------------------------
/nextjs/models/constants.ts:
--------------------------------------------------------------------------------

```typescript
1 | // /models/constants.ts
2 | export const EMAIL = '[email protected]'
3 | 
4 | 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "dependencies": {
3 |     "@types/uuid": "^10.0.0",
4 |     "uuid": "^11.1.0"
5 |   }
6 | }
7 | 
```

--------------------------------------------------------------------------------
/nextjs/postcss.config.js:
--------------------------------------------------------------------------------

```javascript
1 | module.exports = {
2 |   plugins: {
3 |     tailwindcss: {},
4 |     autoprefixer: {},
5 |   },
6 | };
7 | 
```

--------------------------------------------------------------------------------
/nextjs/models/cart.ts:
--------------------------------------------------------------------------------

```typescript
1 | import { CartItem } from "./cartItem"
2 | 
3 | export type Cart = {
4 |     userName: string
5 |     items: CartItem[]
6 |   }
7 |   
```

--------------------------------------------------------------------------------
/nextjs/models/cartItem.ts:
--------------------------------------------------------------------------------

```typescript
1 | export type CartItem = {
2 |   id: number
3 |   name: string
4 |   price: number
5 |   quantity: number,
6 |   imageUrl: string
7 | }
```

--------------------------------------------------------------------------------
/nextjs/app/page.tsx:
--------------------------------------------------------------------------------

```typescript
1 | import { redirect } from "next/navigation";
2 | 
3 | export default function Home() {
4 |   redirect("http://localhost:3002/products");
5 | }
6 | 
```

--------------------------------------------------------------------------------
/nextjs/models/product.ts:
--------------------------------------------------------------------------------

```typescript
 1 | export type Product = {
 2 |   id: string;
 3 |   type: string;
 4 |   brand: string;
 5 |   description: string;
 6 |   name: string;
 7 |   price: number;
 8 |   imageUrl: string;  
 9 | };
10 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/aspect-ratio.tsx:
--------------------------------------------------------------------------------

```typescript
1 | 'use client';
2 | 
3 | import * as AspectRatioPrimitive from '@radix-ui/react-aspect-ratio';
4 | 
5 | const AspectRatio = AspectRatioPrimitive.Root;
6 | 
7 | export { AspectRatio };
8 | 
```

--------------------------------------------------------------------------------
/nextjs/lib/utils.ts:
--------------------------------------------------------------------------------

```typescript
1 | import { clsx, type ClassValue } from 'clsx';
2 | import { twMerge } from 'tailwind-merge';
3 | 
4 | export function cn(...inputs: ClassValue[]) {
5 |   return twMerge(clsx(inputs));
6 | }
7 | 
```

--------------------------------------------------------------------------------
/nextjs/app/cart/layout.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | export const dynamic = 'force-dynamic'
 2 | export const revalidate = 0
 3 | 
 4 | export default function CartLayout({
 5 |   children,
 6 | }: {
 7 |   children: React.ReactNode
 8 | }) {
 9 |   return children
10 | }
```

--------------------------------------------------------------------------------
/nextjs/next-env.d.ts:
--------------------------------------------------------------------------------

```typescript
1 | /// <reference types="next" />
2 | /// <reference types="next/image-types/global" />
3 | 
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
6 | 
```

--------------------------------------------------------------------------------
/nextjs/models/cartContextType.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { CartItem } from "./cartItem"
 2 | 
 3 | export type CartContextType = {
 4 |   items: CartItem[]
 5 |   addItem: (item: Omit<CartItem, 'quantity'>) => void
 6 |   removeItem: (id: number) => void
 7 |   updateQuantity: (id: number, quantity: number) => void
 8 |   clearCart: () => void
 9 | }
10 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/skeleton.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | import { cn } from '@/lib/utils';
 2 | 
 3 | function Skeleton({
 4 |   className,
 5 |   ...props
 6 | }: React.HTMLAttributes<HTMLDivElement>) {
 7 |   return (
 8 |     <div
 9 |       className={cn('animate-pulse rounded-md bg-muted', className)}
10 |       {...props}
11 |     />
12 |   );
13 | }
14 | 
15 | export { Skeleton };
16 | 
```

--------------------------------------------------------------------------------
/populate/product.cs:
--------------------------------------------------------------------------------

```csharp
 1 | public class Product
 2 | {
 3 |     public int id { get; set; }
 4 |     public string type { get; set; }
 5 |     public string brand { get; set; }
 6 |     public string name { get; set; }
 7 |     public string description { get; set; }
 8 |     public decimal price { get; set; }
 9 |     public float[] embedding { get; set;}
10 | }
11 | 
```

--------------------------------------------------------------------------------
/mcp-server/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "es6",
 4 |     "module": "commonjs",
 5 |     "outDir": "./dist",
 6 |     "rootDir": "./src",
 7 |     "strict": true,
 8 |     "esModuleInterop": true,
 9 |     "skipLibCheck": true,
10 |     "forceConsistentCasingInFileNames": true
11 |   },
12 |   "include": ["src/**/*"],
13 |   "exclude": ["node_modules"]
14 | }
```

--------------------------------------------------------------------------------
/nextjs/components/ui/collapsible.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
 4 | 
 5 | const Collapsible = CollapsiblePrimitive.Root;
 6 | 
 7 | const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;
 8 | 
 9 | const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent;
10 | 
11 | export { Collapsible, CollapsibleTrigger, CollapsibleContent };
12 | 
```

--------------------------------------------------------------------------------
/nextjs/next.config.js:
--------------------------------------------------------------------------------

```javascript
 1 | /** @type {import('next').NextConfig} */
 2 | const nextConfig = {
 3 |   env: {
 4 |     AZURE_STORAGE_ACCOUNT_NAME: process.env.AZURE_STORAGE_ACCOUNT_NAME,
 5 |     AZURE_STORAGE_CONTAINER_NAME: process.env.AZURE_STORAGE_CONTAINER_NAME,
 6 |   },
 7 |   // output: 'export',
 8 |   eslint: {
 9 |     ignoreDuringBuilds: true,
10 |   },
11 |   images: { unoptimized: true },
12 | };
13 | 
14 | module.exports = nextConfig;
15 | 
```

--------------------------------------------------------------------------------
/nextjs/components.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "$schema": "https://ui.shadcn.com/schema.json",
 3 |   "style": "default",
 4 |   "rsc": true,
 5 |   "tsx": true,
 6 |   "tailwind": {
 7 |     "config": "tailwind.config.ts",
 8 |     "css": "app/globals.css",
 9 |     "baseColor": "neutral",
10 |     "cssVariables": true,
11 |     "prefix": ""
12 |   },
13 |   "aliases": {
14 |     "components": "@/components",
15 |     "utils": "@/lib/utils",
16 |     "ui": "@/components/ui",
17 |     "lib": "@/lib",
18 |     "hooks": "@/hooks"
19 |   }
20 | }
21 | 
```

--------------------------------------------------------------------------------
/nextjs/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "es5",
 4 |     "lib": ["dom", "dom.iterable", "esnext"],
 5 |     "allowJs": true,
 6 |     "skipLibCheck": true,
 7 |     "strict": true,
 8 |     "noEmit": true,
 9 |     "esModuleInterop": true,
10 |     "module": "esnext",
11 |     "moduleResolution": "bundler",
12 |     "resolveJsonModule": true,
13 |     "isolatedModules": true,
14 |     "jsx": "preserve",
15 |     "incremental": true,
16 |     "plugins": [
17 |       {
18 |         "name": "next"
19 |       }
20 |     ],
21 |     "paths": {
22 |       "@/*": ["./*"]
23 |     }
24 |   },
25 |   "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
26 |   "exclude": ["node_modules"]
27 | }
28 | 
```

--------------------------------------------------------------------------------
/mcp-server/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "mcp-server",
 3 |   "version": "1.0.0",
 4 |   "main": "index.js",
 5 |   "scripts": {
 6 |     "start": "node dist/server.js",
 7 |     "dev": "nodemon src/server.ts",
 8 |     "build": "tsc"
 9 |   },
10 |   "keywords": [],
11 |   "author": "",
12 |   "license": "ISC",
13 |   "description": "",
14 |   "dependencies": {
15 |     "@azure/cosmos": "^4.2.0",
16 |     "@azure/identity": "^4.8.0",
17 |     "@azure/openai": "^2.0.0",
18 |     "@modelcontextprotocol/sdk": "^1.8.0",
19 |     "@types/cors": "^2.8.17",
20 |     "@types/express": "^5.0.1",
21 |     "@types/node": "^22.13.13",
22 |     "cors": "^2.8.5",
23 |     "dotenv": "^16.4.7",
24 |     "express": "^4.21.2",
25 |     "nodemon": "^3.1.9",
26 |     "openai": "^4.90.0",
27 |     "ts-node": "^10.9.2",
28 |     "typescript": "^5.8.2"
29 |   }
30 | }
31 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/label.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import * as React from 'react';
 4 | import * as LabelPrimitive from '@radix-ui/react-label';
 5 | import { cva, type VariantProps } from 'class-variance-authority';
 6 | 
 7 | import { cn } from '@/lib/utils';
 8 | 
 9 | const labelVariants = cva(
10 |   'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'
11 | );
12 | 
13 | const Label = React.forwardRef<
14 |   React.ElementRef<typeof LabelPrimitive.Root>,
15 |   React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
16 |     VariantProps<typeof labelVariants>
17 | >(({ className, ...props }, ref) => (
18 |   <LabelPrimitive.Root
19 |     ref={ref}
20 |     className={cn(labelVariants(), className)}
21 |     {...props}
22 |   />
23 | ));
24 | Label.displayName = LabelPrimitive.Root.displayName;
25 | 
26 | export { Label };
27 | 
```

--------------------------------------------------------------------------------
/nextjs/components/CartItemCount.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client'
 2 | 
 3 | import Link from 'next/link'
 4 | import { ShoppingCart } from 'lucide-react'
 5 | import io from 'socket.io-client'
 6 | import { useCart } from '@/context/CartContext'
 7 | import { useEffect } from 'react'
 8 | 
 9 | export default function CartItemCount () {
10 |   const { items } = useCart()
11 |   const itemCount = items.reduce((total, item) => total + item.quantity, 0)
12 | 
13 |   return (
14 |     <Link href='/cart' className='relative p-2 hover:bg-gray-100 rounded-full'>
15 |       <ShoppingCart className='h-6 w-6' />
16 |       {itemCount > 0 && (
17 |         <span className='absolute top-0 right-0 inline-flex items-center justify-center px-2 py-1 text-xs font-bold leading-none text-red-100 bg-red-600 rounded-full'>
18 |           {itemCount}
19 |         </span>
20 |       )}
21 |     </Link>
22 |   )
23 | }
24 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/separator.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import * as React from 'react';
 4 | import * as SeparatorPrimitive from '@radix-ui/react-separator';
 5 | 
 6 | import { cn } from '@/lib/utils';
 7 | 
 8 | const Separator = React.forwardRef<
 9 |   React.ElementRef<typeof SeparatorPrimitive.Root>,
10 |   React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
11 | >(
12 |   (
13 |     { className, orientation = 'horizontal', decorative = true, ...props },
14 |     ref
15 |   ) => (
16 |     <SeparatorPrimitive.Root
17 |       ref={ref}
18 |       decorative={decorative}
19 |       orientation={orientation}
20 |       className={cn(
21 |         'shrink-0 bg-border',
22 |         orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
23 |         className
24 |       )}
25 |       {...props}
26 |     />
27 |   )
28 | );
29 | Separator.displayName = SeparatorPrimitive.Root.displayName;
30 | 
31 | export { Separator };
32 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/textarea.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | import * as React from 'react';
 2 | 
 3 | import { cn } from '@/lib/utils';
 4 | 
 5 | export interface TextareaProps
 6 |   extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
 7 | 
 8 | const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
 9 |   ({ className, ...props }, ref) => {
10 |     return (
11 |       <textarea
12 |         className={cn(
13 |           'flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
14 |           className
15 |         )}
16 |         ref={ref}
17 |         {...props}
18 |       />
19 |     );
20 |   }
21 | );
22 | Textarea.displayName = 'Textarea';
23 | 
24 | export { Textarea };
25 | 
```

--------------------------------------------------------------------------------
/nextjs/app/api/orders/route.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { NextRequest, NextResponse } from 'next/server';
 2 | import { cosmosDBService } from '@/lib/cosmosdb';
 3 | 
 4 | export async function POST(request: NextRequest) {
 5 |   try {
 6 |     const order = await request.json();
 7 |     
 8 |     if (!order || !order.items || !order.total) {
 9 |       return NextResponse.json(
10 |         { error: 'Invalid order data' },
11 |         { status: 400 }
12 |       );
13 |     }
14 | 
15 |     const { resources: items } = await cosmosDBService.database
16 |       .container('orders')
17 |       .items.create(order);
18 | 
19 |     return NextResponse.json({ 
20 |       message: 'Order created successfully',
21 |       orderId: order.id
22 |     });
23 | 
24 |   } catch (error) {
25 |     console.error('Error creating order:', error);
26 |     return NextResponse.json(
27 |       { error: 'Failed to create order' },
28 |       { status: 500 }
29 |     );
30 |   }
31 | }
```

--------------------------------------------------------------------------------
/nextjs/components/ui/toaster.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import { useToast } from '@/hooks/use-toast';
 4 | import {
 5 |   Toast,
 6 |   ToastClose,
 7 |   ToastDescription,
 8 |   ToastProvider,
 9 |   ToastTitle,
10 |   ToastViewport,
11 | } from '@/components/ui/toast';
12 | 
13 | export function Toaster() {
14 |   const { toasts } = useToast();
15 | 
16 |   return (
17 |     <ToastProvider>
18 |       {toasts.map(function ({ id, title, description, action, ...props }) {
19 |         return (
20 |           <Toast key={id} {...props}>
21 |             <div className="grid gap-1">
22 |               {title && <ToastTitle>{title}</ToastTitle>}
23 |               {description && (
24 |                 <ToastDescription>{description}</ToastDescription>
25 |               )}
26 |             </div>
27 |             {action}
28 |             <ToastClose />
29 |           </Toast>
30 |         );
31 |       })}
32 |       <ToastViewport />
33 |     </ToastProvider>
34 |   );
35 | }
36 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/progress.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import * as React from 'react';
 4 | import * as ProgressPrimitive from '@radix-ui/react-progress';
 5 | 
 6 | import { cn } from '@/lib/utils';
 7 | 
 8 | const Progress = React.forwardRef<
 9 |   React.ElementRef<typeof ProgressPrimitive.Root>,
10 |   React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>
11 | >(({ className, value, ...props }, ref) => (
12 |   <ProgressPrimitive.Root
13 |     ref={ref}
14 |     className={cn(
15 |       'relative h-4 w-full overflow-hidden rounded-full bg-secondary',
16 |       className
17 |     )}
18 |     {...props}
19 |   >
20 |     <ProgressPrimitive.Indicator
21 |       className="h-full w-full flex-1 bg-primary transition-all"
22 |       style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
23 |     />
24 |   </ProgressPrimitive.Root>
25 | ));
26 | Progress.displayName = ProgressPrimitive.Root.displayName;
27 | 
28 | export { Progress };
29 | 
```

--------------------------------------------------------------------------------
/nextjs/app/api/orders/[id]/route.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { NextRequest, NextResponse } from 'next/server';
 2 | import { cosmosDBService } from '@/lib/cosmosdb';
 3 | 
 4 | export async function GET(
 5 |   request: NextRequest,
 6 |   { params }: { params: { id: string } }
 7 | ) {
 8 |   try {
 9 |     const { resources: items } = await cosmosDBService.ordersContainer.items
10 |       .query({
11 |         query: 'SELECT * FROM c WHERE c.id = @id',
12 |         parameters: [{ name: '@id', value: params.id }]
13 |       })
14 |       .fetchAll();
15 | 
16 |     if (items.length === 0) {
17 |       return NextResponse.json({ error: 'Order not found' }, { status: 404 });
18 |     }
19 | 
20 |     return NextResponse.json({ 
21 |       data: items[0],
22 |       statusCode: 200 
23 |     });
24 |   } catch (error) {
25 |     console.error('Error fetching order:', error);
26 |     return NextResponse.json(
27 |       { error: 'Failed to fetch order' },
28 |       { status: 500 }
29 |     );
30 |   }
31 | }
```

--------------------------------------------------------------------------------
/nextjs/components/ui/input.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | import * as React from 'react';
 2 | 
 3 | import { cn } from '@/lib/utils';
 4 | 
 5 | export interface InputProps
 6 |   extends React.InputHTMLAttributes<HTMLInputElement> {}
 7 | 
 8 | const Input = React.forwardRef<HTMLInputElement, InputProps>(
 9 |   ({ className, type, ...props }, ref) => {
10 |     return (
11 |       <input
12 |         type={type}
13 |         className={cn(
14 |           'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
15 |           className
16 |         )}
17 |         ref={ref}
18 |         {...props}
19 |       />
20 |     );
21 |   }
22 | );
23 | Input.displayName = 'Input';
24 | 
25 | export { Input };
26 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/sonner.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import { useTheme } from 'next-themes';
 4 | import { Toaster as Sonner } from 'sonner';
 5 | 
 6 | type ToasterProps = React.ComponentProps<typeof Sonner>;
 7 | 
 8 | const Toaster = ({ ...props }: ToasterProps) => {
 9 |   const { theme = 'system' } = useTheme();
10 | 
11 |   return (
12 |     <Sonner
13 |       theme={theme as ToasterProps['theme']}
14 |       className="toaster group"
15 |       toastOptions={{
16 |         classNames: {
17 |           toast:
18 |             'group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg',
19 |           description: 'group-[.toast]:text-muted-foreground',
20 |           actionButton:
21 |             'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',
22 |           cancelButton:
23 |             'group-[.toast]:bg-muted group-[.toast]:text-muted-foreground',
24 |         },
25 |       }}
26 |       {...props}
27 |     />
28 |   );
29 | };
30 | 
31 | export { Toaster };
32 | 
```

--------------------------------------------------------------------------------
/mcp-server/src/aoai.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import * as dotenv from "dotenv";
 2 | 
 3 | import { AzureOpenAI } from "openai";
 4 | 
 5 | const FILE_NAME = "src/aoai.ts";
 6 | 
 7 | /**
 8 |  * Get embeddings from Azure OpenAI
 9 |  * @param {string} q
10 |  * @returns {Promise<number[]>}
11 |  */
12 | export const getEmbeddingsAsync = async (q: string) => {
13 |   try {
14 |     console.log(`[${FILE_NAME}] q: ${q}`);
15 | 
16 |     dotenv.config();
17 |     console.log(`[${FILE_NAME}] Embedding model=${process.env.AZURE_OPENAI_EMBEDDING_MODEL!}`);
18 | 
19 |     const client = new AzureOpenAI({
20 |       endpoint: process.env.AZURE_OPENAI_ENDPOINT,
21 |       apiKey: process.env.AZURE_OPENAI_API_KEY!,
22 |       apiVersion: "2024-12-01-preview",
23 |     });
24 | 
25 |     const embeddingResponse = await client.embeddings.create({
26 |       model: process.env.AZURE_OPENAI_EMBEDDING_MODEL!,
27 |       input: q,
28 |     });
29 |     const [{ embedding }] = embeddingResponse.data;
30 |     // console.log(`[${FILE_NAME}] Embeddings: ${JSON.stringify(embedding.slice(0, 50))}...`)
31 |     return embedding;
32 |   } catch (error) {
33 |     console.error(`[${FILE_NAME}] Error getting embeddings: ${JSON.stringify(error)}`);
34 |   }
35 | };
36 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/checkbox.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import * as React from 'react';
 4 | import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
 5 | import { Check } from 'lucide-react';
 6 | 
 7 | import { cn } from '@/lib/utils';
 8 | 
 9 | const Checkbox = React.forwardRef<
10 |   React.ElementRef<typeof CheckboxPrimitive.Root>,
11 |   React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
12 | >(({ className, ...props }, ref) => (
13 |   <CheckboxPrimitive.Root
14 |     ref={ref}
15 |     className={cn(
16 |       'peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
17 |       className
18 |     )}
19 |     {...props}
20 |   >
21 |     <CheckboxPrimitive.Indicator
22 |       className={cn('flex items-center justify-center text-current')}
23 |     >
24 |       <Check className="h-4 w-4" />
25 |     </CheckboxPrimitive.Indicator>
26 |   </CheckboxPrimitive.Root>
27 | ));
28 | Checkbox.displayName = CheckboxPrimitive.Root.displayName;
29 | 
30 | export { Checkbox };
31 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/slider.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import * as React from 'react';
 4 | import * as SliderPrimitive from '@radix-ui/react-slider';
 5 | 
 6 | import { cn } from '@/lib/utils';
 7 | 
 8 | const Slider = React.forwardRef<
 9 |   React.ElementRef<typeof SliderPrimitive.Root>,
10 |   React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
11 | >(({ className, ...props }, ref) => (
12 |   <SliderPrimitive.Root
13 |     ref={ref}
14 |     className={cn(
15 |       'relative flex w-full touch-none select-none items-center',
16 |       className
17 |     )}
18 |     {...props}
19 |   >
20 |     <SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full bg-secondary">
21 |       <SliderPrimitive.Range className="absolute h-full bg-primary" />
22 |     </SliderPrimitive.Track>
23 |     <SliderPrimitive.Thumb className="block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50" />
24 |   </SliderPrimitive.Root>
25 | ));
26 | Slider.displayName = SliderPrimitive.Root.displayName;
27 | 
28 | export { Slider };
29 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/badge.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | import * as React from 'react';
 2 | import { cva, type VariantProps } from 'class-variance-authority';
 3 | 
 4 | import { cn } from '@/lib/utils';
 5 | 
 6 | const badgeVariants = cva(
 7 |   'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
 8 |   {
 9 |     variants: {
10 |       variant: {
11 |         default:
12 |           'border-transparent bg-primary text-primary-foreground hover:bg-primary/80',
13 |         secondary:
14 |           'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
15 |         destructive:
16 |           'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80',
17 |         outline: 'text-foreground',
18 |       },
19 |     },
20 |     defaultVariants: {
21 |       variant: 'default',
22 |     },
23 |   }
24 | );
25 | 
26 | export interface BadgeProps
27 |   extends React.HTMLAttributes<HTMLDivElement>,
28 |     VariantProps<typeof badgeVariants> {}
29 | 
30 | function Badge({ className, variant, ...props }: BadgeProps) {
31 |   return (
32 |     <div className={cn(badgeVariants({ variant }), className)} {...props} />
33 |   );
34 | }
35 | 
36 | export { Badge, badgeVariants };
37 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/switch.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import * as React from 'react';
 4 | import * as SwitchPrimitives from '@radix-ui/react-switch';
 5 | 
 6 | import { cn } from '@/lib/utils';
 7 | 
 8 | const Switch = React.forwardRef<
 9 |   React.ElementRef<typeof SwitchPrimitives.Root>,
10 |   React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
11 | >(({ className, ...props }, ref) => (
12 |   <SwitchPrimitives.Root
13 |     className={cn(
14 |       'peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',
15 |       className
16 |     )}
17 |     {...props}
18 |     ref={ref}
19 |   >
20 |     <SwitchPrimitives.Thumb
21 |       className={cn(
22 |         'pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0'
23 |       )}
24 |     />
25 |   </SwitchPrimitives.Root>
26 | ));
27 | Switch.displayName = SwitchPrimitives.Root.displayName;
28 | 
29 | export { Switch };
30 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/tooltip.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import * as React from 'react';
 4 | import * as TooltipPrimitive from '@radix-ui/react-tooltip';
 5 | 
 6 | import { cn } from '@/lib/utils';
 7 | 
 8 | const TooltipProvider = TooltipPrimitive.Provider;
 9 | 
10 | const Tooltip = TooltipPrimitive.Root;
11 | 
12 | const TooltipTrigger = TooltipPrimitive.Trigger;
13 | 
14 | const TooltipContent = React.forwardRef<
15 |   React.ElementRef<typeof TooltipPrimitive.Content>,
16 |   React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
17 | >(({ className, sideOffset = 4, ...props }, ref) => (
18 |   <TooltipPrimitive.Content
19 |     ref={ref}
20 |     sideOffset={sideOffset}
21 |     className={cn(
22 |       'z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
23 |       className
24 |     )}
25 |     {...props}
26 |   />
27 | ));
28 | TooltipContent.displayName = TooltipPrimitive.Content.displayName;
29 | 
30 | export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
31 | 
```

--------------------------------------------------------------------------------
/mcp-server/src/server.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import 'dotenv/config'
 2 | 
 3 | import express, { Request, Response } from 'express'
 4 | 
 5 | import { CosmosDBMcpServer } from './cosmosdb-mcp-server'
 6 | import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'
 7 | import cors from 'cors'
 8 | 
 9 | const app = express()
10 | 
11 | // Add CORS middleware
12 | app.use(cors({
13 |   origin: 'http://localhost:3002',
14 |   credentials: true,
15 |   methods: ['GET', 'POST'],
16 |   allowedHeaders: ['Content-Type']
17 | }))
18 | 
19 | const cosmosDBMcpServer = new CosmosDBMcpServer()
20 | const server = cosmosDBMcpServer.getServer()
21 | 
22 | const transports: { [sessionId: string]: SSEServerTransport } = {}
23 | 
24 | app.get('/sse', async (_: Request, res: Response) => {
25 |   const transport = new SSEServerTransport('/messages', res)
26 |   transports[transport.sessionId] = transport
27 |   res.on('close', () => {
28 |     delete transports[transport.sessionId]
29 |   })
30 |   await server.connect(transport)
31 | })
32 | 
33 | app.post('/messages', async (req: Request, res: Response) => {
34 |   const sessionId = req.query.sessionId as string
35 |   const transport = transports[sessionId]
36 |   if (transport) {
37 |     await transport.handlePostMessage(req, res)
38 |   } else {
39 |     res.status(400).send('No transport found for sessionId')
40 |   }
41 | })
42 | 
43 | app.listen(3001)
44 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/hover-card.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import * as React from 'react';
 4 | import * as HoverCardPrimitive from '@radix-ui/react-hover-card';
 5 | 
 6 | import { cn } from '@/lib/utils';
 7 | 
 8 | const HoverCard = HoverCardPrimitive.Root;
 9 | 
10 | const HoverCardTrigger = HoverCardPrimitive.Trigger;
11 | 
12 | const HoverCardContent = React.forwardRef<
13 |   React.ElementRef<typeof HoverCardPrimitive.Content>,
14 |   React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>
15 | >(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
16 |   <HoverCardPrimitive.Content
17 |     ref={ref}
18 |     align={align}
19 |     sideOffset={sideOffset}
20 |     className={cn(
21 |       'z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
22 |       className
23 |     )}
24 |     {...props}
25 |   />
26 | ));
27 | HoverCardContent.displayName = HoverCardPrimitive.Content.displayName;
28 | 
29 | export { HoverCard, HoverCardTrigger, HoverCardContent };
30 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/popover.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import * as React from 'react';
 4 | import * as PopoverPrimitive from '@radix-ui/react-popover';
 5 | 
 6 | import { cn } from '@/lib/utils';
 7 | 
 8 | const Popover = PopoverPrimitive.Root;
 9 | 
10 | const PopoverTrigger = PopoverPrimitive.Trigger;
11 | 
12 | const PopoverContent = React.forwardRef<
13 |   React.ElementRef<typeof PopoverPrimitive.Content>,
14 |   React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
15 | >(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
16 |   <PopoverPrimitive.Portal>
17 |     <PopoverPrimitive.Content
18 |       ref={ref}
19 |       align={align}
20 |       sideOffset={sideOffset}
21 |       className={cn(
22 |         'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
23 |         className
24 |       )}
25 |       {...props}
26 |     />
27 |   </PopoverPrimitive.Portal>
28 | ));
29 | PopoverContent.displayName = PopoverPrimitive.Content.displayName;
30 | 
31 | export { Popover, PopoverTrigger, PopoverContent };
32 | 
```

--------------------------------------------------------------------------------
/nextjs/lib/mcp-client.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { Client } from "@modelcontextprotocol/sdk/client/index.js";
 2 | import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
 3 | 
 4 | export class MCPClient {
 5 |   private client: Client | null = null;
 6 | 
 7 |   private initialize = async () => {
 8 |     if (this.client) return;
 9 | 
10 |     this.client = new Client(
11 |       {
12 |         name: "cosmosdb-client",
13 |         version: "1.0.0"
14 |       },
15 |       {
16 |         capabilities: {
17 |           prompts: {},
18 |           resources: {},
19 |           tools: {}
20 |         }
21 |       }
22 |     );
23 | 
24 |     const transport = new SSEClientTransport(
25 |       new URL("/sse", "http://localhost:3001/"),
26 |       {
27 |         requestInit: {
28 |           headers: {
29 |             'Content-Type': 'text/event-stream',
30 |           }
31 |         }
32 |       }
33 |     );
34 | 
35 |     try {
36 |       await this.client.connect(transport);
37 |     } catch (e) {
38 |       console.error('Failed to connect to MCP server:', e);
39 |       this.client = null;
40 |     }
41 |   };
42 | 
43 |   getClient = async (): Promise<Client | null> => {
44 |     await this.initialize();
45 |     return this.client;
46 |   };
47 | 
48 |   static create = async (): Promise<MCPClient> => {
49 |     const instance = new MCPClient();
50 |     await instance.initialize();
51 |     return instance;
52 |   };
53 | }
54 | 
55 | export const createMCPClient = async () => {
56 |   const mcpClient = await MCPClient.create();
57 |   return mcpClient.getClient();
58 | };
```

--------------------------------------------------------------------------------
/nextjs/components/ui/avatar.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import * as React from 'react';
 4 | import * as AvatarPrimitive from '@radix-ui/react-avatar';
 5 | 
 6 | import { cn } from '@/lib/utils';
 7 | 
 8 | const Avatar = React.forwardRef<
 9 |   React.ElementRef<typeof AvatarPrimitive.Root>,
10 |   React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
11 | >(({ className, ...props }, ref) => (
12 |   <AvatarPrimitive.Root
13 |     ref={ref}
14 |     className={cn(
15 |       'relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full',
16 |       className
17 |     )}
18 |     {...props}
19 |   />
20 | ));
21 | Avatar.displayName = AvatarPrimitive.Root.displayName;
22 | 
23 | const AvatarImage = React.forwardRef<
24 |   React.ElementRef<typeof AvatarPrimitive.Image>,
25 |   React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
26 | >(({ className, ...props }, ref) => (
27 |   <AvatarPrimitive.Image
28 |     ref={ref}
29 |     className={cn('aspect-square h-full w-full', className)}
30 |     {...props}
31 |   />
32 | ));
33 | AvatarImage.displayName = AvatarPrimitive.Image.displayName;
34 | 
35 | const AvatarFallback = React.forwardRef<
36 |   React.ElementRef<typeof AvatarPrimitive.Fallback>,
37 |   React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
38 | >(({ className, ...props }, ref) => (
39 |   <AvatarPrimitive.Fallback
40 |     ref={ref}
41 |     className={cn(
42 |       'flex h-full w-full items-center justify-center rounded-full bg-muted',
43 |       className
44 |     )}
45 |     {...props}
46 |   />
47 | ));
48 | AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
49 | 
50 | export { Avatar, AvatarImage, AvatarFallback };
51 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/toggle.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import * as React from 'react';
 4 | import * as TogglePrimitive from '@radix-ui/react-toggle';
 5 | import { cva, type VariantProps } from 'class-variance-authority';
 6 | 
 7 | import { cn } from '@/lib/utils';
 8 | 
 9 | const toggleVariants = cva(
10 |   'inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground',
11 |   {
12 |     variants: {
13 |       variant: {
14 |         default: 'bg-transparent',
15 |         outline:
16 |           'border border-input bg-transparent hover:bg-accent hover:text-accent-foreground',
17 |       },
18 |       size: {
19 |         default: 'h-10 px-3',
20 |         sm: 'h-9 px-2.5',
21 |         lg: 'h-11 px-5',
22 |       },
23 |     },
24 |     defaultVariants: {
25 |       variant: 'default',
26 |       size: 'default',
27 |     },
28 |   }
29 | );
30 | 
31 | const Toggle = React.forwardRef<
32 |   React.ElementRef<typeof TogglePrimitive.Root>,
33 |   React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> &
34 |     VariantProps<typeof toggleVariants>
35 | >(({ className, variant, size, ...props }, ref) => (
36 |   <TogglePrimitive.Root
37 |     ref={ref}
38 |     className={cn(toggleVariants({ variant, size, className }))}
39 |     {...props}
40 |   />
41 | ));
42 | 
43 | Toggle.displayName = TogglePrimitive.Root.displayName;
44 | 
45 | export { Toggle, toggleVariants };
46 | 
```

--------------------------------------------------------------------------------
/populate/set_rbac.ps1:
--------------------------------------------------------------------------------

```
 1 | $SubscriptionId = "<subscription_id>"   # Azure subscription id
 2 | $AccountName = "<cosmosdb_account_name>"    # cosmos db account name
 3 | $ResourceGroupName = "rg-cosmosdb" # resource group name of the Cosmos DB account
 4 | $PrincipalId = "481510d9-3e2b-4582-a356-ffb8bca58b71"   # id of the virtual machine in Entra ID
 5 | 
 6 | # Assign the "Cosmos DB Built-in Data Reader" role to an identity
 7 | $parameters = @{
 8 |     ResourceGroupName = $ResourceGroupName
 9 |     AccountName = $AccountName
10 |     RoleDefinitionId = "/subscriptions/$SubscriptionId/resourceGroups/$ResourceGroupName/providers/Microsoft.DocumentDB/databaseAccounts/$AccountName/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001"
11 |     PrincipalId = $PrincipalId
12 |     Scope = "/subscriptions/$SubscriptionId/resourceGroups/$ResourceGroupName/providers/Microsoft.DocumentDB/databaseAccounts/$AccountName"
13 | }    
14 | New-AzCosmosDBSqlRoleAssignment @parameters
15 | 
16 | # Assign the "Cosmos DB Built-in Data Contributor" role to an identity
17 | $parameters = @{
18 |     ResourceGroupName = $ResourceGroupName
19 |     AccountName = $AccountName
20 |     RoleDefinitionId = "/subscriptions/$SubscriptionId/resourceGroups/$ResourceGroupName/providers/Microsoft.DocumentDB/databaseAccounts/$AccountName/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002"
21 |     PrincipalId = $PrincipalId
22 |     Scope = "/subscriptions/$SubscriptionId/resourceGroups/$ResourceGroupName/providers/Microsoft.DocumentDB/databaseAccounts/$AccountName"
23 | }    
24 | New-AzCosmosDBSqlRoleAssignment @parameters
```

--------------------------------------------------------------------------------
/nextjs/app/api/products/route.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { NextRequest, NextResponse } from 'next/server';
 2 | 
 3 | import { SqlQuerySpec } from '@azure/cosmos';
 4 | import { cosmosDBService } from '@/lib/cosmosdb';
 5 | 
 6 | export async function GET(request: NextRequest) {
 7 |   const startTime = Date.now();
 8 |   
 9 |   try {
10 |     // Get query parameters
11 |     const searchParams = request.nextUrl.searchParams;
12 |     const token = searchParams.get('token');
13 |     const ids = searchParams.get('ids');
14 |     
15 |     let result;
16 |     
17 |     if (ids) {
18 |       // If IDs are provided, fetch only those products
19 |       const idArray = ids.split(',');
20 |       const sqlQuerySpec: SqlQuerySpec = {
21 |         query: 'SELECT c.id, c.type, c.brand, c.name, c.description, c.price FROM c WHERE ARRAY_CONTAINS(@ids, c.id)',
22 |         parameters: [
23 |           {
24 |             name: '@ids',
25 |             value: idArray
26 |           }
27 |         ]
28 |       };
29 |       
30 |       const { resources: items } = await cosmosDBService.productsContainer.items
31 |         .query(sqlQuerySpec)
32 |         .fetchAll();
33 |       
34 |       const duration = Date.now() - startTime;
35 |       
36 |       result = {
37 |         data: items,
38 |         duration,
39 |         token
40 |       };
41 |     } else {
42 |       // Otherwise, fetch all products using the existing service method
43 |       result = await cosmosDBService.getProducts();     
44 |     }
45 |     
46 |     return NextResponse.json(result);
47 |     
48 |   } catch (error) {
49 |     console.error('Error fetching products:', error);
50 |     return NextResponse.json(
51 |       { error: 'Failed to fetch products' },
52 |       { status: 500 }
53 |     );
54 |   }
55 | }
```

--------------------------------------------------------------------------------
/nextjs/components/ui/radio-group.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import * as React from 'react';
 4 | import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
 5 | import { Circle } from 'lucide-react';
 6 | 
 7 | import { cn } from '@/lib/utils';
 8 | 
 9 | const RadioGroup = React.forwardRef<
10 |   React.ElementRef<typeof RadioGroupPrimitive.Root>,
11 |   React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
12 | >(({ className, ...props }, ref) => {
13 |   return (
14 |     <RadioGroupPrimitive.Root
15 |       className={cn('grid gap-2', className)}
16 |       {...props}
17 |       ref={ref}
18 |     />
19 |   );
20 | });
21 | RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
22 | 
23 | const RadioGroupItem = React.forwardRef<
24 |   React.ElementRef<typeof RadioGroupPrimitive.Item>,
25 |   React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
26 | >(({ className, ...props }, ref) => {
27 |   return (
28 |     <RadioGroupPrimitive.Item
29 |       ref={ref}
30 |       className={cn(
31 |         'aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
32 |         className
33 |       )}
34 |       {...props}
35 |     >
36 |       <RadioGroupPrimitive.Indicator className="flex items-center justify-center">
37 |         <Circle className="h-2.5 w-2.5 fill-current text-current" />
38 |       </RadioGroupPrimitive.Indicator>
39 |     </RadioGroupPrimitive.Item>
40 |   );
41 | });
42 | RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
43 | 
44 | export { RadioGroup, RadioGroupItem };
45 | 
```

--------------------------------------------------------------------------------
/nextjs/app/products/page.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | import { Button } from "@/components/ui/button";
 2 | import Image from "next/image";
 3 | import Products from "@/components/Products";
 4 | 
 5 | type Props = {
 6 |   searchParams: Promise<{
 7 |     ids?: string;
 8 |   }>;
 9 | };
10 | 
11 | export default async function ProductsPage({ searchParams }: Props) {
12 |   // Wait for searchParams to resolve
13 |   const params = await searchParams;
14 |   const productIds = params?.ids?.split(",").filter(Boolean);
15 | 
16 |   return (
17 |     <div className="min-h-screen bg-gray-50">
18 |       <div className="relative">
19 |         <div className="absolute inset-0">
20 |           <Image src="https://images.unsplash.com/photo-1551698618-1dfe5d97d256?ixlib=rb-1.2.1&auto=format&fit=crop&w=1950&q=80" alt="Winter mountain landscape" fill priority className="object-cover" />
21 |           <div className="absolute inset-0 bg-gray-900/40" />
22 |         </div>
23 |         <div className="relative max-w-7xl mx-auto px-4 py-32 sm:px-6 lg:px-8">
24 |           <h1 className="text-4xl font-bold tracking-tight text-white sm:text-5xl lg:text-6xl">Ready for a new adventure?</h1>
25 |           <p className="mt-6 text-xl text-white max-w-3xl">Start the season with the latest in clothing and equipment.</p>
26 |           <div className="mt-10">
27 |             <Button size="lg" className="bg-white text-gray-900 hover:bg-gray-100">
28 |               Shop Now
29 |             </Button>
30 |           </div>
31 |         </div>
32 |       </div>
33 | 
34 |       <div className="max-w-7xl mx-auto px-4 py-12 sm:px-6 lg:px-8">
35 |         <Products productIds={productIds} />
36 |       </div>
37 |     </div>
38 |   );
39 | }
40 | 
```

--------------------------------------------------------------------------------
/nextjs/app/api/chat/route.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { AzureOpenAI } from 'openai'
 2 | import { EMAIL } from '@/models/constants'
 3 | import { NextResponse } from 'next/server'
 4 | 
 5 | function validateEnvironmentVariables () {
 6 |   const required = ['AZURE_OPENAI_ENDPOINT', 'AZURE_OPENAI_API_KEY']
 7 | 
 8 |   for (const variable of required) {
 9 |     if (!process.env[variable]) {
10 |       throw new Error(`Missing required environment variable: ${variable}`)
11 |     }
12 |   }
13 | }
14 | 
15 | export async function POST (req: Request) {
16 |   try {
17 |     validateEnvironmentVariables()
18 |     const { message, conversationHistory, tools } = await req.json()
19 | 
20 |     const messages = [
21 |       {
22 |         role: 'system',
23 |         content:
24 |           'You are a helpful shopping assistant that helps customers find products and answers questions about them.'
25 |       },
26 |       ...conversationHistory.map((msg: any) => ({
27 |         role: msg.role,
28 |         content: msg.content
29 |       })),
30 |       { role: 'user', content: message }
31 |     ]
32 | 
33 |     const client = new AzureOpenAI({
34 |       endpoint: process.env.AZURE_OPENAI_ENDPOINT,
35 |       apiKey: process.env.AZURE_OPENAI_API_KEY!,
36 |       apiVersion: process.env.AZURE_OPENAI_API_VERSION!
37 |     })
38 | 
39 |     const response = await client.chat.completions.create({
40 |       messages: messages,
41 |       model: process.env.AZURE_OPENAI_CHAT_MODEL!,
42 |       tools: tools
43 |     })
44 | 
45 |     const content = JSON.stringify(response)
46 |     console.log('Chat API Response:', content)
47 | 
48 |     return NextResponse.json({ content })
49 |   } catch (error) {
50 |     console.error('Chat API Error:', error)
51 |     return NextResponse.json(
52 |       { error: 'Internal server error' },
53 |       { status: 500 }
54 |     )
55 |   }
56 | }
57 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/alert.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | import * as React from 'react';
 2 | import { cva, type VariantProps } from 'class-variance-authority';
 3 | 
 4 | import { cn } from '@/lib/utils';
 5 | 
 6 | const alertVariants = cva(
 7 |   'relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground',
 8 |   {
 9 |     variants: {
10 |       variant: {
11 |         default: 'bg-background text-foreground',
12 |         destructive:
13 |           'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive',
14 |       },
15 |     },
16 |     defaultVariants: {
17 |       variant: 'default',
18 |     },
19 |   }
20 | );
21 | 
22 | const Alert = React.forwardRef<
23 |   HTMLDivElement,
24 |   React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
25 | >(({ className, variant, ...props }, ref) => (
26 |   <div
27 |     ref={ref}
28 |     role="alert"
29 |     className={cn(alertVariants({ variant }), className)}
30 |     {...props}
31 |   />
32 | ));
33 | Alert.displayName = 'Alert';
34 | 
35 | const AlertTitle = React.forwardRef<
36 |   HTMLParagraphElement,
37 |   React.HTMLAttributes<HTMLHeadingElement>
38 | >(({ className, ...props }, ref) => (
39 |   <h5
40 |     ref={ref}
41 |     className={cn('mb-1 font-medium leading-none tracking-tight', className)}
42 |     {...props}
43 |   />
44 | ));
45 | AlertTitle.displayName = 'AlertTitle';
46 | 
47 | const AlertDescription = React.forwardRef<
48 |   HTMLParagraphElement,
49 |   React.HTMLAttributes<HTMLParagraphElement>
50 | >(({ className, ...props }, ref) => (
51 |   <div
52 |     ref={ref}
53 |     className={cn('text-sm [&_p]:leading-relaxed', className)}
54 |     {...props}
55 |   />
56 | ));
57 | AlertDescription.displayName = 'AlertDescription';
58 | 
59 | export { Alert, AlertTitle, AlertDescription };
60 | 
```

--------------------------------------------------------------------------------
/nextjs/app/api/blob-url/route.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { BlobServiceClient } from "@azure/storage-blob";
 2 | import { ClientSecretCredential } from "@azure/identity";
 3 | import { NextResponse } from "next/server";
 4 | 
 5 | export async function GET(request: Request) {
 6 |   const { searchParams } = new URL(request.url);
 7 |   const blobName = searchParams.get("blob");
 8 | 
 9 |   if (!blobName) {
10 |     return NextResponse.json({ error: "Blob name is required" }, { status: 400 });
11 |   }
12 | 
13 |   try {
14 |     const credential = new ClientSecretCredential(process.env.NEXT_PUBLIC_AZURE_TENANT_ID!, process.env.NEXT_PUBLIC_AZURE_CLIENT_ID!, process.env.NEXT_PUBLIC_AZURE_CLIENT_SECRET!);
15 | 
16 |     const blobServiceClient = new BlobServiceClient(`https://${process.env.NEXT_PUBLIC_AZURE_STORAGE_ACCOUNT_NAME}.blob.core.windows.net`, credential);
17 | 
18 |     const containerClient = blobServiceClient.getContainerClient(process.env.NEXT_PUBLIC_AZURE_STORAGE_CONTAINER_NAME!);
19 |     const blobClient = containerClient.getBlobClient(blobName);
20 | 
21 |     // Download blob content
22 |     const downloadResponse = await blobClient.download();
23 | 
24 |     const chunks: Uint8Array[] = [];
25 | 
26 |     for await (const chunk of downloadResponse.readableStreamBody as AsyncIterable<Uint8Array>) {
27 |       chunks.push(chunk);
28 |     }
29 | 
30 |     const buffer = Buffer.concat(chunks);
31 | 
32 |     const base64String = `data:image/webp;base64,${buffer.toString("base64")}`;
33 | 
34 |     return NextResponse.json({ url: base64String });
35 |   } catch (error) {
36 |     console.error("Error accessing blob:", JSON.stringify(error, null, 2));
37 |     return NextResponse.json(
38 |       {
39 |         error: "Failed to access blob",
40 |         details: error instanceof Error ? error.message : "Unknown error",
41 |       },
42 |       { status: 500 }
43 |     );
44 |   }
45 | }
46 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/scroll-area.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import * as React from 'react';
 4 | import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
 5 | 
 6 | import { cn } from '@/lib/utils';
 7 | 
 8 | const ScrollArea = React.forwardRef<
 9 |   React.ElementRef<typeof ScrollAreaPrimitive.Root>,
10 |   React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
11 | >(({ className, children, ...props }, ref) => (
12 |   <ScrollAreaPrimitive.Root
13 |     ref={ref}
14 |     className={cn('relative overflow-hidden', className)}
15 |     {...props}
16 |   >
17 |     <ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
18 |       {children}
19 |     </ScrollAreaPrimitive.Viewport>
20 |     <ScrollBar />
21 |     <ScrollAreaPrimitive.Corner />
22 |   </ScrollAreaPrimitive.Root>
23 | ));
24 | ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
25 | 
26 | const ScrollBar = React.forwardRef<
27 |   React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
28 |   React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
29 | >(({ className, orientation = 'vertical', ...props }, ref) => (
30 |   <ScrollAreaPrimitive.ScrollAreaScrollbar
31 |     ref={ref}
32 |     orientation={orientation}
33 |     className={cn(
34 |       'flex touch-none select-none transition-colors',
35 |       orientation === 'vertical' &&
36 |         'h-full w-2.5 border-l border-l-transparent p-[1px]',
37 |       orientation === 'horizontal' &&
38 |         'h-2.5 flex-col border-t border-t-transparent p-[1px]',
39 |       className
40 |     )}
41 |     {...props}
42 |   >
43 |     <ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
44 |   </ScrollAreaPrimitive.ScrollAreaScrollbar>
45 | ));
46 | ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
47 | 
48 | export { ScrollArea, ScrollBar };
49 | 
```

--------------------------------------------------------------------------------
/nextjs/app/api/cart/route.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { NextRequest, NextResponse } from 'next/server';
 2 | import { cosmosDBService } from '@/lib/cosmosdb';
 3 | 
 4 | export async function GET(request: NextRequest) {
 5 |   try {
 6 |     // Get the userName from query parameters
 7 |     const searchParams = request.nextUrl.searchParams;
 8 |     const userName = searchParams.get('userName');
 9 |     
10 |     if (!userName) {
11 |       return NextResponse.json(
12 |         { error: 'userName parameter is required' },
13 |         { status: 400 }
14 |       );
15 |     }
16 |     
17 |     // Load the cart from Cosmos DB
18 |     const result = await cosmosDBService.loadCart(userName);
19 |     
20 |     if (result.error) {
21 |       return NextResponse.json(
22 |         { error: result.error },
23 |         { status: result.statusCode }
24 |       );
25 |     }
26 |     
27 |     return NextResponse.json(result);
28 |     
29 |   } catch (error) {
30 |     console.error('Error loading cart:', error);
31 |     return NextResponse.json(
32 |       { error: 'Failed to load cart' },
33 |       { status: 500 }
34 |     );
35 |   }
36 | }
37 | 
38 | export async function POST(request: NextRequest) {
39 |   try {
40 |     // Get the cart data from the request body
41 |     const cart = await request.json();
42 |     
43 |     if (!cart || !cart.userName) {
44 |       return NextResponse.json(
45 |         { error: 'Invalid cart data. userName is required.' },
46 |         { status: 400 }
47 |       );
48 |     }
49 |     
50 |     // Store the cart in Cosmos DB
51 |     const result = await cosmosDBService.storeCart(cart);
52 |     
53 |     if (result.error) {
54 |       return NextResponse.json(
55 |         { error: result.error },
56 |         { status: result.statusCode }
57 |       );
58 |     }
59 |     
60 |     return NextResponse.json(result);
61 |     
62 |   } catch (error) {
63 |     console.error('Error storing cart:', error);
64 |     return NextResponse.json(
65 |       { error: 'Failed to store cart' },
66 |       { status: 500 }
67 |     );
68 |   }
69 | }
```

--------------------------------------------------------------------------------
/nextjs/components/ui/resizable.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import { GripVertical } from 'lucide-react';
 4 | import * as ResizablePrimitive from 'react-resizable-panels';
 5 | 
 6 | import { cn } from '@/lib/utils';
 7 | 
 8 | const ResizablePanelGroup = ({
 9 |   className,
10 |   ...props
11 | }: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) => (
12 |   <ResizablePrimitive.PanelGroup
13 |     className={cn(
14 |       'flex h-full w-full data-[panel-group-direction=vertical]:flex-col',
15 |       className
16 |     )}
17 |     {...props}
18 |   />
19 | );
20 | 
21 | const ResizablePanel = ResizablePrimitive.Panel;
22 | 
23 | const ResizableHandle = ({
24 |   withHandle,
25 |   className,
26 |   ...props
27 | }: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
28 |   withHandle?: boolean;
29 | }) => (
30 |   <ResizablePrimitive.PanelResizeHandle
31 |     className={cn(
32 |       'relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90',
33 |       className
34 |     )}
35 |     {...props}
36 |   >
37 |     {withHandle && (
38 |       <div className="z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border">
39 |         <GripVertical className="h-2.5 w-2.5" />
40 |       </div>
41 |     )}
42 |   </ResizablePrimitive.PanelResizeHandle>
43 | );
44 | 
45 | export { ResizablePanelGroup, ResizablePanel, ResizableHandle };
46 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/toggle-group.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import * as React from 'react';
 4 | import * as ToggleGroupPrimitive from '@radix-ui/react-toggle-group';
 5 | import { type VariantProps } from 'class-variance-authority';
 6 | 
 7 | import { cn } from '@/lib/utils';
 8 | import { toggleVariants } from '@/components/ui/toggle';
 9 | 
10 | const ToggleGroupContext = React.createContext<
11 |   VariantProps<typeof toggleVariants>
12 | >({
13 |   size: 'default',
14 |   variant: 'default',
15 | });
16 | 
17 | const ToggleGroup = React.forwardRef<
18 |   React.ElementRef<typeof ToggleGroupPrimitive.Root>,
19 |   React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> &
20 |     VariantProps<typeof toggleVariants>
21 | >(({ className, variant, size, children, ...props }, ref) => (
22 |   <ToggleGroupPrimitive.Root
23 |     ref={ref}
24 |     className={cn('flex items-center justify-center gap-1', className)}
25 |     {...props}
26 |   >
27 |     <ToggleGroupContext.Provider value={{ variant, size }}>
28 |       {children}
29 |     </ToggleGroupContext.Provider>
30 |   </ToggleGroupPrimitive.Root>
31 | ));
32 | 
33 | ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;
34 | 
35 | const ToggleGroupItem = React.forwardRef<
36 |   React.ElementRef<typeof ToggleGroupPrimitive.Item>,
37 |   React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
38 |     VariantProps<typeof toggleVariants>
39 | >(({ className, children, variant, size, ...props }, ref) => {
40 |   const context = React.useContext(ToggleGroupContext);
41 | 
42 |   return (
43 |     <ToggleGroupPrimitive.Item
44 |       ref={ref}
45 |       className={cn(
46 |         toggleVariants({
47 |           variant: context.variant || variant,
48 |           size: context.size || size,
49 |         }),
50 |         className
51 |       )}
52 |       {...props}
53 |     >
54 |       {children}
55 |     </ToggleGroupPrimitive.Item>
56 |   );
57 | });
58 | 
59 | ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;
60 | 
61 | export { ToggleGroup, ToggleGroupItem };
62 | 
```

--------------------------------------------------------------------------------
/nextjs/app/layout.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | import './globals.css';
 2 | 
 3 | import { Bot, Mountain, User } from 'lucide-react';
 4 | 
 5 | import AIAssistantDrawer from '@/components/AIAssistantDrawer';
 6 | import CartItemCount from '@/components/CartItemCount';
 7 | import { CartProvider } from '@/context/CartContext';
 8 | import { Inter } from 'next/font/google';
 9 | import Link from 'next/link';
10 | import type { Metadata } from 'next';
11 | 
12 | const inter = Inter({ subsets: ['latin'] });
13 | 
14 | export const metadata: Metadata = {
15 |   title: 'Northern Mountains',
16 |   description: 'Your adventure gear destination',
17 | };
18 | 
19 | export default function RootLayout({
20 |   children,
21 | }: {
22 |   children: React.ReactNode;
23 | }) {
24 |   return (
25 |     <html lang="en">
26 |       <body className={inter.className}>
27 |         <CartProvider>
28 |           <div className="flex flex-col min-h-screen">
29 |             <header className="border-b">
30 |               <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
31 |                 <div className="flex items-center justify-between">
32 |                   <Link href="/" className="flex items-center space-x-2">
33 |                     <Mountain className="h-8 w-8" />
34 |                     <span className="font-bold text-xl">Northern Mountains</span>
35 |                     <span className="font-bold text-xl text-red-500 pl-2">(East US 2)</span>
36 |                   </Link>
37 |                   <div className="flex items-center space-x-4">
38 |                     <AIAssistantDrawer />
39 |                     <Link href="/account" className="p-2 hover:bg-gray-100 rounded-full">
40 |                       <User className="h-6 w-6" />
41 |                     </Link>
42 |                     <CartItemCount />
43 |                   </div>
44 |                 </div>
45 |               </div>
46 |             </header>
47 |             <main className="flex-grow relative">{children}</main>
48 |           </div>
49 |         </CartProvider>
50 |       </body>
51 |     </html>
52 |   );
53 | }
```

--------------------------------------------------------------------------------
/mcp-server/src/cosmosdb.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { CosmosClient } from '@azure/cosmos'
 2 | import { DefaultAzureCredential } from '@azure/identity'
 3 | 
 4 | const sourceFile = 'src/cosmosdb.ts'
 5 | 
 6 | export function validateEnvironmentVariables () {
 7 |   const required = [
 8 |     'AZURE_COSMOSDB_NOSQL_ENDPOINT',
 9 |     'AZURE_COSMOSDB_NOSQL_DATABASE',
10 |     'AZURE_COSMOSDB_NOSQL_PRODUCTS_CONTAINER',
11 |     'AZURE_COSMOSDB_NOSQL_CARTS_CONTAINER'
12 |   ]
13 | 
14 |   for (const variable of required) {
15 |     if (!process.env[variable]) {
16 |       throw new Error(`Missing required environment variable: ${variable}`)
17 |     }
18 |   }
19 | }
20 | 
21 | export const initializeCosmosDB = () => {
22 |   const endpoint = process.env.AZURE_COSMOSDB_NOSQL_ENDPOINT as string
23 |   const databaseId = process.env.AZURE_COSMOSDB_NOSQL_DATABASE as string
24 |   const productsContainerId = process.env
25 |     .AZURE_COSMOSDB_NOSQL_PRODUCTS_CONTAINER as string
26 |   const cartsContainerId = process.env
27 |     .AZURE_COSMOSDB_NOSQL_CARTS_CONTAINER as string
28 |     const ordersContainerId = process.env
29 |     .AZURE_COSMOSDB_NOSQL_ORDERS_CONTAINER as string
30 | 
31 |   const credential = new DefaultAzureCredential()
32 | 
33 |   console.debug(
34 |     `[${sourceFile}::initializeCosmosDB] Cosmos DB endpoint: ${endpoint}`
35 |   )
36 |   console.debug(
37 |     `[${sourceFile}::initializeCosmosDB] Cosmos DB products container: ${productsContainerId}`
38 |   )
39 |   console.debug(
40 |     `[${sourceFile}::initializeCosmosDB] Cosmos DB carts container: ${cartsContainerId}`
41 |   )
42 |   console.debug(
43 |     `[${sourceFile}::initializeCosmosDB] Cosmos DB orders container: ${ordersContainerId}`
44 |   )
45 | 
46 |   const client = new CosmosClient({
47 |     endpoint: endpoint,
48 |     aadCredentials: credential
49 |   })
50 | 
51 |   const database = client.database(databaseId)
52 |   const productsContainer = database.container(productsContainerId)
53 |   const ordersContainer = database.container(ordersContainerId)
54 | 
55 |   return { client, database, productsContainer, ordersContainer }
56 | }
57 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/button.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | import * as React from 'react';
 2 | import { Slot } from '@radix-ui/react-slot';
 3 | import { cva, type VariantProps } from 'class-variance-authority';
 4 | 
 5 | import { cn } from '@/lib/utils';
 6 | 
 7 | const buttonVariants = cva(
 8 |   'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
 9 |   {
10 |     variants: {
11 |       variant: {
12 |         default: 'bg-primary text-primary-foreground hover:bg-primary/90',
13 |         destructive:
14 |           'bg-destructive text-destructive-foreground hover:bg-destructive/90',
15 |         outline:
16 |           'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
17 |         secondary:
18 |           'bg-secondary text-secondary-foreground hover:bg-secondary/80',
19 |         ghost: 'hover:bg-accent hover:text-accent-foreground',
20 |         link: 'text-primary underline-offset-4 hover:underline',
21 |       },
22 |       size: {
23 |         default: 'h-10 px-4 py-2',
24 |         sm: 'h-9 rounded-md px-3',
25 |         lg: 'h-11 rounded-md px-8',
26 |         icon: 'h-10 w-10',
27 |       },
28 |     },
29 |     defaultVariants: {
30 |       variant: 'default',
31 |       size: 'default',
32 |     },
33 |   }
34 | );
35 | 
36 | export interface ButtonProps
37 |   extends React.ButtonHTMLAttributes<HTMLButtonElement>,
38 |     VariantProps<typeof buttonVariants> {
39 |   asChild?: boolean;
40 | }
41 | 
42 | const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
43 |   ({ className, variant, size, asChild = false, ...props }, ref) => {
44 |     const Comp = asChild ? Slot : 'button';
45 |     return (
46 |       <Comp
47 |         className={cn(buttonVariants({ variant, size, className }))}
48 |         ref={ref}
49 |         {...props}
50 |       />
51 |     );
52 |   }
53 | );
54 | Button.displayName = 'Button';
55 | 
56 | export { Button, buttonVariants };
57 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/card.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | import * as React from 'react';
 2 | 
 3 | import { cn } from '@/lib/utils';
 4 | 
 5 | const Card = React.forwardRef<
 6 |   HTMLDivElement,
 7 |   React.HTMLAttributes<HTMLDivElement>
 8 | >(({ className, ...props }, ref) => (
 9 |   <div
10 |     ref={ref}
11 |     className={cn(
12 |       'rounded-lg border bg-card text-card-foreground shadow-sm',
13 |       className
14 |     )}
15 |     {...props}
16 |   />
17 | ));
18 | Card.displayName = 'Card';
19 | 
20 | const CardHeader = React.forwardRef<
21 |   HTMLDivElement,
22 |   React.HTMLAttributes<HTMLDivElement>
23 | >(({ className, ...props }, ref) => (
24 |   <div
25 |     ref={ref}
26 |     className={cn('flex flex-col space-y-1.5 p-6', className)}
27 |     {...props}
28 |   />
29 | ));
30 | CardHeader.displayName = 'CardHeader';
31 | 
32 | const CardTitle = React.forwardRef<
33 |   HTMLParagraphElement,
34 |   React.HTMLAttributes<HTMLHeadingElement>
35 | >(({ className, ...props }, ref) => (
36 |   <h3
37 |     ref={ref}
38 |     className={cn(
39 |       'text-2xl font-semibold leading-none tracking-tight',
40 |       className
41 |     )}
42 |     {...props}
43 |   />
44 | ));
45 | CardTitle.displayName = 'CardTitle';
46 | 
47 | const CardDescription = React.forwardRef<
48 |   HTMLParagraphElement,
49 |   React.HTMLAttributes<HTMLParagraphElement>
50 | >(({ className, ...props }, ref) => (
51 |   <p
52 |     ref={ref}
53 |     className={cn('text-sm text-muted-foreground', className)}
54 |     {...props}
55 |   />
56 | ));
57 | CardDescription.displayName = 'CardDescription';
58 | 
59 | const CardContent = React.forwardRef<
60 |   HTMLDivElement,
61 |   React.HTMLAttributes<HTMLDivElement>
62 | >(({ className, ...props }, ref) => (
63 |   <div ref={ref} className={cn('p-6 pt-0', className)} {...props} />
64 | ));
65 | CardContent.displayName = 'CardContent';
66 | 
67 | const CardFooter = React.forwardRef<
68 |   HTMLDivElement,
69 |   React.HTMLAttributes<HTMLDivElement>
70 | >(({ className, ...props }, ref) => (
71 |   <div
72 |     ref={ref}
73 |     className={cn('flex items-center p-6 pt-0', className)}
74 |     {...props}
75 |   />
76 | ));
77 | CardFooter.displayName = 'CardFooter';
78 | 
79 | export {
80 |   Card,
81 |   CardHeader,
82 |   CardFooter,
83 |   CardTitle,
84 |   CardDescription,
85 |   CardContent,
86 | };
87 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/tabs.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import * as React from 'react';
 4 | import * as TabsPrimitive from '@radix-ui/react-tabs';
 5 | 
 6 | import { cn } from '@/lib/utils';
 7 | 
 8 | const Tabs = TabsPrimitive.Root;
 9 | 
10 | const TabsList = React.forwardRef<
11 |   React.ElementRef<typeof TabsPrimitive.List>,
12 |   React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
13 | >(({ className, ...props }, ref) => (
14 |   <TabsPrimitive.List
15 |     ref={ref}
16 |     className={cn(
17 |       'inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground',
18 |       className
19 |     )}
20 |     {...props}
21 |   />
22 | ));
23 | TabsList.displayName = TabsPrimitive.List.displayName;
24 | 
25 | const TabsTrigger = React.forwardRef<
26 |   React.ElementRef<typeof TabsPrimitive.Trigger>,
27 |   React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
28 | >(({ className, ...props }, ref) => (
29 |   <TabsPrimitive.Trigger
30 |     ref={ref}
31 |     className={cn(
32 |       'inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm',
33 |       className
34 |     )}
35 |     {...props}
36 |   />
37 | ));
38 | TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
39 | 
40 | const TabsContent = React.forwardRef<
41 |   React.ElementRef<typeof TabsPrimitive.Content>,
42 |   React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
43 | >(({ className, ...props }, ref) => (
44 |   <TabsPrimitive.Content
45 |     ref={ref}
46 |     className={cn(
47 |       'mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
48 |       className
49 |     )}
50 |     {...props}
51 |   />
52 | ));
53 | TabsContent.displayName = TabsPrimitive.Content.displayName;
54 | 
55 | export { Tabs, TabsList, TabsTrigger, TabsContent };
56 | 
```

--------------------------------------------------------------------------------
/nextjs/app/globals.css:
--------------------------------------------------------------------------------

```css
 1 | @tailwind base;
 2 | @tailwind components;
 3 | @tailwind utilities;
 4 | 
 5 | :root {
 6 |   --foreground-rgb: 0, 0, 0;
 7 |   --background-start-rgb: 214, 219, 220;
 8 |   --background-end-rgb: 255, 255, 255;
 9 | }
10 | 
11 | @media (prefers-color-scheme: dark) {
12 |   :root {
13 |     --foreground-rgb: 255, 255, 255;
14 |     --background-start-rgb: 0, 0, 0;
15 |     --background-end-rgb: 0, 0, 0;
16 |   }
17 | }
18 | 
19 | @layer base {
20 |   :root {
21 |     --background: 0 0% 100%;
22 |     --foreground: 0 0% 3.9%;
23 |     --card: 0 0% 100%;
24 |     --card-foreground: 0 0% 3.9%;
25 |     --popover: 0 0% 100%;
26 |     --popover-foreground: 0 0% 3.9%;
27 |     --primary: 0 0% 9%;
28 |     --primary-foreground: 0 0% 98%;
29 |     --secondary: 0 0% 96.1%;
30 |     --secondary-foreground: 0 0% 9%;
31 |     --muted: 0 0% 96.1%;
32 |     --muted-foreground: 0 0% 45.1%;
33 |     --accent: 0 0% 96.1%;
34 |     --accent-foreground: 0 0% 9%;
35 |     --destructive: 0 84.2% 60.2%;
36 |     --destructive-foreground: 0 0% 98%;
37 |     --border: 0 0% 89.8%;
38 |     --input: 0 0% 89.8%;
39 |     --ring: 0 0% 3.9%;
40 |     --chart-1: 12 76% 61%;
41 |     --chart-2: 173 58% 39%;
42 |     --chart-3: 197 37% 24%;
43 |     --chart-4: 43 74% 66%;
44 |     --chart-5: 27 87% 67%;
45 |     --radius: 0.5rem;
46 |   }
47 |   .dark {
48 |     --background: 0 0% 3.9%;
49 |     --foreground: 0 0% 98%;
50 |     --card: 0 0% 3.9%;
51 |     --card-foreground: 0 0% 98%;
52 |     --popover: 0 0% 3.9%;
53 |     --popover-foreground: 0 0% 98%;
54 |     --primary: 0 0% 98%;
55 |     --primary-foreground: 0 0% 9%;
56 |     --secondary: 0 0% 14.9%;
57 |     --secondary-foreground: 0 0% 98%;
58 |     --muted: 0 0% 14.9%;
59 |     --muted-foreground: 0 0% 63.9%;
60 |     --accent: 0 0% 14.9%;
61 |     --accent-foreground: 0 0% 98%;
62 |     --destructive: 0 62.8% 30.6%;
63 |     --destructive-foreground: 0 0% 98%;
64 |     --border: 0 0% 14.9%;
65 |     --input: 0 0% 14.9%;
66 |     --ring: 0 0% 83.1%;
67 |     --chart-1: 220 70% 50%;
68 |     --chart-2: 160 60% 45%;
69 |     --chart-3: 30 80% 55%;
70 |     --chart-4: 280 65% 60%;
71 |     --chart-5: 340 75% 55%;
72 |   }
73 | }
74 | 
75 | @layer base {
76 |   * {
77 |     @apply border-border;
78 |   }
79 |   body {
80 |     @apply bg-background text-foreground;
81 |   }
82 | }
83 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/accordion.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import * as React from 'react';
 4 | import * as AccordionPrimitive from '@radix-ui/react-accordion';
 5 | import { ChevronDown } from 'lucide-react';
 6 | 
 7 | import { cn } from '@/lib/utils';
 8 | 
 9 | const Accordion = AccordionPrimitive.Root;
10 | 
11 | const AccordionItem = React.forwardRef<
12 |   React.ElementRef<typeof AccordionPrimitive.Item>,
13 |   React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
14 | >(({ className, ...props }, ref) => (
15 |   <AccordionPrimitive.Item
16 |     ref={ref}
17 |     className={cn('border-b', className)}
18 |     {...props}
19 |   />
20 | ));
21 | AccordionItem.displayName = 'AccordionItem';
22 | 
23 | const AccordionTrigger = React.forwardRef<
24 |   React.ElementRef<typeof AccordionPrimitive.Trigger>,
25 |   React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
26 | >(({ className, children, ...props }, ref) => (
27 |   <AccordionPrimitive.Header className="flex">
28 |     <AccordionPrimitive.Trigger
29 |       ref={ref}
30 |       className={cn(
31 |         'flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180',
32 |         className
33 |       )}
34 |       {...props}
35 |     >
36 |       {children}
37 |       <ChevronDown className="h-4 w-4 shrink-0 transition-transform duration-200" />
38 |     </AccordionPrimitive.Trigger>
39 |   </AccordionPrimitive.Header>
40 | ));
41 | AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
42 | 
43 | const AccordionContent = React.forwardRef<
44 |   React.ElementRef<typeof AccordionPrimitive.Content>,
45 |   React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
46 | >(({ className, children, ...props }, ref) => (
47 |   <AccordionPrimitive.Content
48 |     ref={ref}
49 |     className="overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
50 |     {...props}
51 |   >
52 |     <div className={cn('pb-4 pt-0', className)}>{children}</div>
53 |   </AccordionPrimitive.Content>
54 | ));
55 | 
56 | AccordionContent.displayName = AccordionPrimitive.Content.displayName;
57 | 
58 | export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
59 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/input-otp.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import * as React from 'react';
 4 | import { OTPInput, OTPInputContext } from 'input-otp';
 5 | import { Dot } from 'lucide-react';
 6 | 
 7 | import { cn } from '@/lib/utils';
 8 | 
 9 | const InputOTP = React.forwardRef<
10 |   React.ElementRef<typeof OTPInput>,
11 |   React.ComponentPropsWithoutRef<typeof OTPInput>
12 | >(({ className, containerClassName, ...props }, ref) => (
13 |   <OTPInput
14 |     ref={ref}
15 |     containerClassName={cn(
16 |       'flex items-center gap-2 has-[:disabled]:opacity-50',
17 |       containerClassName
18 |     )}
19 |     className={cn('disabled:cursor-not-allowed', className)}
20 |     {...props}
21 |   />
22 | ));
23 | InputOTP.displayName = 'InputOTP';
24 | 
25 | const InputOTPGroup = React.forwardRef<
26 |   React.ElementRef<'div'>,
27 |   React.ComponentPropsWithoutRef<'div'>
28 | >(({ className, ...props }, ref) => (
29 |   <div ref={ref} className={cn('flex items-center', className)} {...props} />
30 | ));
31 | InputOTPGroup.displayName = 'InputOTPGroup';
32 | 
33 | const InputOTPSlot = React.forwardRef<
34 |   React.ElementRef<'div'>,
35 |   React.ComponentPropsWithoutRef<'div'> & { index: number }
36 | >(({ index, className, ...props }, ref) => {
37 |   const inputOTPContext = React.useContext(OTPInputContext);
38 |   const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index];
39 | 
40 |   return (
41 |     <div
42 |       ref={ref}
43 |       className={cn(
44 |         'relative flex h-10 w-10 items-center justify-center border-y border-r border-input text-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md',
45 |         isActive && 'z-10 ring-2 ring-ring ring-offset-background',
46 |         className
47 |       )}
48 |       {...props}
49 |     >
50 |       {char}
51 |       {hasFakeCaret && (
52 |         <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
53 |           <div className="h-4 w-px animate-caret-blink bg-foreground duration-1000" />
54 |         </div>
55 |       )}
56 |     </div>
57 |   );
58 | });
59 | InputOTPSlot.displayName = 'InputOTPSlot';
60 | 
61 | const InputOTPSeparator = React.forwardRef<
62 |   React.ElementRef<'div'>,
63 |   React.ComponentPropsWithoutRef<'div'>
64 | >(({ ...props }, ref) => (
65 |   <div ref={ref} role="separator" {...props}>
66 |     <Dot />
67 |   </div>
68 | ));
69 | InputOTPSeparator.displayName = 'InputOTPSeparator';
70 | 
71 | export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };
72 | 
```

--------------------------------------------------------------------------------
/nextjs/tailwind.config.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import type { Config } from 'tailwindcss';
 2 | 
 3 | const config: Config = {
 4 |   darkMode: ['class'],
 5 |   content: [
 6 |     './pages/**/*.{js,ts,jsx,tsx,mdx}',
 7 |     './components/**/*.{js,ts,jsx,tsx,mdx}',
 8 |     './app/**/*.{js,ts,jsx,tsx,mdx}',
 9 |   ],
10 |   theme: {
11 |     extend: {
12 |       backgroundImage: {
13 |         'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
14 |         'gradient-conic':
15 |           'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
16 |       },
17 |       borderRadius: {
18 |         lg: 'var(--radius)',
19 |         md: 'calc(var(--radius) - 2px)',
20 |         sm: 'calc(var(--radius) - 4px)',
21 |       },
22 |       colors: {
23 |         background: 'hsl(var(--background))',
24 |         foreground: 'hsl(var(--foreground))',
25 |         card: {
26 |           DEFAULT: 'hsl(var(--card))',
27 |           foreground: 'hsl(var(--card-foreground))',
28 |         },
29 |         popover: {
30 |           DEFAULT: 'hsl(var(--popover))',
31 |           foreground: 'hsl(var(--popover-foreground))',
32 |         },
33 |         primary: {
34 |           DEFAULT: 'hsl(var(--primary))',
35 |           foreground: 'hsl(var(--primary-foreground))',
36 |         },
37 |         secondary: {
38 |           DEFAULT: 'hsl(var(--secondary))',
39 |           foreground: 'hsl(var(--secondary-foreground))',
40 |         },
41 |         muted: {
42 |           DEFAULT: 'hsl(var(--muted))',
43 |           foreground: 'hsl(var(--muted-foreground))',
44 |         },
45 |         accent: {
46 |           DEFAULT: 'hsl(var(--accent))',
47 |           foreground: 'hsl(var(--accent-foreground))',
48 |         },
49 |         destructive: {
50 |           DEFAULT: 'hsl(var(--destructive))',
51 |           foreground: 'hsl(var(--destructive-foreground))',
52 |         },
53 |         border: 'hsl(var(--border))',
54 |         input: 'hsl(var(--input))',
55 |         ring: 'hsl(var(--ring))',
56 |         chart: {
57 |           '1': 'hsl(var(--chart-1))',
58 |           '2': 'hsl(var(--chart-2))',
59 |           '3': 'hsl(var(--chart-3))',
60 |           '4': 'hsl(var(--chart-4))',
61 |           '5': 'hsl(var(--chart-5))',
62 |         },
63 |       },
64 |       keyframes: {
65 |         'accordion-down': {
66 |           from: {
67 |             height: '0',
68 |           },
69 |           to: {
70 |             height: 'var(--radix-accordion-content-height)',
71 |           },
72 |         },
73 |         'accordion-up': {
74 |           from: {
75 |             height: 'var(--radix-accordion-content-height)',
76 |           },
77 |           to: {
78 |             height: '0',
79 |           },
80 |         },
81 |       },
82 |       animation: {
83 |         'accordion-down': 'accordion-down 0.2s ease-out',
84 |         'accordion-up': 'accordion-up 0.2s ease-out',
85 |       },
86 |     },
87 |   },
88 |   plugins: [require('tailwindcss-animate')],
89 | };
90 | export default config;
91 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/calendar.tsx:
--------------------------------------------------------------------------------

```typescript
 1 | 'use client';
 2 | 
 3 | import * as React from 'react';
 4 | import { ChevronLeft, ChevronRight } from 'lucide-react';
 5 | import { DayPicker } from 'react-day-picker';
 6 | 
 7 | import { cn } from '@/lib/utils';
 8 | import { buttonVariants } from '@/components/ui/button';
 9 | 
10 | export type CalendarProps = React.ComponentProps<typeof DayPicker>;
11 | 
12 | function Calendar({
13 |   className,
14 |   classNames,
15 |   showOutsideDays = true,
16 |   ...props
17 | }: CalendarProps) {
18 |   return (
19 |     <DayPicker
20 |       showOutsideDays={showOutsideDays}
21 |       className={cn('p-3', className)}
22 |       classNames={{
23 |         months: 'flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0',
24 |         month: 'space-y-4',
25 |         caption: 'flex justify-center pt-1 relative items-center',
26 |         caption_label: 'text-sm font-medium',
27 |         nav: 'space-x-1 flex items-center',
28 |         nav_button: cn(
29 |           buttonVariants({ variant: 'outline' }),
30 |           'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100'
31 |         ),
32 |         nav_button_previous: 'absolute left-1',
33 |         nav_button_next: 'absolute right-1',
34 |         table: 'w-full border-collapse space-y-1',
35 |         head_row: 'flex',
36 |         head_cell:
37 |           'text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]',
38 |         row: 'flex w-full mt-2',
39 |         cell: 'h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20',
40 |         day: cn(
41 |           buttonVariants({ variant: 'ghost' }),
42 |           'h-9 w-9 p-0 font-normal aria-selected:opacity-100'
43 |         ),
44 |         day_range_end: 'day-range-end',
45 |         day_selected:
46 |           'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground',
47 |         day_today: 'bg-accent text-accent-foreground',
48 |         day_outside:
49 |           'day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30',
50 |         day_disabled: 'text-muted-foreground opacity-50',
51 |         day_range_middle:
52 |           'aria-selected:bg-accent aria-selected:text-accent-foreground',
53 |         day_hidden: 'invisible',
54 |         ...classNames,
55 |       }}
56 |       components={{
57 |         IconLeft: ({ ...props }) => <ChevronLeft className="h-4 w-4" />,
58 |         IconRight: ({ ...props }) => <ChevronRight className="h-4 w-4" />,
59 |       }}
60 |       {...props}
61 |     />
62 |   );
63 | }
64 | Calendar.displayName = 'Calendar';
65 | 
66 | export { Calendar };
67 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/breadcrumb.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | import * as React from 'react';
  2 | import { Slot } from '@radix-ui/react-slot';
  3 | import { ChevronRight, MoreHorizontal } from 'lucide-react';
  4 | 
  5 | import { cn } from '@/lib/utils';
  6 | 
  7 | const Breadcrumb = React.forwardRef<
  8 |   HTMLElement,
  9 |   React.ComponentPropsWithoutRef<'nav'> & {
 10 |     separator?: React.ReactNode;
 11 |   }
 12 | >(({ ...props }, ref) => <nav ref={ref} aria-label="breadcrumb" {...props} />);
 13 | Breadcrumb.displayName = 'Breadcrumb';
 14 | 
 15 | const BreadcrumbList = React.forwardRef<
 16 |   HTMLOListElement,
 17 |   React.ComponentPropsWithoutRef<'ol'>
 18 | >(({ className, ...props }, ref) => (
 19 |   <ol
 20 |     ref={ref}
 21 |     className={cn(
 22 |       'flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5',
 23 |       className
 24 |     )}
 25 |     {...props}
 26 |   />
 27 | ));
 28 | BreadcrumbList.displayName = 'BreadcrumbList';
 29 | 
 30 | const BreadcrumbItem = React.forwardRef<
 31 |   HTMLLIElement,
 32 |   React.ComponentPropsWithoutRef<'li'>
 33 | >(({ className, ...props }, ref) => (
 34 |   <li
 35 |     ref={ref}
 36 |     className={cn('inline-flex items-center gap-1.5', className)}
 37 |     {...props}
 38 |   />
 39 | ));
 40 | BreadcrumbItem.displayName = 'BreadcrumbItem';
 41 | 
 42 | const BreadcrumbLink = React.forwardRef<
 43 |   HTMLAnchorElement,
 44 |   React.ComponentPropsWithoutRef<'a'> & {
 45 |     asChild?: boolean;
 46 |   }
 47 | >(({ asChild, className, ...props }, ref) => {
 48 |   const Comp = asChild ? Slot : 'a';
 49 | 
 50 |   return (
 51 |     <Comp
 52 |       ref={ref}
 53 |       className={cn('transition-colors hover:text-foreground', className)}
 54 |       {...props}
 55 |     />
 56 |   );
 57 | });
 58 | BreadcrumbLink.displayName = 'BreadcrumbLink';
 59 | 
 60 | const BreadcrumbPage = React.forwardRef<
 61 |   HTMLSpanElement,
 62 |   React.ComponentPropsWithoutRef<'span'>
 63 | >(({ className, ...props }, ref) => (
 64 |   <span
 65 |     ref={ref}
 66 |     role="link"
 67 |     aria-disabled="true"
 68 |     aria-current="page"
 69 |     className={cn('font-normal text-foreground', className)}
 70 |     {...props}
 71 |   />
 72 | ));
 73 | BreadcrumbPage.displayName = 'BreadcrumbPage';
 74 | 
 75 | const BreadcrumbSeparator = ({
 76 |   children,
 77 |   className,
 78 |   ...props
 79 | }: React.ComponentProps<'li'>) => (
 80 |   <li
 81 |     role="presentation"
 82 |     aria-hidden="true"
 83 |     className={cn('[&>svg]:size-3.5', className)}
 84 |     {...props}
 85 |   >
 86 |     {children ?? <ChevronRight />}
 87 |   </li>
 88 | );
 89 | BreadcrumbSeparator.displayName = 'BreadcrumbSeparator';
 90 | 
 91 | const BreadcrumbEllipsis = ({
 92 |   className,
 93 |   ...props
 94 | }: React.ComponentProps<'span'>) => (
 95 |   <span
 96 |     role="presentation"
 97 |     aria-hidden="true"
 98 |     className={cn('flex h-9 w-9 items-center justify-center', className)}
 99 |     {...props}
100 |   >
101 |     <MoreHorizontal className="h-4 w-4" />
102 |     <span className="sr-only">More</span>
103 |   </span>
104 | );
105 | BreadcrumbEllipsis.displayName = 'BreadcrumbElipssis';
106 | 
107 | export {
108 |   Breadcrumb,
109 |   BreadcrumbList,
110 |   BreadcrumbItem,
111 |   BreadcrumbLink,
112 |   BreadcrumbPage,
113 |   BreadcrumbSeparator,
114 |   BreadcrumbEllipsis,
115 | };
116 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/pagination.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | import * as React from 'react';
  2 | import { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react';
  3 | 
  4 | import { cn } from '@/lib/utils';
  5 | import { ButtonProps, buttonVariants } from '@/components/ui/button';
  6 | 
  7 | const Pagination = ({ className, ...props }: React.ComponentProps<'nav'>) => (
  8 |   <nav
  9 |     role="navigation"
 10 |     aria-label="pagination"
 11 |     className={cn('mx-auto flex w-full justify-center', className)}
 12 |     {...props}
 13 |   />
 14 | );
 15 | Pagination.displayName = 'Pagination';
 16 | 
 17 | const PaginationContent = React.forwardRef<
 18 |   HTMLUListElement,
 19 |   React.ComponentProps<'ul'>
 20 | >(({ className, ...props }, ref) => (
 21 |   <ul
 22 |     ref={ref}
 23 |     className={cn('flex flex-row items-center gap-1', className)}
 24 |     {...props}
 25 |   />
 26 | ));
 27 | PaginationContent.displayName = 'PaginationContent';
 28 | 
 29 | const PaginationItem = React.forwardRef<
 30 |   HTMLLIElement,
 31 |   React.ComponentProps<'li'>
 32 | >(({ className, ...props }, ref) => (
 33 |   <li ref={ref} className={cn('', className)} {...props} />
 34 | ));
 35 | PaginationItem.displayName = 'PaginationItem';
 36 | 
 37 | type PaginationLinkProps = {
 38 |   isActive?: boolean;
 39 | } & Pick<ButtonProps, 'size'> &
 40 |   React.ComponentProps<'a'>;
 41 | 
 42 | const PaginationLink = ({
 43 |   className,
 44 |   isActive,
 45 |   size = 'icon',
 46 |   ...props
 47 | }: PaginationLinkProps) => (
 48 |   <a
 49 |     aria-current={isActive ? 'page' : undefined}
 50 |     className={cn(
 51 |       buttonVariants({
 52 |         variant: isActive ? 'outline' : 'ghost',
 53 |         size,
 54 |       }),
 55 |       className
 56 |     )}
 57 |     {...props}
 58 |   />
 59 | );
 60 | PaginationLink.displayName = 'PaginationLink';
 61 | 
 62 | const PaginationPrevious = ({
 63 |   className,
 64 |   ...props
 65 | }: React.ComponentProps<typeof PaginationLink>) => (
 66 |   <PaginationLink
 67 |     aria-label="Go to previous page"
 68 |     size="default"
 69 |     className={cn('gap-1 pl-2.5', className)}
 70 |     {...props}
 71 |   >
 72 |     <ChevronLeft className="h-4 w-4" />
 73 |     <span>Previous</span>
 74 |   </PaginationLink>
 75 | );
 76 | PaginationPrevious.displayName = 'PaginationPrevious';
 77 | 
 78 | const PaginationNext = ({
 79 |   className,
 80 |   ...props
 81 | }: React.ComponentProps<typeof PaginationLink>) => (
 82 |   <PaginationLink
 83 |     aria-label="Go to next page"
 84 |     size="default"
 85 |     className={cn('gap-1 pr-2.5', className)}
 86 |     {...props}
 87 |   >
 88 |     <span>Next</span>
 89 |     <ChevronRight className="h-4 w-4" />
 90 |   </PaginationLink>
 91 | );
 92 | PaginationNext.displayName = 'PaginationNext';
 93 | 
 94 | const PaginationEllipsis = ({
 95 |   className,
 96 |   ...props
 97 | }: React.ComponentProps<'span'>) => (
 98 |   <span
 99 |     aria-hidden
100 |     className={cn('flex h-9 w-9 items-center justify-center', className)}
101 |     {...props}
102 |   >
103 |     <MoreHorizontal className="h-4 w-4" />
104 |     <span className="sr-only">More pages</span>
105 |   </span>
106 | );
107 | PaginationEllipsis.displayName = 'PaginationEllipsis';
108 | 
109 | export {
110 |   Pagination,
111 |   PaginationContent,
112 |   PaginationEllipsis,
113 |   PaginationItem,
114 |   PaginationLink,
115 |   PaginationNext,
116 |   PaginationPrevious,
117 | };
118 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/table.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | import * as React from 'react';
  2 | 
  3 | import { cn } from '@/lib/utils';
  4 | 
  5 | const Table = React.forwardRef<
  6 |   HTMLTableElement,
  7 |   React.HTMLAttributes<HTMLTableElement>
  8 | >(({ className, ...props }, ref) => (
  9 |   <div className="relative w-full overflow-auto">
 10 |     <table
 11 |       ref={ref}
 12 |       className={cn('w-full caption-bottom text-sm', className)}
 13 |       {...props}
 14 |     />
 15 |   </div>
 16 | ));
 17 | Table.displayName = 'Table';
 18 | 
 19 | const TableHeader = React.forwardRef<
 20 |   HTMLTableSectionElement,
 21 |   React.HTMLAttributes<HTMLTableSectionElement>
 22 | >(({ className, ...props }, ref) => (
 23 |   <thead ref={ref} className={cn('[&_tr]:border-b', className)} {...props} />
 24 | ));
 25 | TableHeader.displayName = 'TableHeader';
 26 | 
 27 | const TableBody = React.forwardRef<
 28 |   HTMLTableSectionElement,
 29 |   React.HTMLAttributes<HTMLTableSectionElement>
 30 | >(({ className, ...props }, ref) => (
 31 |   <tbody
 32 |     ref={ref}
 33 |     className={cn('[&_tr:last-child]:border-0', className)}
 34 |     {...props}
 35 |   />
 36 | ));
 37 | TableBody.displayName = 'TableBody';
 38 | 
 39 | const TableFooter = React.forwardRef<
 40 |   HTMLTableSectionElement,
 41 |   React.HTMLAttributes<HTMLTableSectionElement>
 42 | >(({ className, ...props }, ref) => (
 43 |   <tfoot
 44 |     ref={ref}
 45 |     className={cn(
 46 |       'border-t bg-muted/50 font-medium [&>tr]:last:border-b-0',
 47 |       className
 48 |     )}
 49 |     {...props}
 50 |   />
 51 | ));
 52 | TableFooter.displayName = 'TableFooter';
 53 | 
 54 | const TableRow = React.forwardRef<
 55 |   HTMLTableRowElement,
 56 |   React.HTMLAttributes<HTMLTableRowElement>
 57 | >(({ className, ...props }, ref) => (
 58 |   <tr
 59 |     ref={ref}
 60 |     className={cn(
 61 |       'border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',
 62 |       className
 63 |     )}
 64 |     {...props}
 65 |   />
 66 | ));
 67 | TableRow.displayName = 'TableRow';
 68 | 
 69 | const TableHead = React.forwardRef<
 70 |   HTMLTableCellElement,
 71 |   React.ThHTMLAttributes<HTMLTableCellElement>
 72 | >(({ className, ...props }, ref) => (
 73 |   <th
 74 |     ref={ref}
 75 |     className={cn(
 76 |       'h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0',
 77 |       className
 78 |     )}
 79 |     {...props}
 80 |   />
 81 | ));
 82 | TableHead.displayName = 'TableHead';
 83 | 
 84 | const TableCell = React.forwardRef<
 85 |   HTMLTableCellElement,
 86 |   React.TdHTMLAttributes<HTMLTableCellElement>
 87 | >(({ className, ...props }, ref) => (
 88 |   <td
 89 |     ref={ref}
 90 |     className={cn('p-4 align-middle [&:has([role=checkbox])]:pr-0', className)}
 91 |     {...props}
 92 |   />
 93 | ));
 94 | TableCell.displayName = 'TableCell';
 95 | 
 96 | const TableCaption = React.forwardRef<
 97 |   HTMLTableCaptionElement,
 98 |   React.HTMLAttributes<HTMLTableCaptionElement>
 99 | >(({ className, ...props }, ref) => (
100 |   <caption
101 |     ref={ref}
102 |     className={cn('mt-4 text-sm text-muted-foreground', className)}
103 |     {...props}
104 |   />
105 | ));
106 | TableCaption.displayName = 'TableCaption';
107 | 
108 | export {
109 |   Table,
110 |   TableHeader,
111 |   TableBody,
112 |   TableFooter,
113 |   TableHead,
114 |   TableRow,
115 |   TableCell,
116 |   TableCaption,
117 | };
118 | 
```

--------------------------------------------------------------------------------
/nextjs/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "nextjs",
 3 |   "version": "0.1.0",
 4 |   "private": true,
 5 |   "scripts": {
 6 |     "dev": "next dev --turbopack -p 3002",
 7 |     "build": "next build",
 8 |     "start": "next start",
 9 |     "lint": "next lint"
10 |   },
11 |   "dependencies": {
12 |     "@azure/cosmos": "^4.2.0",
13 |     "@azure/identity": "^4.6.0",
14 |     "@azure/storage-blob": "^12.26.0",
15 |     "@fastify/cors": "^10.0.2",
16 |     "@hookform/resolvers": "^3.9.0",
17 |     "@modelcontextprotocol/sdk": "^1.8.0",
18 |     "@next/swc-wasm-nodejs": "13.5.1",
19 |     "@radix-ui/react-accordion": "^1.2.0",
20 |     "@radix-ui/react-alert-dialog": "^1.1.1",
21 |     "@radix-ui/react-aspect-ratio": "^1.1.0",
22 |     "@radix-ui/react-avatar": "^1.1.0",
23 |     "@radix-ui/react-checkbox": "^1.1.1",
24 |     "@radix-ui/react-collapsible": "^1.1.0",
25 |     "@radix-ui/react-context-menu": "^2.2.1",
26 |     "@radix-ui/react-dialog": "^1.1.1",
27 |     "@radix-ui/react-dropdown-menu": "^2.1.1",
28 |     "@radix-ui/react-hover-card": "^1.1.1",
29 |     "@radix-ui/react-label": "^2.1.0",
30 |     "@radix-ui/react-menubar": "^1.1.1",
31 |     "@radix-ui/react-navigation-menu": "^1.2.0",
32 |     "@radix-ui/react-popover": "^1.1.1",
33 |     "@radix-ui/react-progress": "^1.1.0",
34 |     "@radix-ui/react-radio-group": "^1.2.0",
35 |     "@radix-ui/react-scroll-area": "^1.1.0",
36 |     "@radix-ui/react-select": "^2.1.1",
37 |     "@radix-ui/react-separator": "^1.1.0",
38 |     "@radix-ui/react-slider": "^1.2.0",
39 |     "@radix-ui/react-slot": "^1.1.0",
40 |     "@radix-ui/react-switch": "^1.1.0",
41 |     "@radix-ui/react-tabs": "^1.1.0",
42 |     "@radix-ui/react-toast": "^1.2.1",
43 |     "@radix-ui/react-toggle": "^1.1.0",
44 |     "@radix-ui/react-toggle-group": "^1.1.0",
45 |     "@radix-ui/react-tooltip": "^1.1.2",
46 |     "@types/node": "20.6.2",
47 |     "@types/react": "19.0.8",
48 |     "@types/react-dom": "19.0.3",
49 |     "autoprefixer": "10.4.15",
50 |     "axios": "^1.7.9",
51 |     "azure-storage": "^2.10.7",
52 |     "class-variance-authority": "^0.7.0",
53 |     "clsx": "^2.1.1",
54 |     "cmdk": "^1.0.0",
55 |     "date-fns": "^3.6.0",
56 |     "dotenv": "^16.4.7",
57 |     "embla-carousel-react": "^8.3.0",
58 |     "eslint": "8.49.0",
59 |     "eslint-config-next": "15.1.6",
60 |     "express": "^5.0.1",
61 |     "input-otp": "^1.2.4",
62 |     "lucide-react": "^0.446.0",
63 |     "next": "15.1.6",
64 |     "next-themes": "^0.3.0",
65 |     "openai": "^4.90.0",
66 |     "postcss": "8.4.30",
67 |     "re-resizable": "^6.11.2",
68 |     "react": "19.0.0",
69 |     "react-day-picker": "^8.10.1",
70 |     "react-dom": "19.0.0",
71 |     "react-hook-form": "^7.53.0",
72 |     "react-markdown": "^10.1.0",
73 |     "react-resizable-panels": "^2.1.3",
74 |     "recharts": "^2.12.7",
75 |     "sonner": "^1.5.0",
76 |     "tailwind-merge": "^2.5.2",
77 |     "tailwindcss": "3.3.3",
78 |     "tailwindcss-animate": "^1.0.7",
79 |     "typescript": "5.2.2",
80 |     "uuid": "^11.0.5",
81 |     "vaul": "^0.9.9",
82 |     "zod": "^3.24.2"
83 |   },
84 |   "devDependencies": {},
85 |   "overrides": {
86 |     "@types/react": "19.0.8",
87 |     "@types/react-dom": "19.0.3"
88 |   }
89 | }
90 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/drawer.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | 'use client';
  2 | 
  3 | import * as React from 'react';
  4 | import { Drawer as DrawerPrimitive } from 'vaul';
  5 | 
  6 | import { cn } from '@/lib/utils';
  7 | 
  8 | const Drawer = ({
  9 |   shouldScaleBackground = true,
 10 |   ...props
 11 | }: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
 12 |   <DrawerPrimitive.Root
 13 |     shouldScaleBackground={shouldScaleBackground}
 14 |     {...props}
 15 |   />
 16 | );
 17 | Drawer.displayName = 'Drawer';
 18 | 
 19 | const DrawerTrigger = DrawerPrimitive.Trigger;
 20 | 
 21 | const DrawerPortal = DrawerPrimitive.Portal;
 22 | 
 23 | const DrawerClose = DrawerPrimitive.Close;
 24 | 
 25 | const DrawerOverlay = React.forwardRef<
 26 |   React.ElementRef<typeof DrawerPrimitive.Overlay>,
 27 |   React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
 28 | >(({ className, ...props }, ref) => (
 29 |   <DrawerPrimitive.Overlay
 30 |     ref={ref}
 31 |     className={cn('fixed inset-0 z-50 bg-black/80', className)}
 32 |     {...props}
 33 |   />
 34 | ));
 35 | DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName;
 36 | 
 37 | const DrawerContent = React.forwardRef<
 38 |   React.ElementRef<typeof DrawerPrimitive.Content>,
 39 |   React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
 40 | >(({ className, children, ...props }, ref) => (
 41 |   <DrawerPortal>
 42 |     <DrawerOverlay />
 43 |     <DrawerPrimitive.Content
 44 |       ref={ref}
 45 |       className={cn(
 46 |         'fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background',
 47 |         className
 48 |       )}
 49 |       {...props}
 50 |     >
 51 |       <div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
 52 |       {children}
 53 |     </DrawerPrimitive.Content>
 54 |   </DrawerPortal>
 55 | ));
 56 | DrawerContent.displayName = 'DrawerContent';
 57 | 
 58 | const DrawerHeader = ({
 59 |   className,
 60 |   ...props
 61 | }: React.HTMLAttributes<HTMLDivElement>) => (
 62 |   <div
 63 |     className={cn('grid gap-1.5 p-4 text-center sm:text-left', className)}
 64 |     {...props}
 65 |   />
 66 | );
 67 | DrawerHeader.displayName = 'DrawerHeader';
 68 | 
 69 | const DrawerFooter = ({
 70 |   className,
 71 |   ...props
 72 | }: React.HTMLAttributes<HTMLDivElement>) => (
 73 |   <div
 74 |     className={cn('mt-auto flex flex-col gap-2 p-4', className)}
 75 |     {...props}
 76 |   />
 77 | );
 78 | DrawerFooter.displayName = 'DrawerFooter';
 79 | 
 80 | const DrawerTitle = React.forwardRef<
 81 |   React.ElementRef<typeof DrawerPrimitive.Title>,
 82 |   React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
 83 | >(({ className, ...props }, ref) => (
 84 |   <DrawerPrimitive.Title
 85 |     ref={ref}
 86 |     className={cn(
 87 |       'text-lg font-semibold leading-none tracking-tight',
 88 |       className
 89 |     )}
 90 |     {...props}
 91 |   />
 92 | ));
 93 | DrawerTitle.displayName = DrawerPrimitive.Title.displayName;
 94 | 
 95 | const DrawerDescription = React.forwardRef<
 96 |   React.ElementRef<typeof DrawerPrimitive.Description>,
 97 |   React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
 98 | >(({ className, ...props }, ref) => (
 99 |   <DrawerPrimitive.Description
100 |     ref={ref}
101 |     className={cn('text-sm text-muted-foreground', className)}
102 |     {...props}
103 |   />
104 | ));
105 | DrawerDescription.displayName = DrawerPrimitive.Description.displayName;
106 | 
107 | export {
108 |   Drawer,
109 |   DrawerPortal,
110 |   DrawerOverlay,
111 |   DrawerTrigger,
112 |   DrawerClose,
113 |   DrawerContent,
114 |   DrawerHeader,
115 |   DrawerFooter,
116 |   DrawerTitle,
117 |   DrawerDescription,
118 | };
119 | 
```

--------------------------------------------------------------------------------
/nextjs/app/orders/[id]/page.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | 'use client'
  2 | 
  3 | import { useEffect, useState } from 'react'
  4 | import Image from 'next/image'
  5 | import { Button } from '@/components/ui/button'
  6 | import { useRouter } from 'next/navigation'
  7 | 
  8 | export default function OrderDetailsPage({ params }: { params: { id: string } }) {
  9 |   const [order, setOrder] = useState<any>(null)
 10 |   const [loading, setLoading] = useState(true)
 11 |   const [imageUrls, setImageUrls] = useState<{ [key: string]: string }>({})
 12 |   const router = useRouter()
 13 | 
 14 |   useEffect(() => {
 15 |     async function fetchOrder() {
 16 |       try {
 17 |         const response = await fetch(`/api/orders/${params.id}`)
 18 |         if (response.ok) {
 19 |           const data = await response.json()
 20 |           setOrder(data.data)
 21 |           // Fetch images for all items
 22 |           data.data.items.forEach(async (item: any) => {
 23 |             const imgResponse = await fetch(`/api/blob-url?blob=${item.id}.webp`, {
 24 |               cache: 'force-cache'
 25 |             })
 26 |             const imgData = await imgResponse.json()
 27 |             if (imgData.url) {
 28 |               setImageUrls(prev => ({
 29 |                 ...prev,
 30 |                 [item.id]: imgData.url
 31 |               }))
 32 |             }
 33 |           })
 34 |         }
 35 |       } catch (error) {
 36 |         console.error('Error fetching order:', error)
 37 |       } finally {
 38 |         setLoading(false)
 39 |       }
 40 |     }
 41 | 
 42 |     fetchOrder()
 43 |   }, [params.id])
 44 | 
 45 |   if (loading) {
 46 |     return <div>Loading order details...</div>
 47 |   }
 48 | 
 49 |   if (!order) {
 50 |     return <div>Order not found</div>
 51 |   }
 52 | 
 53 |   return (
 54 |     <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
 55 |       <div className="mb-8">
 56 |         <h1 className="text-2xl font-bold mb-2">Order Confirmation</h1>
 57 |         <p className="text-gray-600">Order #{order.id}</p>
 58 |         <p className="text-gray-600">Status: {order.status}</p>
 59 |         <p className="text-gray-600">Date: {new Date(order.createdAt).toLocaleDateString()}</p>
 60 |       </div>
 61 | 
 62 |       <div className="bg-white shadow overflow-hidden sm:rounded-lg">
 63 |         <div className="px-4 py-5 sm:px-6">
 64 |           <h2 className="text-lg font-medium">Order Items</h2>
 65 |         </div>
 66 |         <div className="border-t border-gray-200">
 67 |           {order.items.map((item: any) => (
 68 |             <div key={item.id} className="flex items-center p-4 border-b">
 69 |               <Image
 70 |                 src={imageUrls[item.id] || '/placeholder-300x300.png'}
 71 |                 alt={item.name}
 72 |                 className="w-20 h-20 object-cover rounded"
 73 |                 width={80}
 74 |                 height={80}
 75 |                 unoptimized
 76 |               />
 77 |               <div className="ml-4 flex-1">
 78 |                 <h3 className="font-medium">{item.name}</h3>
 79 |                 <p className="text-gray-500">Quantity: {item.quantity}</p>
 80 |                 <p className="text-gray-500">${item.price} each</p>
 81 |               </div>
 82 |               <div className="text-right">
 83 |                 <p className="font-medium">${(item.price * item.quantity).toFixed(2)}</p>
 84 |               </div>
 85 |             </div>
 86 |           ))}
 87 |         </div>
 88 |         <div className="px-4 py-5 sm:px-6">
 89 |           <div className="flex justify-between">
 90 |             <span className="font-medium">Total</span>
 91 |             <span className="font-medium">${order.total.toFixed(2)}</span>
 92 |           </div>
 93 |         </div>
 94 |       </div>
 95 | 
 96 |       <Button 
 97 |         className="mt-8"
 98 |         onClick={() => router.push('/')}
 99 |       >
100 |         Continue Shopping
101 |       </Button>
102 |     </div>
103 |   )
104 | }
```

--------------------------------------------------------------------------------
/nextjs/context/CartContext.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | // app/context/CartContext.tsx
  2 | 
  3 | 'use client'
  4 | 
  5 | export const dynamic = 'force-dynamic' // Ensure dynamic rendering
  6 | 
  7 | import { createContext, useContext, useEffect, useState } from 'react'
  8 | 
  9 | import { Cart } from '@/models/cart'
 10 | import { CartContextType } from '@/models/cartContextType'
 11 | import { CartItem } from '@/models/cartItem'
 12 | import { EMAIL } from '@/models/constants'
 13 | 
 14 | export const CartContext = createContext<CartContextType | undefined>(undefined)
 15 | const prefix = '/context/CartContext.tsx'
 16 | 
 17 | export function CartProvider ({ children }: { children: React.ReactNode }) {
 18 |   const [items, setItems] = useState<CartItem[]>([])
 19 | 
 20 |   useEffect(() => {
 21 |     async function loadCart () {
 22 |       try {
 23 |         const savedCart = await loadCartFromCosmosDB(EMAIL)
 24 |         if (savedCart?.data?.items) {
 25 |           console.log(`[${prefix}::loadCart]`, savedCart.data.items)
 26 |           setItems(savedCart.data.items)
 27 |         }
 28 |       } catch (error) {
 29 |         console.error('Error loading cart:', error)
 30 |       }
 31 |     }
 32 | 
 33 |     loadCart()
 34 |   }, []) // Remove isSocketUpdate dependency
 35 | 
 36 |   useEffect(() => {
 37 |     console.log('Items state changed:', items)
 38 |     let isStale = false
 39 | 
 40 |     const storeCart = async () => {
 41 |       if (isStale) return
 42 |       try {
 43 |         const cart: Cart = {
 44 |           userName: EMAIL,
 45 |           items: items
 46 |         }
 47 |         await storeCartInCosmosDB(cart)
 48 |       } catch (error) {
 49 |         console.error('Error managing cart:', error)
 50 |       }
 51 |     }
 52 | 
 53 |     storeCart()
 54 | 
 55 |     return () => {
 56 |       isStale = true
 57 |     }
 58 |   }, [items])
 59 | 
 60 |   const addItem = (newItem: Omit<CartItem, 'quantity'>) => {
 61 |     setItems(currentItems => {
 62 |       const existingItem = currentItems.find(item => item.id === newItem.id)
 63 |       if (existingItem) {
 64 |         return currentItems.map(item =>
 65 |           item.id === newItem.id
 66 |             ? { ...item, quantity: item.quantity + 1 }
 67 |             : item
 68 |         )
 69 |       }
 70 |       return [...currentItems, { ...newItem, quantity: 1 }]
 71 |     })
 72 |   }
 73 |   const removeItem = (id: number) => {
 74 |     setItems(currentItems => currentItems.filter(item => item.id !== id))
 75 |   }
 76 |   const updateQuantity = (id: number, quantity: number) => {
 77 |     setItems(currentItems =>
 78 |       currentItems.map(item => (item.id === id ? { ...item, quantity } : item))
 79 |     )
 80 |   }
 81 |   const clearCart = () => {
 82 |     setItems([])
 83 |   }
 84 |   // load cart from Cosmos DB
 85 |   const loadCartFromCosmosDB = async (userName: string) => {
 86 |     try {
 87 |       const response = await fetch(`/api/cart?userName=${userName}`)
 88 |       const result = await response.json()
 89 |       console.log(`[${prefix}::loadCartFromCosmosDB] ${JSON.stringify(result)}`)
 90 |       return result
 91 |     } catch (error) {
 92 |       console.error('Error fetching cart:', error)
 93 |       return error
 94 |     }
 95 |   }
 96 |   // Function to store cart in Cosmos DB
 97 |   const storeCartInCosmosDB = async (cart: Cart) => {
 98 |     try {
 99 |       console.log(`[${prefix}::storeCartInCosmosDB] ${JSON.stringify(cart)}`)
100 |       const response = await fetch(`/api/cart`, {
101 |         method: 'POST',
102 |         headers: {
103 |           'Content-Type': 'application/json',
104 |           'X-Client-Update': 'true'
105 |         },
106 |         body: JSON.stringify(cart)
107 |       })
108 |       return await response.json()
109 |     } catch (error) {
110 |       console.error('Error storing cart in Cosmos DB:', error)
111 |       throw error
112 |     }
113 |   }
114 | 
115 |   return (
116 |     <CartContext.Provider
117 |       value={{ items, addItem, removeItem, updateQuantity, clearCart }}
118 |     >
119 |       {children}
120 |     </CartContext.Provider>
121 |   )
122 | }
123 | 
124 | export function useCart () {
125 |   const context = useContext(CartContext)
126 |   if (context === undefined) {
127 |     throw new Error('useCart must be used within a CartProvider')
128 |   }
129 |   return context
130 | }
131 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/dialog.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | 'use client';
  2 | 
  3 | import * as React from 'react';
  4 | import * as DialogPrimitive from '@radix-ui/react-dialog';
  5 | import { X } from 'lucide-react';
  6 | 
  7 | import { cn } from '@/lib/utils';
  8 | 
  9 | const Dialog = DialogPrimitive.Root;
 10 | 
 11 | const DialogTrigger = DialogPrimitive.Trigger;
 12 | 
 13 | const DialogPortal = DialogPrimitive.Portal;
 14 | 
 15 | const DialogClose = DialogPrimitive.Close;
 16 | 
 17 | const DialogOverlay = React.forwardRef<
 18 |   React.ElementRef<typeof DialogPrimitive.Overlay>,
 19 |   React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
 20 | >(({ className, ...props }, ref) => (
 21 |   <DialogPrimitive.Overlay
 22 |     ref={ref}
 23 |     className={cn(
 24 |       'fixed inset-0 z-50 bg-black/80  data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
 25 |       className
 26 |     )}
 27 |     {...props}
 28 |   />
 29 | ));
 30 | DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
 31 | 
 32 | const DialogContent = React.forwardRef<
 33 |   React.ElementRef<typeof DialogPrimitive.Content>,
 34 |   React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
 35 | >(({ className, children, ...props }, ref) => (
 36 |   <DialogPortal>
 37 |     <DialogOverlay />
 38 |     <DialogPrimitive.Content
 39 |       ref={ref}
 40 |       className={cn(
 41 |         'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
 42 |         className
 43 |       )}
 44 |       {...props}
 45 |     >
 46 |       {children}
 47 |       <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
 48 |         <X className="h-4 w-4" />
 49 |         <span className="sr-only">Close</span>
 50 |       </DialogPrimitive.Close>
 51 |     </DialogPrimitive.Content>
 52 |   </DialogPortal>
 53 | ));
 54 | DialogContent.displayName = DialogPrimitive.Content.displayName;
 55 | 
 56 | const DialogHeader = ({
 57 |   className,
 58 |   ...props
 59 | }: React.HTMLAttributes<HTMLDivElement>) => (
 60 |   <div
 61 |     className={cn(
 62 |       'flex flex-col space-y-1.5 text-center sm:text-left',
 63 |       className
 64 |     )}
 65 |     {...props}
 66 |   />
 67 | );
 68 | DialogHeader.displayName = 'DialogHeader';
 69 | 
 70 | const DialogFooter = ({
 71 |   className,
 72 |   ...props
 73 | }: React.HTMLAttributes<HTMLDivElement>) => (
 74 |   <div
 75 |     className={cn(
 76 |       'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
 77 |       className
 78 |     )}
 79 |     {...props}
 80 |   />
 81 | );
 82 | DialogFooter.displayName = 'DialogFooter';
 83 | 
 84 | const DialogTitle = React.forwardRef<
 85 |   React.ElementRef<typeof DialogPrimitive.Title>,
 86 |   React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
 87 | >(({ className, ...props }, ref) => (
 88 |   <DialogPrimitive.Title
 89 |     ref={ref}
 90 |     className={cn(
 91 |       'text-lg font-semibold leading-none tracking-tight',
 92 |       className
 93 |     )}
 94 |     {...props}
 95 |   />
 96 | ));
 97 | DialogTitle.displayName = DialogPrimitive.Title.displayName;
 98 | 
 99 | const DialogDescription = React.forwardRef<
100 |   React.ElementRef<typeof DialogPrimitive.Description>,
101 |   React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
102 | >(({ className, ...props }, ref) => (
103 |   <DialogPrimitive.Description
104 |     ref={ref}
105 |     className={cn('text-sm text-muted-foreground', className)}
106 |     {...props}
107 |   />
108 | ));
109 | DialogDescription.displayName = DialogPrimitive.Description.displayName;
110 | 
111 | export {
112 |   Dialog,
113 |   DialogPortal,
114 |   DialogOverlay,
115 |   DialogClose,
116 |   DialogTrigger,
117 |   DialogContent,
118 |   DialogHeader,
119 |   DialogFooter,
120 |   DialogTitle,
121 |   DialogDescription,
122 | };
123 | 
```

--------------------------------------------------------------------------------
/nextjs/components/Products.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | // components/Products.tsx
  2 | 
  3 | 'use client'
  4 | 
  5 | import { useEffect, useState } from 'react'
  6 | 
  7 | import { Button } from '@/components/ui/button'
  8 | import Image from 'next/image'
  9 | import { Product } from '@/models/product'
 10 | import { useCart } from '@/context/CartContext'
 11 | import { useRouter } from 'next/navigation'
 12 | import { v4 as uuidv4 } from 'uuid' // Import the uuid library
 13 | 
 14 | const prefix = 'components/Products.tsx'
 15 | 
 16 | interface ProductsProps {
 17 |   productIds?: string[];
 18 | }
 19 | 
 20 | export default function Products({ productIds }: ProductsProps) {
 21 |   const { addItem } = useCart()
 22 |   const router = useRouter()
 23 |   const [products, setProducts] = useState<Product[]>([])
 24 |   const [loading, setLoading] = useState(true)
 25 |   const [imageUrls, setImageUrls] = useState<{ [key: string]: string }>({})
 26 | 
 27 |   useEffect(() => {
 28 |     async function fetchImageUrl (id: string) {
 29 |       try {
 30 |         const response = await fetch(`/api/blob-url?blob=${id}.webp`, {
 31 |           cache: 'force-cache'
 32 |         })
 33 |         const data = await response.json()
 34 |         if (data.url) {
 35 |           setImageUrls(prev => ({
 36 |             ...prev,
 37 |             [id]: data.url // This will now be a base64 string
 38 |           }))
 39 |         }
 40 |       } catch (error) {
 41 |         console.error('Error fetching image URL:', error)
 42 |       }
 43 |     }
 44 | 
 45 |     async function fetchProducts () {
 46 |       try {
 47 |         const token = uuidv4()
 48 |         let url = `/api/products?token=${token}`
 49 |         
 50 |         // If productIds are provided, add them as a query parameter
 51 |         if (productIds && productIds.length > 0) {
 52 |           url += `&ids=${productIds.join(',')}`
 53 |         }
 54 |         
 55 |         const response = await fetch(url)
 56 |         const result = await response.json()
 57 |         console.log(`[${prefix}] fetchProducts: ${result.duration} ms `)
 58 |         setProducts(result.data)
 59 | 
 60 |         // Fetch image URLs for all products
 61 |         for (const product of result.data) {
 62 |           fetchImageUrl(product.id)
 63 |         }
 64 |       } catch (error) {
 65 |         console.error('Error fetching products:', error)
 66 |       } finally {
 67 |         setLoading(false)
 68 |       }
 69 |     }
 70 | 
 71 |     fetchProducts()
 72 |   }, [productIds]) // Add productIds as a dependency
 73 | 
 74 |   const handleAddToCart = (product: Product) => {
 75 |     const cartItem = {
 76 |       ...product,
 77 |       id: Number(product.id) // Convert id to number
 78 |     }
 79 |     addItem(cartItem)
 80 |     // router.push('/cart')
 81 |   }
 82 | 
 83 |   if (loading) {
 84 |     return (
 85 |       <div className='grid grid-cols-1 gap-y-10 gap-x-6 sm:grid-cols-2 lg:grid-cols-3 xl:gap-x-8'>
 86 |         {[...Array(6)].map((_, i) => (
 87 |           <div key={i} className='animate-pulse'>
 88 |             <div className='aspect-w-1 aspect-h-1 w-full bg-gray-200 rounded-lg mb-4' />
 89 |             <div className='h-4 bg-gray-200 rounded w-3/4 mb-2' />
 90 |             <div className='h-4 bg-gray-200 rounded w-1/4' />
 91 |           </div>
 92 |         ))}
 93 |       </div>
 94 |     )
 95 |   }
 96 | 
 97 |   return (
 98 |     <div className='grid grid-cols-1 gap-y-10 gap-x-6 sm:grid-cols-2 lg:grid-cols-3 xl:gap-x-8'>
 99 |       {products.map(product => (
100 |         <div key={product.id} className='group relative'>
101 |           <div className='aspect-w-1 aspect-h-1 w-full overflow-hidden rounded-lg bg-gray-200'>
102 |             <Image
103 |               src={imageUrls[product.id] || '/placeholder-300x300.png'}
104 |               alt={product.name}
105 |               className='h-full w-full object-cover object-center group-hover:opacity-75'
106 |               width={300}
107 |               height={300}
108 |               unoptimized
109 |             />
110 |           </div>
111 |           <div className='mt-4 flex justify-between'>
112 |             <div>
113 |               <h3 className='text-sm text-gray-700'>{product.name}</h3>
114 |               <p className='mt-1 text-sm text-gray-500'>${product.price}</p>
115 |             </div>
116 |           </div>
117 |           <Button
118 |             onClick={() => handleAddToCart(product)}
119 |             className='mt-4 w-full'
120 |           >
121 |             Add to Cart
122 |           </Button>
123 |         </div>
124 |       ))}
125 |     </div>
126 |   )
127 | }
128 | 
```

--------------------------------------------------------------------------------
/nextjs/hooks/use-toast.ts:
--------------------------------------------------------------------------------

```typescript
  1 | 'use client';
  2 | 
  3 | // Inspired by react-hot-toast library
  4 | import * as React from 'react';
  5 | 
  6 | import type { ToastActionElement, ToastProps } from '@/components/ui/toast';
  7 | 
  8 | const TOAST_LIMIT = 1;
  9 | const TOAST_REMOVE_DELAY = 1000000;
 10 | 
 11 | type ToasterToast = ToastProps & {
 12 |   id: string;
 13 |   title?: React.ReactNode;
 14 |   description?: React.ReactNode;
 15 |   action?: ToastActionElement;
 16 | };
 17 | 
 18 | const actionTypes = {
 19 |   ADD_TOAST: 'ADD_TOAST',
 20 |   UPDATE_TOAST: 'UPDATE_TOAST',
 21 |   DISMISS_TOAST: 'DISMISS_TOAST',
 22 |   REMOVE_TOAST: 'REMOVE_TOAST',
 23 | } as const;
 24 | 
 25 | let count = 0;
 26 | 
 27 | function genId() {
 28 |   count = (count + 1) % Number.MAX_SAFE_INTEGER;
 29 |   return count.toString();
 30 | }
 31 | 
 32 | type ActionType = typeof actionTypes;
 33 | 
 34 | type Action =
 35 |   | {
 36 |       type: ActionType['ADD_TOAST'];
 37 |       toast: ToasterToast;
 38 |     }
 39 |   | {
 40 |       type: ActionType['UPDATE_TOAST'];
 41 |       toast: Partial<ToasterToast>;
 42 |     }
 43 |   | {
 44 |       type: ActionType['DISMISS_TOAST'];
 45 |       toastId?: ToasterToast['id'];
 46 |     }
 47 |   | {
 48 |       type: ActionType['REMOVE_TOAST'];
 49 |       toastId?: ToasterToast['id'];
 50 |     };
 51 | 
 52 | interface State {
 53 |   toasts: ToasterToast[];
 54 | }
 55 | 
 56 | const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();
 57 | 
 58 | const addToRemoveQueue = (toastId: string) => {
 59 |   if (toastTimeouts.has(toastId)) {
 60 |     return;
 61 |   }
 62 | 
 63 |   const timeout = setTimeout(() => {
 64 |     toastTimeouts.delete(toastId);
 65 |     dispatch({
 66 |       type: 'REMOVE_TOAST',
 67 |       toastId: toastId,
 68 |     });
 69 |   }, TOAST_REMOVE_DELAY);
 70 | 
 71 |   toastTimeouts.set(toastId, timeout);
 72 | };
 73 | 
 74 | export const reducer = (state: State, action: Action): State => {
 75 |   switch (action.type) {
 76 |     case 'ADD_TOAST':
 77 |       return {
 78 |         ...state,
 79 |         toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
 80 |       };
 81 | 
 82 |     case 'UPDATE_TOAST':
 83 |       return {
 84 |         ...state,
 85 |         toasts: state.toasts.map((t) =>
 86 |           t.id === action.toast.id ? { ...t, ...action.toast } : t
 87 |         ),
 88 |       };
 89 | 
 90 |     case 'DISMISS_TOAST': {
 91 |       const { toastId } = action;
 92 | 
 93 |       // ! Side effects ! - This could be extracted into a dismissToast() action,
 94 |       // but I'll keep it here for simplicity
 95 |       if (toastId) {
 96 |         addToRemoveQueue(toastId);
 97 |       } else {
 98 |         state.toasts.forEach((toast) => {
 99 |           addToRemoveQueue(toast.id);
100 |         });
101 |       }
102 | 
103 |       return {
104 |         ...state,
105 |         toasts: state.toasts.map((t) =>
106 |           t.id === toastId || toastId === undefined
107 |             ? {
108 |                 ...t,
109 |                 open: false,
110 |               }
111 |             : t
112 |         ),
113 |       };
114 |     }
115 |     case 'REMOVE_TOAST':
116 |       if (action.toastId === undefined) {
117 |         return {
118 |           ...state,
119 |           toasts: [],
120 |         };
121 |       }
122 |       return {
123 |         ...state,
124 |         toasts: state.toasts.filter((t) => t.id !== action.toastId),
125 |       };
126 |   }
127 | };
128 | 
129 | const listeners: Array<(state: State) => void> = [];
130 | 
131 | let memoryState: State = { toasts: [] };
132 | 
133 | function dispatch(action: Action) {
134 |   memoryState = reducer(memoryState, action);
135 |   listeners.forEach((listener) => {
136 |     listener(memoryState);
137 |   });
138 | }
139 | 
140 | type Toast = Omit<ToasterToast, 'id'>;
141 | 
142 | function toast({ ...props }: Toast) {
143 |   const id = genId();
144 | 
145 |   const update = (props: ToasterToast) =>
146 |     dispatch({
147 |       type: 'UPDATE_TOAST',
148 |       toast: { ...props, id },
149 |     });
150 |   const dismiss = () => dispatch({ type: 'DISMISS_TOAST', toastId: id });
151 | 
152 |   dispatch({
153 |     type: 'ADD_TOAST',
154 |     toast: {
155 |       ...props,
156 |       id,
157 |       open: true,
158 |       onOpenChange: (open) => {
159 |         if (!open) dismiss();
160 |       },
161 |     },
162 |   });
163 | 
164 |   return {
165 |     id: id,
166 |     dismiss,
167 |     update,
168 |   };
169 | }
170 | 
171 | function useToast() {
172 |   const [state, setState] = React.useState<State>(memoryState);
173 | 
174 |   React.useEffect(() => {
175 |     listeners.push(setState);
176 |     return () => {
177 |       const index = listeners.indexOf(setState);
178 |       if (index > -1) {
179 |         listeners.splice(index, 1);
180 |       }
181 |     };
182 |   }, [state]);
183 | 
184 |   return {
185 |     ...state,
186 |     toast,
187 |     dismiss: (toastId?: string) => dispatch({ type: 'DISMISS_TOAST', toastId }),
188 |   };
189 | }
190 | 
191 | export { useToast, toast };
192 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/form.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | 'use client';
  2 | 
  3 | import * as React from 'react';
  4 | import * as LabelPrimitive from '@radix-ui/react-label';
  5 | import { Slot } from '@radix-ui/react-slot';
  6 | import {
  7 |   Controller,
  8 |   ControllerProps,
  9 |   FieldPath,
 10 |   FieldValues,
 11 |   FormProvider,
 12 |   useFormContext,
 13 | } from 'react-hook-form';
 14 | 
 15 | import { cn } from '@/lib/utils';
 16 | import { Label } from '@/components/ui/label';
 17 | 
 18 | const Form = FormProvider;
 19 | 
 20 | type FormFieldContextValue<
 21 |   TFieldValues extends FieldValues = FieldValues,
 22 |   TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
 23 | > = {
 24 |   name: TName;
 25 | };
 26 | 
 27 | const FormFieldContext = React.createContext<FormFieldContextValue>(
 28 |   {} as FormFieldContextValue
 29 | );
 30 | 
 31 | const FormField = <
 32 |   TFieldValues extends FieldValues = FieldValues,
 33 |   TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
 34 | >({
 35 |   ...props
 36 | }: ControllerProps<TFieldValues, TName>) => {
 37 |   return (
 38 |     <FormFieldContext.Provider value={{ name: props.name }}>
 39 |       <Controller {...props} />
 40 |     </FormFieldContext.Provider>
 41 |   );
 42 | };
 43 | 
 44 | const useFormField = () => {
 45 |   const fieldContext = React.useContext(FormFieldContext);
 46 |   const itemContext = React.useContext(FormItemContext);
 47 |   const { getFieldState, formState } = useFormContext();
 48 | 
 49 |   const fieldState = getFieldState(fieldContext.name, formState);
 50 | 
 51 |   if (!fieldContext) {
 52 |     throw new Error('useFormField should be used within <FormField>');
 53 |   }
 54 | 
 55 |   const { id } = itemContext;
 56 | 
 57 |   return {
 58 |     id,
 59 |     name: fieldContext.name,
 60 |     formItemId: `${id}-form-item`,
 61 |     formDescriptionId: `${id}-form-item-description`,
 62 |     formMessageId: `${id}-form-item-message`,
 63 |     ...fieldState,
 64 |   };
 65 | };
 66 | 
 67 | type FormItemContextValue = {
 68 |   id: string;
 69 | };
 70 | 
 71 | const FormItemContext = React.createContext<FormItemContextValue>(
 72 |   {} as FormItemContextValue
 73 | );
 74 | 
 75 | const FormItem = React.forwardRef<
 76 |   HTMLDivElement,
 77 |   React.HTMLAttributes<HTMLDivElement>
 78 | >(({ className, ...props }, ref) => {
 79 |   const id = React.useId();
 80 | 
 81 |   return (
 82 |     <FormItemContext.Provider value={{ id }}>
 83 |       <div ref={ref} className={cn('space-y-2', className)} {...props} />
 84 |     </FormItemContext.Provider>
 85 |   );
 86 | });
 87 | FormItem.displayName = 'FormItem';
 88 | 
 89 | const FormLabel = React.forwardRef<
 90 |   React.ElementRef<typeof LabelPrimitive.Root>,
 91 |   React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
 92 | >(({ className, ...props }, ref) => {
 93 |   const { error, formItemId } = useFormField();
 94 | 
 95 |   return (
 96 |     <Label
 97 |       ref={ref}
 98 |       className={cn(error && 'text-destructive', className)}
 99 |       htmlFor={formItemId}
100 |       {...props}
101 |     />
102 |   );
103 | });
104 | FormLabel.displayName = 'FormLabel';
105 | 
106 | const FormControl = React.forwardRef<
107 |   React.ElementRef<typeof Slot>,
108 |   React.ComponentPropsWithoutRef<typeof Slot>
109 | >(({ ...props }, ref) => {
110 |   const { error, formItemId, formDescriptionId, formMessageId } =
111 |     useFormField();
112 | 
113 |   return (
114 |     <Slot
115 |       ref={ref}
116 |       id={formItemId}
117 |       aria-describedby={
118 |         !error
119 |           ? `${formDescriptionId}`
120 |           : `${formDescriptionId} ${formMessageId}`
121 |       }
122 |       aria-invalid={!!error}
123 |       {...props}
124 |     />
125 |   );
126 | });
127 | FormControl.displayName = 'FormControl';
128 | 
129 | const FormDescription = React.forwardRef<
130 |   HTMLParagraphElement,
131 |   React.HTMLAttributes<HTMLParagraphElement>
132 | >(({ className, ...props }, ref) => {
133 |   const { formDescriptionId } = useFormField();
134 | 
135 |   return (
136 |     <p
137 |       ref={ref}
138 |       id={formDescriptionId}
139 |       className={cn('text-sm text-muted-foreground', className)}
140 |       {...props}
141 |     />
142 |   );
143 | });
144 | FormDescription.displayName = 'FormDescription';
145 | 
146 | const FormMessage = React.forwardRef<
147 |   HTMLParagraphElement,
148 |   React.HTMLAttributes<HTMLParagraphElement>
149 | >(({ className, children, ...props }, ref) => {
150 |   const { error, formMessageId } = useFormField();
151 |   const body = error ? String(error?.message) : children;
152 | 
153 |   if (!body) {
154 |     return null;
155 |   }
156 | 
157 |   return (
158 |     <p
159 |       ref={ref}
160 |       id={formMessageId}
161 |       className={cn('text-sm font-medium text-destructive', className)}
162 |       {...props}
163 |     >
164 |       {body}
165 |     </p>
166 |   );
167 | });
168 | FormMessage.displayName = 'FormMessage';
169 | 
170 | export {
171 |   useFormField,
172 |   Form,
173 |   FormItem,
174 |   FormLabel,
175 |   FormControl,
176 |   FormDescription,
177 |   FormMessage,
178 |   FormField,
179 | };
180 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/sheet.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | "use client"
  2 | 
  3 | import * as React from "react"
  4 | import * as SheetPrimitive from "@radix-ui/react-dialog"
  5 | import { cva, type VariantProps } from "class-variance-authority"
  6 | import { X } from "lucide-react"
  7 | 
  8 | import { cn } from "@/lib/utils"
  9 | 
 10 | const Sheet = SheetPrimitive.Root
 11 | 
 12 | const SheetTrigger = SheetPrimitive.Trigger
 13 | 
 14 | const SheetClose = SheetPrimitive.Close
 15 | 
 16 | const SheetPortal = SheetPrimitive.Portal
 17 | 
 18 | const SheetOverlay = React.forwardRef<
 19 |   React.ElementRef<typeof SheetPrimitive.Overlay>,
 20 |   React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
 21 | >(({ className, ...props }, ref) => (
 22 |   <SheetPrimitive.Overlay
 23 |     className={cn(
 24 |       "fixed inset-0 z-50 pointer-events-none",
 25 |       className
 26 |     )}
 27 |     {...props}
 28 |     ref={ref}
 29 |   />
 30 | ))
 31 | SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
 32 | 
 33 | const sheetVariants = cva(
 34 |   'fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
 35 |   {
 36 |     variants: {
 37 |       side: {
 38 |         top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',
 39 |         bottom:
 40 |           'inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',
 41 |         left: 'inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm',
 42 |         right:
 43 |           'inset-y-0 right-0 h-full w-3/4  border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm',
 44 |       },
 45 |     },
 46 |     defaultVariants: {
 47 |       side: 'right',
 48 |     },
 49 |   }
 50 | );
 51 | 
 52 | interface SheetContentProps
 53 |   extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
 54 |     VariantProps<typeof sheetVariants> {}
 55 | 
 56 | const SheetContent = React.forwardRef<
 57 |   React.ElementRef<typeof SheetPrimitive.Content>,
 58 |   SheetContentProps
 59 | >(({ side = 'right', className, children, ...props }, ref) => (
 60 |   <SheetPortal>
 61 |     <SheetOverlay />
 62 |     <SheetPrimitive.Content
 63 |       ref={ref}
 64 |       className={cn(sheetVariants({ side }), className)}
 65 |       onPointerDownOutside={(e) => {
 66 |         e.preventDefault();
 67 |       }}
 68 |       {...props}
 69 |     >
 70 |       {children}
 71 |       <SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
 72 |         <X className="h-4 w-4" />
 73 |         <span className="sr-only">Close</span>
 74 |       </SheetPrimitive.Close>
 75 |     </SheetPrimitive.Content>
 76 |   </SheetPortal>
 77 | ));
 78 | SheetContent.displayName = SheetPrimitive.Content.displayName;
 79 | 
 80 | const SheetHeader = ({
 81 |   className,
 82 |   ...props
 83 | }: React.HTMLAttributes<HTMLDivElement>) => (
 84 |   <div
 85 |     className={cn(
 86 |       'flex flex-col space-y-2 text-center sm:text-left',
 87 |       className
 88 |     )}
 89 |     {...props}
 90 |   />
 91 | );
 92 | SheetHeader.displayName = 'SheetHeader';
 93 | 
 94 | const SheetFooter = ({
 95 |   className,
 96 |   ...props
 97 | }: React.HTMLAttributes<HTMLDivElement>) => (
 98 |   <div
 99 |     className={cn(
100 |       'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
101 |       className
102 |     )}
103 |     {...props}
104 |   />
105 | );
106 | SheetFooter.displayName = 'SheetFooter';
107 | 
108 | const SheetTitle = React.forwardRef<
109 |   React.ElementRef<typeof SheetPrimitive.Title>,
110 |   React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
111 | >(({ className, ...props }, ref) => (
112 |   <SheetPrimitive.Title
113 |     ref={ref}
114 |     className={cn('text-lg font-semibold text-foreground', className)}
115 |     {...props}
116 |   />
117 | ));
118 | SheetTitle.displayName = SheetPrimitive.Title.displayName;
119 | 
120 | const SheetDescription = React.forwardRef<
121 |   React.ElementRef<typeof SheetPrimitive.Description>,
122 |   React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
123 | >(({ className, ...props }, ref) => (
124 |   <SheetPrimitive.Description
125 |     ref={ref}
126 |     className={cn('text-sm text-muted-foreground', className)}
127 |     {...props}
128 |   />
129 | ));
130 | SheetDescription.displayName = SheetPrimitive.Description.displayName;
131 | 
132 | export {
133 |   Sheet,
134 |   SheetPortal,
135 |   SheetOverlay,
136 |   SheetTrigger,
137 |   SheetClose,
138 |   SheetContent,
139 |   SheetHeader,
140 |   SheetFooter,
141 |   SheetTitle,
142 |   SheetDescription,
143 | };
144 | 
```

--------------------------------------------------------------------------------
/nextjs/lib/cosmosdb.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { Container, CosmosClient, SqlQuerySpec } from "@azure/cosmos";
  2 | 
  3 | import { Cart } from "@/models/cart";
  4 | import { DefaultAzureCredential } from "@azure/identity";
  5 | 
  6 | const sourceFile: string = "lib/cosmosdb.ts";
  7 | 
  8 | export class CosmosDBService {
  9 |   private client: CosmosClient;
 10 |   public database: any;
 11 |   public cartsContainer: Container;
 12 |   public productsContainer: Container;
 13 |   public ordersContainer: Container; // Add this line
 14 | 
 15 |   constructor() {
 16 |     const endpoint = process.env.AZURE_COSMOSDB_NOSQL_ENDPOINT as string;
 17 |     const databaseId = process.env.AZURE_COSMOSDB_NOSQL_DATABASE as string;
 18 |     const productsContainerId = process.env.AZURE_COSMOSDB_NOSQL_PRODUCTS_CONTAINER as string;
 19 |     const cartsContainerId = process.env.AZURE_COSMOSDB_NOSQL_CARTS_CONTAINER as string;
 20 |     const ordersContainerId = process.env.AZURE_COSMOSDB_NOSQL_ORDERS_CONTAINER as string;
 21 | 
 22 |     const credential = new DefaultAzureCredential();
 23 | 
 24 |     this.client = new CosmosClient({
 25 |       endpoint: endpoint,
 26 |       aadCredentials: credential,
 27 |     });
 28 | 
 29 |     this.database = this.client.database(databaseId);
 30 |     this.cartsContainer = this.database.container(cartsContainerId);
 31 |     this.productsContainer = this.database.container(productsContainerId);
 32 |     this.ordersContainer = this.database.container(ordersContainerId);
 33 |   }
 34 | 
 35 |   async storeCart(cart: Cart) {
 36 |     try {
 37 |       const sqlQuerySpec: SqlQuerySpec = {
 38 |         query: "SELECT TOP 1 * FROM c WHERE c.userName = @userName",
 39 |         parameters: [
 40 |           {
 41 |             name: "@userName",
 42 |             value: cart.userName,
 43 |           },
 44 |         ],
 45 |       };
 46 |       const { resources: items } = await this.cartsContainer.items.query(sqlQuerySpec).fetchAll();
 47 | 
 48 |       if (items.length > 0) {
 49 |         const existingCart = items[0];
 50 |         existingCart.items = cart.items;
 51 |         this.cartsContainer.items.upsert(existingCart);
 52 |       } else {
 53 |         this.cartsContainer.items.upsert(cart);
 54 |       }
 55 | 
 56 |       return {
 57 |         data: items,
 58 |         statusCode: 200,
 59 |       };
 60 |     } catch (error) {
 61 |       return {
 62 |         error: "Error storing cart in Cosmos DB: " + error,
 63 |         statusCode: 500,
 64 |       };
 65 |     }
 66 |   }
 67 | 
 68 |   async loadCart(userName: string) {
 69 |     try {
 70 |       const sqlQuerySpec: SqlQuerySpec = {
 71 |         query: "SELECT TOP 1 * FROM c WHERE c.userName = @userName",
 72 |         parameters: [
 73 |           {
 74 |             name: "@userName",
 75 |             value: userName,
 76 |           },
 77 |         ],
 78 |       };
 79 |       const { resources: items } = await this.cartsContainer.items.query(sqlQuerySpec).fetchAll();
 80 | 
 81 |       return {
 82 |         data: items,
 83 |         statusCode: 200,
 84 |       };
 85 |     } catch (error) {
 86 |       return {
 87 |         error: "Error loading cart from Cosmos DB: " + error,
 88 |         statusCode: 500,
 89 |       };
 90 |     }
 91 |   }
 92 | 
 93 |   async getProducts() {
 94 |     const startTime = Date.now();
 95 |     try {
 96 |       const query = `SELECT c.id, c.type, c.brand, c.name, c.description, c.price FROM c`;
 97 |       const sqlQuerySpec: SqlQuerySpec = {
 98 |         query: query,
 99 |       };
100 |       const { resources: items } = await this.productsContainer.items.query(sqlQuerySpec).fetchAll();
101 | 
102 |       const duration = Date.now() - startTime;
103 |       console.debug(`[${sourceFile}] getProducts: ${duration} ms`);
104 | 
105 |       return {
106 |         data: items,
107 |         statusCode: 200,
108 |         duration: duration,
109 |       };
110 |     } catch (error) {
111 |       return {
112 |         error: "Error fetching products from Cosmos DB: " + error,
113 |         statusCode: 500,
114 |       };
115 |     }
116 |   }
117 | 
118 |   async createOrder(cart: Cart) {
119 |     const startTime = Date.now();
120 |     try {
121 |       const order = {
122 |         id: Date.now().toString(),
123 |         items: cart.items,
124 |         userName: cart.userName,
125 |         total: cart.items.reduce((sum, item) => sum + item.price * item.quantity, 0),
126 |         status: "completed",
127 |         createdAt: new Date().toISOString(),
128 |       };
129 | 
130 |       const { resource } = await this.ordersContainer.items.create(order);
131 | 
132 |       const duration = Date.now() - startTime;
133 |       console.debug(`[${sourceFile}] createOrder: ${duration} ms`);
134 | 
135 |       return {
136 |         data: resource,
137 |         statusCode: 200,
138 |         duration: duration,
139 |       };
140 |     } catch (error) {
141 |       return {
142 |         error: "Error creating order in Cosmos DB: " + error,
143 |         statusCode: 500,
144 |       };
145 |     }
146 |   }
147 | }
148 | 
149 | // Create a singleton instance
150 | export const cosmosDBService = new CosmosDBService();
151 | 
```

--------------------------------------------------------------------------------
/nextjs/components/ui/alert-dialog.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | 'use client';
  2 | 
  3 | import * as React from 'react';
  4 | import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
  5 | 
  6 | import { cn } from '@/lib/utils';
  7 | import { buttonVariants } from '@/components/ui/button';
  8 | 
  9 | const AlertDialog = AlertDialogPrimitive.Root;
 10 | 
 11 | const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
 12 | 
 13 | const AlertDialogPortal = AlertDialogPrimitive.Portal;
 14 | 
 15 | const AlertDialogOverlay = React.forwardRef<
 16 |   React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
 17 |   React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
 18 | >(({ className, ...props }, ref) => (
 19 |   <AlertDialogPrimitive.Overlay
 20 |     className={cn(
 21 |       'fixed inset-0 z-50 bg-black/80  data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
 22 |       className
 23 |     )}
 24 |     {...props}
 25 |     ref={ref}
 26 |   />
 27 | ));
 28 | AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
 29 | 
 30 | const AlertDialogContent = React.forwardRef<
 31 |   React.ElementRef<typeof AlertDialogPrimitive.Content>,
 32 |   React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
 33 | >(({ className, ...props }, ref) => (
 34 |   <AlertDialogPortal>
 35 |     <AlertDialogOverlay />
 36 |     <AlertDialogPrimitive.Content
 37 |       ref={ref}
 38 |       className={cn(
 39 |         'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
 40 |         className
 41 |       )}
 42 |       {...props}
 43 |     />
 44 |   </AlertDialogPortal>
 45 | ));
 46 | AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
 47 | 
 48 | const AlertDialogHeader = ({
 49 |   className,
 50 |   ...props
 51 | }: React.HTMLAttributes<HTMLDivElement>) => (
 52 |   <div
 53 |     className={cn(
 54 |       'flex flex-col space-y-2 text-center sm:text-left',
 55 |       className
 56 |     )}
 57 |     {...props}
 58 |   />
 59 | );
 60 | AlertDialogHeader.displayName = 'AlertDialogHeader';
 61 | 
 62 | const AlertDialogFooter = ({
 63 |   className,
 64 |   ...props
 65 | }: React.HTMLAttributes<HTMLDivElement>) => (
 66 |   <div
 67 |     className={cn(
 68 |       'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
 69 |       className
 70 |     )}
 71 |     {...props}
 72 |   />
 73 | );
 74 | AlertDialogFooter.displayName = 'AlertDialogFooter';
 75 | 
 76 | const AlertDialogTitle = React.forwardRef<
 77 |   React.ElementRef<typeof AlertDialogPrimitive.Title>,
 78 |   React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
 79 | >(({ className, ...props }, ref) => (
 80 |   <AlertDialogPrimitive.Title
 81 |     ref={ref}
 82 |     className={cn('text-lg font-semibold', className)}
 83 |     {...props}
 84 |   />
 85 | ));
 86 | AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
 87 | 
 88 | const AlertDialogDescription = React.forwardRef<
 89 |   React.ElementRef<typeof AlertDialogPrimitive.Description>,
 90 |   React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
 91 | >(({ className, ...props }, ref) => (
 92 |   <AlertDialogPrimitive.Description
 93 |     ref={ref}
 94 |     className={cn('text-sm text-muted-foreground', className)}
 95 |     {...props}
 96 |   />
 97 | ));
 98 | AlertDialogDescription.displayName =
 99 |   AlertDialogPrimitive.Description.displayName;
100 | 
101 | const AlertDialogAction = React.forwardRef<
102 |   React.ElementRef<typeof AlertDialogPrimitive.Action>,
103 |   React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
104 | >(({ className, ...props }, ref) => (
105 |   <AlertDialogPrimitive.Action
106 |     ref={ref}
107 |     className={cn(buttonVariants(), className)}
108 |     {...props}
109 |   />
110 | ));
111 | AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
112 | 
113 | const AlertDialogCancel = React.forwardRef<
114 |   React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
115 |   React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
116 | >(({ className, ...props }, ref) => (
117 |   <AlertDialogPrimitive.Cancel
118 |     ref={ref}
119 |     className={cn(
120 |       buttonVariants({ variant: 'outline' }),
121 |       'mt-2 sm:mt-0',
122 |       className
123 |     )}
124 |     {...props}
125 |   />
126 | ));
127 | AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
128 | 
129 | export {
130 |   AlertDialog,
131 |   AlertDialogPortal,
132 |   AlertDialogOverlay,
133 |   AlertDialogTrigger,
134 |   AlertDialogContent,
135 |   AlertDialogHeader,
136 |   AlertDialogFooter,
137 |   AlertDialogTitle,
138 |   AlertDialogDescription,
139 |   AlertDialogAction,
140 |   AlertDialogCancel,
141 | };
142 | 
```
Page 1/2FirstPrevNextLast