@seamapi/react 0.27.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/index.css +97 -0
  2. package/index.css.map +1 -1
  3. package/index.min.css +1 -1
  4. package/index.min.css.map +1 -1
  5. package/lib/capitalize.d.ts +1 -0
  6. package/lib/capitalize.js +4 -0
  7. package/lib/capitalize.js.map +1 -0
  8. package/lib/icons/ChevronDown.d.ts +2 -0
  9. package/lib/icons/ChevronDown.js +3 -0
  10. package/lib/icons/ChevronDown.js.map +1 -0
  11. package/lib/ui/Button.d.ts +4 -3
  12. package/lib/ui/Button.js +2 -2
  13. package/lib/ui/Button.js.map +1 -1
  14. package/lib/ui/SupportedDeviceTable/FilterCategoryMenu.d.ts +21 -0
  15. package/lib/ui/SupportedDeviceTable/FilterCategoryMenu.js +20 -0
  16. package/lib/ui/SupportedDeviceTable/FilterCategoryMenu.js.map +1 -0
  17. package/lib/ui/SupportedDeviceTable/SupportedDeviceContent.d.ts +4 -0
  18. package/lib/ui/SupportedDeviceTable/SupportedDeviceContent.js +53 -0
  19. package/lib/ui/SupportedDeviceTable/SupportedDeviceContent.js.map +1 -0
  20. package/lib/ui/SupportedDeviceTable/SupportedDeviceFilterArea.d.ts +11 -0
  21. package/lib/ui/SupportedDeviceTable/SupportedDeviceFilterArea.js +50 -0
  22. package/lib/ui/SupportedDeviceTable/SupportedDeviceFilterArea.js.map +1 -0
  23. package/lib/ui/SupportedDeviceTable/SupportedDeviceHeader.d.ts +1 -0
  24. package/lib/ui/{SupportedDevices/SupportedDevicesHeader.js → SupportedDeviceTable/SupportedDeviceHeader.js} +2 -2
  25. package/lib/ui/SupportedDeviceTable/SupportedDeviceHeader.js.map +1 -0
  26. package/lib/ui/{SupportedDevices → SupportedDeviceTable}/SupportedDeviceRow.d.ts +1 -1
  27. package/lib/ui/SupportedDeviceTable/SupportedDeviceRow.js.map +1 -0
  28. package/lib/ui/SupportedDeviceTable/SupportedDeviceTable.d.ts +3 -0
  29. package/lib/ui/SupportedDeviceTable/SupportedDeviceTable.js +8 -0
  30. package/lib/ui/SupportedDeviceTable/SupportedDeviceTable.js.map +1 -0
  31. package/lib/ui/{SupportedDevices → SupportedDeviceTable}/types.d.ts +5 -0
  32. package/lib/ui/SupportedDeviceTable/types.js.map +1 -0
  33. package/lib/ui/index.d.ts +1 -1
  34. package/lib/ui/index.js +1 -1
  35. package/lib/ui/index.js.map +1 -1
  36. package/package.json +1 -1
  37. package/src/lib/capitalize.ts +3 -0
  38. package/src/lib/icons/ChevronDown.tsx +19 -0
  39. package/src/lib/ui/Button.tsx +12 -6
  40. package/src/lib/ui/SupportedDeviceTable/FilterCategoryMenu.tsx +65 -0
  41. package/src/lib/ui/SupportedDeviceTable/SupportedDeviceContent.tsx +147 -0
  42. package/src/lib/ui/SupportedDeviceTable/SupportedDeviceFilterArea.tsx +131 -0
  43. package/src/lib/ui/{SupportedDevices/SupportedDevicesHeader.tsx → SupportedDeviceTable/SupportedDeviceHeader.tsx} +1 -1
  44. package/src/lib/ui/{SupportedDevices → SupportedDeviceTable}/SupportedDeviceRow.tsx +1 -1
  45. package/src/lib/ui/SupportedDeviceTable/SupportedDeviceTable.tsx +16 -0
  46. package/src/lib/ui/{SupportedDevices → SupportedDeviceTable}/types.ts +6 -0
  47. package/src/lib/ui/index.ts +1 -1
  48. package/src/styles/_supported-devices.scss +114 -0
  49. package/lib/ui/SupportedDevices/SupportedDeviceRow.js.map +0 -1
  50. package/lib/ui/SupportedDevices/SupportedDevices.d.ts +0 -1
  51. package/lib/ui/SupportedDevices/SupportedDevices.js +0 -21
  52. package/lib/ui/SupportedDevices/SupportedDevices.js.map +0 -1
  53. package/lib/ui/SupportedDevices/SupportedDevicesHeader.d.ts +0 -1
  54. package/lib/ui/SupportedDevices/SupportedDevicesHeader.js.map +0 -1
  55. package/lib/ui/SupportedDevices/types.js.map +0 -1
  56. package/src/lib/ui/SupportedDevices/SupportedDevices.tsx +0 -65
  57. /package/lib/ui/{SupportedDevices → SupportedDeviceTable}/SupportedDeviceRow.js +0 -0
  58. /package/lib/ui/{SupportedDevices → SupportedDeviceTable}/types.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/lib/ui/index.ts"],"names":[],"mappings":"AAAA,cAAc,0CAA0C,CAAA;AACxD,cAAc,sCAAsC,CAAA;AACpD,cAAc,kCAAkC,CAAA;AAChD,cAAc,8BAA8B,CAAA;AAC5C,cAAc,wCAAwC,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/lib/ui/index.ts"],"names":[],"mappings":"AAAA,cAAc,0CAA0C,CAAA;AACxD,cAAc,sCAAsC,CAAA;AACpD,cAAc,kCAAkC,CAAA;AAChD,cAAc,8BAA8B,CAAA;AAC5C,cAAc,gDAAgD,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seamapi/react",
3
- "version": "0.27.0",
3
+ "version": "1.1.0",
4
4
  "description": "Seam React component library.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -0,0 +1,3 @@
1
+ export function capitalize(str: string): string {
2
+ return str.charAt(0).toUpperCase() + str.slice(1)
3
+ }
@@ -0,0 +1,19 @@
1
+ import type { SVGProps } from 'react'
2
+ export const ChevronDownIcon = (
3
+ props: SVGProps<SVGSVGElement>
4
+ ): JSX.Element => (
5
+ <svg
6
+ xmlns='http://www.w3.org/2000/svg'
7
+ width={20}
8
+ height={20}
9
+ fill='none'
10
+ {...props}
11
+ >
12
+ <g mask='url(#chevron-down_svg__mask0_1045_100036)'>
13
+ <path
14
+ fill='#6E7179'
15
+ d='m10 12.813-5-5 1.167-1.167L10 10.479l3.833-3.833L15 7.813l-5 5Z'
16
+ />
17
+ </g>
18
+ </svg>
19
+ )
@@ -1,11 +1,12 @@
1
1
  import classNames from 'classnames'
2
+ import type { MouseEventHandler, PropsWithChildren } from 'react'
2
3
 
3
4
  interface ButtonProps {
4
- children?: string
5
5
  variant?: 'solid' | 'outline' | 'neutral'
6
6
  size?: 'small' | 'medium' | 'large'
7
7
  disabled?: boolean
8
- onClick?: () => void
8
+ onClick?: MouseEventHandler<HTMLButtonElement>
9
+ className?: string
9
10
  }
10
11
 
11
12
  export function Button({
@@ -14,12 +15,17 @@ export function Button({
14
15
  size = 'medium',
15
16
  disabled,
16
17
  onClick,
17
- }: ButtonProps): JSX.Element {
18
+ className,
19
+ }: PropsWithChildren<ButtonProps>): JSX.Element {
18
20
  return (
19
21
  <button
20
- className={classNames(`seam-btn seam-btn-${variant} seam-btn-${size}`, {
21
- 'seam-btn-disabled': disabled,
22
- })}
22
+ className={classNames(
23
+ `seam-btn seam-btn-${variant} seam-btn-${size}`,
24
+ {
25
+ 'seam-btn-disabled': disabled,
26
+ },
27
+ className
28
+ )}
23
29
  disabled={disabled}
24
30
  onClick={onClick}
25
31
  >
@@ -0,0 +1,65 @@
1
+ import { ChevronDownIcon } from 'lib/icons/ChevronDown.js'
2
+ import { Menu } from 'lib/ui/Menu/Menu.js'
3
+ import { MenuItem } from 'lib/ui/Menu/MenuItem.js'
4
+
5
+ interface FilterCategoryMenuBaseProps {
6
+ label: string
7
+ options: string[]
8
+ onSelect: (option: string) => void
9
+ buttonLabel?: string
10
+ }
11
+
12
+ export type FilterCategoryMenuProps =
13
+ | (FilterCategoryMenuBaseProps & {
14
+ addAllOption: true
15
+ onAllOptionSelect: () => void
16
+ })
17
+ | (FilterCategoryMenuBaseProps & {
18
+ addAllOption?: false
19
+ onAllOptionSelect?: never
20
+ })
21
+
22
+ export function FilterCategoryMenu({
23
+ label,
24
+ options,
25
+ addAllOption,
26
+ onSelect,
27
+ onAllOptionSelect,
28
+ buttonLabel,
29
+ }: FilterCategoryMenuProps) {
30
+ const usableOptions = addAllOption !== null ? ['All', ...options] : options
31
+
32
+ return (
33
+ <div className='seam-supported-devices-filter-menu-wrap'>
34
+ <p>{label}</p>
35
+ <Menu
36
+ renderButton={({ onOpen }) => (
37
+ <button onClick={onOpen}>
38
+ <span>{buttonLabel}</span>
39
+ <ChevronDownIcon />
40
+ </button>
41
+ )}
42
+ >
43
+ {usableOptions.map((option, index) => (
44
+ <MenuItem
45
+ key={`${index}:${option}`}
46
+ onClick={() => {
47
+ if (option === 'All') {
48
+ onAllOptionSelect?.()
49
+ } else {
50
+ onSelect(option)
51
+ }
52
+ }}
53
+ >
54
+ <span>{option}</span>
55
+ </MenuItem>
56
+ ))}
57
+ </Menu>
58
+ </div>
59
+ )
60
+ }
61
+
62
+ FilterCategoryMenu.defaultProps = {
63
+ addAllOption: true,
64
+ buttonLabel: 'Filter',
65
+ }
@@ -0,0 +1,147 @@
1
+ import { useQuery } from '@tanstack/react-query'
2
+ import axios from 'axios'
3
+ import { useCallback, useEffect, useState } from 'react'
4
+
5
+ import { Button } from 'lib/ui/Button.js'
6
+ import { SupportedDeviceFilterArea } from 'lib/ui/SupportedDeviceTable/SupportedDeviceFilterArea.js'
7
+ import type { DeviceModel, Filters } from 'lib/ui/SupportedDeviceTable/types.js'
8
+
9
+ import { SupportedDeviceHeader } from './SupportedDeviceHeader.js'
10
+ import { SupportedDeviceRow } from './SupportedDeviceRow.js'
11
+
12
+ const BASE_URL = 'https://devicedb.seam.co/api/device_models/list'
13
+
14
+ export interface SupportedDeviceContentProps {
15
+ cannotFilter?: boolean
16
+ }
17
+
18
+ export function SupportedDeviceContent({
19
+ cannotFilter = false,
20
+ }: SupportedDeviceContentProps) {
21
+ const [allDeviceModels, setAllDeviceModels] = useState<DeviceModel[]>([])
22
+ const [filterValue, setFilterValue] = useState('')
23
+ const [filters, setFilters] = useState<Filters>({
24
+ supportedOnly: false,
25
+ category: null,
26
+ brand: null,
27
+ })
28
+
29
+ const fetchDeviceModels = useCallback(async () => {
30
+ const queries = []
31
+
32
+ if (filterValue.trim() !== '') {
33
+ queries.push(`text_search=${encodeURIComponent(filterValue.trim())}`)
34
+ }
35
+
36
+ if (filters.supportedOnly) {
37
+ queries.push('support_level=live')
38
+ }
39
+
40
+ if (filters.category !== null) {
41
+ queries.push(`main_category=${encodeURIComponent(filters.category)}`)
42
+ }
43
+
44
+ if (filters.brand !== null) {
45
+ queries.push(`brand=${encodeURIComponent(filters.brand)}`)
46
+ }
47
+
48
+ const url = `${BASE_URL}?${queries.join('&')}`
49
+ return await axios.get(url)
50
+ }, [filterValue, filters])
51
+
52
+ const { data, isLoading, isError, refetch } = useQuery<{
53
+ data: {
54
+ device_models?: DeviceModel[]
55
+ }
56
+ }>({
57
+ queryKey: ['supported_devices', filterValue, filters],
58
+ queryFn: fetchDeviceModels,
59
+ })
60
+
61
+ useEffect(() => {
62
+ if (
63
+ data?.data?.device_models !== undefined &&
64
+ allDeviceModels.length === 0
65
+ ) {
66
+ setAllDeviceModels(data.data.device_models)
67
+ }
68
+ }, [data, allDeviceModels.length])
69
+
70
+ const deviceModels = data?.data?.device_models ?? []
71
+
72
+ return (
73
+ <div className='seam-supported-devices-table-wrap'>
74
+ {!cannotFilter && (
75
+ <SupportedDeviceFilterArea
76
+ deviceModels={allDeviceModels}
77
+ filterValue={filterValue}
78
+ setFilterValue={setFilterValue}
79
+ filters={filters}
80
+ setFilters={setFilters}
81
+ />
82
+ )}
83
+
84
+ {isLoading && (
85
+ <div className='seam-supported-devices-table-state-block'>
86
+ <p>Loading device models...</p>
87
+ </div>
88
+ )}
89
+
90
+ {isError && (
91
+ <div className='seam-supported-devices-table-state-block'>
92
+ <p>There was an error fetching device models.</p>
93
+ <Button
94
+ variant='solid'
95
+ size='small'
96
+ onClick={() => {
97
+ void refetch()
98
+ }}
99
+ >
100
+ Retry
101
+ </Button>
102
+ </div>
103
+ )}
104
+
105
+ {!isLoading && !isError && data?.data?.device_models !== null && (
106
+ <table className='seam-supported-devices-table'>
107
+ <SupportedDeviceHeader />
108
+ <tbody>
109
+ {deviceModels.length !== 0 &&
110
+ deviceModels.map((deviceModel, index) => (
111
+ <SupportedDeviceRow
112
+ key={`${index}:${deviceModel.manufacturer_model_id}`}
113
+ deviceModel={deviceModel}
114
+ />
115
+ ))}
116
+
117
+ {deviceModels.length === 0 && (
118
+ <tr className='seam-supported-devices-table-message-row'>
119
+ <td colSpan={6}>
120
+ <div className='seam-supported-devices-table-message'>
121
+ {filterValue.length === 0 ? (
122
+ <p>No device models found.</p>
123
+ ) : (
124
+ <>
125
+ <p>No device models matched your search.</p>
126
+ <Button
127
+ variant='outline'
128
+ size='small'
129
+ onClick={() => {
130
+ setFilterValue('')
131
+ }}
132
+ className='seam-supported-devices-table-message-clear-search'
133
+ >
134
+ Clear search terms
135
+ </Button>
136
+ </>
137
+ )}
138
+ </div>
139
+ </td>
140
+ </tr>
141
+ )}
142
+ </tbody>
143
+ </table>
144
+ )}
145
+ </div>
146
+ )
147
+ }
@@ -0,0 +1,131 @@
1
+ import type { Dispatch, SetStateAction } from 'react'
2
+
3
+ import { capitalize } from 'lib/capitalize.js'
4
+ import { Button } from 'lib/ui/Button.js'
5
+ import { Menu } from 'lib/ui/Menu/Menu.js'
6
+ import { FilterCategoryMenu } from 'lib/ui/SupportedDeviceTable/FilterCategoryMenu.js'
7
+ import type { DeviceModel, Filters } from 'lib/ui/SupportedDeviceTable/types.js'
8
+ import { SearchTextField } from 'lib/ui/TextField/SearchTextField.js'
9
+
10
+ interface SupportedDeviceFilterAreaProps {
11
+ deviceModels: DeviceModel[]
12
+ filterValue: string
13
+ setFilterValue: (filter: string) => void
14
+ filters: Filters
15
+ setFilters: Dispatch<SetStateAction<Filters>>
16
+ }
17
+
18
+ export function SupportedDeviceFilterArea({
19
+ deviceModels,
20
+ filterValue,
21
+ setFilterValue,
22
+ filters,
23
+ setFilters,
24
+ }: SupportedDeviceFilterAreaProps) {
25
+ const appliedFilters = Object.keys(filters).filter((key) => {
26
+ const filterProperty = filters[key as keyof Filters]
27
+ return (
28
+ filterProperty !== undefined &&
29
+ filterProperty !== null &&
30
+ filterProperty !== false
31
+ )
32
+ })
33
+ const appliedFiltersCount = appliedFilters.length
34
+
35
+ const getAvailablePropertiesFromDeviceModels = (
36
+ property: keyof DeviceModel
37
+ ) => {
38
+ const properties = new Set<string>()
39
+ deviceModels.forEach((deviceModel) => {
40
+ properties.add(capitalize(deviceModel[property]))
41
+ })
42
+ return Array.from(properties)
43
+ }
44
+
45
+ const resetFilter = (filterType: keyof Filters) => {
46
+ setFilters((filters) => ({
47
+ ...filters,
48
+ [filterType]: null,
49
+ }))
50
+ }
51
+
52
+ const isPlural = appliedFiltersCount > 1
53
+ const filterButtonLabel = isPlural
54
+ ? `Filters (${appliedFiltersCount})`
55
+ : 'Filter'
56
+
57
+ return (
58
+ <div className='seam-supported-devices-filter-area'>
59
+ <div className='seam-deliberate-block' />
60
+ <div className='seam-filters-wrap'>
61
+ <Menu
62
+ renderButton={({ onOpen }) => (
63
+ <Button
64
+ variant='outline'
65
+ className='seam-filters-button'
66
+ onClick={onOpen}
67
+ >
68
+ {filterButtonLabel}
69
+ </Button>
70
+ )}
71
+ >
72
+ <div
73
+ className='seam-supported-devices-filter-menu'
74
+ onClick={(event) => {
75
+ event.stopPropagation()
76
+ }}
77
+ >
78
+ <div className='seam-filter-menu-row'>
79
+ <FilterCategoryMenu
80
+ label='Brand'
81
+ options={getAvailablePropertiesFromDeviceModels('brand')}
82
+ onSelect={(brand: string) => {
83
+ setFilters((filters) => ({
84
+ ...filters,
85
+ brand,
86
+ }))
87
+ }}
88
+ buttonLabel={filters.brand ?? 'All'}
89
+ onAllOptionSelect={() => {
90
+ resetFilter('brand')
91
+ }}
92
+ />
93
+ </div>
94
+
95
+ <div className='seam-filter-menu-row'>
96
+ <label
97
+ htmlFor='supportedOnly'
98
+ className='seam-filter-checkbox-label'
99
+ >
100
+ <p>Supported</p>
101
+ <input
102
+ id='supportedOnly'
103
+ name='supportedOnly'
104
+ type='checkbox'
105
+ className='seam-filter-checkbox'
106
+ checked={filters.supportedOnly}
107
+ onChange={(event) => {
108
+ setFilters((filters) => ({
109
+ ...filters,
110
+ supportedOnly: event.target.checked,
111
+ }))
112
+ }}
113
+ />
114
+ </label>
115
+ </div>
116
+ </div>
117
+ </Menu>
118
+
119
+ <div className='seam-supported-devices-filter-area-search-bar-wrap'>
120
+ <SearchTextField
121
+ value={filterValue}
122
+ onChange={(value) => {
123
+ setFilterValue(value)
124
+ }}
125
+ className='seam-supported-devices-filter-area-search-bar'
126
+ />
127
+ </div>
128
+ </div>
129
+ </div>
130
+ )
131
+ }
@@ -1,4 +1,4 @@
1
- export function SupportedDevicesHeader() {
1
+ export function SupportedDeviceHeader() {
2
2
  return (
3
3
  <thead>
4
4
  <tr>
@@ -1,6 +1,6 @@
1
1
  import classNames from 'classnames'
2
2
 
3
- import type { DeviceModel } from 'lib/ui/SupportedDevices/types.js'
3
+ import type { DeviceModel } from 'lib/ui/SupportedDeviceTable/types.js'
4
4
 
5
5
  export interface SupportedDeviceRowProps {
6
6
  deviceModel: DeviceModel
@@ -0,0 +1,16 @@
1
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
2
+
3
+ import type { SupportedDeviceContentProps } from 'lib/ui/SupportedDeviceTable/SupportedDeviceContent.js'
4
+ import { SupportedDeviceContent } from 'lib/ui/SupportedDeviceTable/SupportedDeviceContent.js'
5
+
6
+ const client = new QueryClient()
7
+
8
+ export type SupportedDeviceTableProps = SupportedDeviceContentProps
9
+
10
+ export function SupportedDeviceTable(props: SupportedDeviceContentProps) {
11
+ return (
12
+ <QueryClientProvider client={client}>
13
+ <SupportedDeviceContent {...props} />
14
+ </QueryClientProvider>
15
+ )
16
+ }
@@ -8,3 +8,9 @@ export interface DeviceModel {
8
8
  icon_url: string
9
9
  seam_device_model_page_url: string
10
10
  }
11
+
12
+ export interface Filters {
13
+ supportedOnly: boolean
14
+ category: string | null
15
+ brand: string | null
16
+ }
@@ -2,4 +2,4 @@ export * from './AccessCodeDetails/AccessCodeDetails.js'
2
2
  export * from './AccessCodeTable/AccessCodeTable.js'
3
3
  export * from './DeviceDetails/DeviceDetails.js'
4
4
  export * from './DeviceTable/DeviceTable.js'
5
- export * from './SupportedDevices/SupportedDevices.js'
5
+ export * from './SupportedDeviceTable/SupportedDeviceTable.js'
@@ -3,6 +3,95 @@
3
3
  $row-padding: 8px;
4
4
 
5
5
  @mixin all {
6
+ .seam-supported-devices-filter-area {
7
+ width: 100%;
8
+ display: flex;
9
+ justify-content: space-between;
10
+ align-items: center;
11
+ flex-direction: row;
12
+ padding: 16px;
13
+
14
+ .seam-filters-wrap {
15
+ display: flex;
16
+ justify-content: flex-start;
17
+ align-items: center;
18
+ flex-direction: row;
19
+ gap: 8px;
20
+ }
21
+
22
+ .seam-supported-devices-filter-area-search-bar-wrap {
23
+ position: relative;
24
+ display: flex;
25
+ justify-content: center;
26
+ align-items: center;
27
+ flex-direction: row;
28
+ }
29
+ }
30
+
31
+ .seam-supported-devices-filter-menu {
32
+ width: 100%;
33
+ padding: 8px 16px;
34
+
35
+ .seam-filter-menu-row {
36
+ width: 100%;
37
+ display: flex;
38
+ justify-content: space-between;
39
+ align-items: center;
40
+ flex-direction: row;
41
+
42
+ &:not(:last-of-type) {
43
+ margin-bottom: 8px;
44
+ }
45
+
46
+ .seam-filter-checkbox-label {
47
+ width: 100%;
48
+ display: flex;
49
+ justify-content: space-between;
50
+ align-items: center;
51
+ flex-direction: row;
52
+ }
53
+
54
+ .seam-filter-checkbox {
55
+ appearance: checkbox;
56
+ }
57
+ }
58
+
59
+ .seam-supported-devices-filter-menu-wrap {
60
+ width: 100%;
61
+ display: flex;
62
+ justify-content: space-between;
63
+ align-items: center;
64
+ flex-direction: row;
65
+
66
+ & button {
67
+ appearance: none;
68
+ padding: 4px 8px;
69
+ padding-right: 24px;
70
+ margin: 0;
71
+ border: 0;
72
+ box-shadow: none;
73
+ border-radius: 4px;
74
+ background-color: colors.$bg-b;
75
+ position: relative;
76
+ cursor: pointer;
77
+
78
+ &:hover {
79
+ background-color: colors.$bg-c;
80
+ }
81
+
82
+ & span {
83
+ font-size: 14px;
84
+ font-weight: 500;
85
+ }
86
+
87
+ & svg {
88
+ position: absolute;
89
+ top: 2px;
90
+ }
91
+ }
92
+ }
93
+ }
94
+
6
95
  .seam-supported-devices-table-state-block {
7
96
  width: 100%;
8
97
  background-color: colors.$bg-a;
@@ -14,6 +103,31 @@ $row-padding: 8px;
14
103
  gap: 8px;
15
104
  }
16
105
 
106
+ .seam-supported-devices-table-message-row {
107
+ height: auto !important;
108
+ }
109
+
110
+ .seam-supported-devices-table-message {
111
+ width: 100%;
112
+ padding: 32px 0;
113
+ display: flex;
114
+ justify-content: center;
115
+ align-items: center;
116
+ flex-direction: column;
117
+ text-align: center;
118
+ gap: 4px;
119
+
120
+ & p {
121
+ line-height: 1;
122
+ margin: 0;
123
+ }
124
+
125
+ & button {
126
+ cursor: pointer;
127
+ margin-top: 8px;
128
+ }
129
+ }
130
+
17
131
  .seam-supported-devices-table {
18
132
  width: 100%;
19
133
  overflow-x: auto;
@@ -1 +0,0 @@
1
- {"version":3,"file":"SupportedDeviceRow.js","sourceRoot":"","sources":["../../../src/lib/ui/SupportedDevices/SupportedDeviceRow.tsx"],"names":[],"mappings":";AAAA,OAAO,UAAU,MAAM,YAAY,CAAA;AAQnC,MAAM,UAAU,kBAAkB,CAAC,EAAE,WAAW,EAA2B;IACzE,MAAM,WAAW,GAAG,kBAAkB,CAAC,WAAW,CAAC,aAAa,CAAC,IAAI,MAAM,CAAA;IAC3E,OAAO,CACL,yBACE,uBACE,cAAK,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,WAAW,CAAC,QAAQ,GAAI,GACrD,EACL,uBAAK,WAAW,CAAC,aAAa,GAAM,EACpC,uBAAK,WAAW,CAAC,UAAU,GAAM,EACjC,uBAAK,WAAW,CAAC,qBAAqB,GAAM,EAC5C,uBAAK,WAAW,CAAC,eAAe,GAAM,EACtC,uBACE,cACE,SAAS,EAAE,UAAU,CAAC,kBAAkB,EAAE,UAAU,WAAW,EAAE,CAAC,YAElE,yBAAO,WAAW,CAAC,aAAa,GAAQ,GACpC,GACH,IACF,CACN,CAAA;AACH,CAAC;AAED,MAAM,kBAAkB,GAAG;IACzB,IAAI,EAAE,OAAO;IACb,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,QAAQ;CACtB,CAAA"}
@@ -1 +0,0 @@
1
- export declare function SupportedDevices(): import("react/jsx-runtime").JSX.Element;
@@ -1,21 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useQuery } from '@tanstack/react-query';
3
- import axios from 'axios';
4
- import { Button } from '../../../lib/ui/Button.js';
5
- import { SupportedDeviceRow } from './SupportedDeviceRow.js';
6
- import { SupportedDevicesHeader } from './SupportedDevicesHeader.js';
7
- export function SupportedDevices() {
8
- const { data, isLoading, isError, refetch } = useQuery({
9
- queryKey: ['supported_devices'],
10
- queryFn: async () => {
11
- return await axios.get('https://devicedb.seam.co/api/device_models/list');
12
- },
13
- });
14
- return (_jsx(_Fragment, { children: _jsxs("div", { className: 'seam-supported-devices-table-wrap', children: [isLoading && (_jsx("div", { className: 'seam-supported-devices-table-state-block', children: _jsx("p", { children: "Loading device models..." }) })), isError && (_jsxs("div", { className: 'seam-supported-devices-table-state-block', children: [_jsx("p", { children: "There was an error fetching device models." }), _jsx(Button, { variant: 'solid', size: 'small', onClick: () => {
15
- void refetch();
16
- }, children: "Retry" })] })), !isLoading &&
17
- !isError &&
18
- data?.data?.device_models !== null &&
19
- Array.isArray(data?.data?.device_models) && (_jsxs("table", { className: 'seam-supported-devices-table', children: [_jsx(SupportedDevicesHeader, {}), _jsx("tbody", { children: data.data.device_models.map((deviceModel) => (_jsx(SupportedDeviceRow, { deviceModel: deviceModel }, deviceModel.manufacturer_model_id))) })] }))] }) }));
20
- }
21
- //# sourceMappingURL=SupportedDevices.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SupportedDevices.js","sourceRoot":"","sources":["../../../src/lib/ui/SupportedDevices/SupportedDevices.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAChD,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAGzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AAEpE,MAAM,UAAU,gBAAgB;IAC9B,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,QAAQ,CAInD;QACD,QAAQ,EAAE,CAAC,mBAAmB,CAAC;QAC/B,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,OAAO,MAAM,KAAK,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAA;QAC3E,CAAC;KACF,CAAC,CAAA;IAEF,OAAO,CACL,4BACE,eAAK,SAAS,EAAC,mCAAmC,aAC/C,SAAS,IAAI,CACZ,cAAK,SAAS,EAAC,0CAA0C,YACvD,mDAA+B,GAC3B,CACP,EAEA,OAAO,IAAI,CACV,eAAK,SAAS,EAAC,0CAA0C,aACvD,qEAAiD,EACjD,KAAC,MAAM,IACL,OAAO,EAAC,OAAO,EACf,IAAI,EAAC,OAAO,EACZ,OAAO,EAAE,GAAG,EAAE;gCACZ,KAAK,OAAO,EAAE,CAAA;4BAChB,CAAC,sBAGM,IACL,CACP,EAEA,CAAC,SAAS;oBACT,CAAC,OAAO;oBACR,IAAI,EAAE,IAAI,EAAE,aAAa,KAAK,IAAI;oBAClC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,aAAa,CAAC,IAAI,CAC1C,iBAAO,SAAS,EAAC,8BAA8B,aAC7C,KAAC,sBAAsB,KAAG,EAC1B,0BACG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAC5C,KAAC,kBAAkB,IAEjB,WAAW,EAAE,WAAW,IADnB,WAAW,CAAC,qBAAqB,CAEtC,CACH,CAAC,GACI,IACF,CACT,IACC,GACL,CACJ,CAAA;AACH,CAAC"}
@@ -1 +0,0 @@
1
- export declare function SupportedDevicesHeader(): import("react/jsx-runtime").JSX.Element;
@@ -1 +0,0 @@
1
- {"version":3,"file":"SupportedDevicesHeader.js","sourceRoot":"","sources":["../../../src/lib/ui/SupportedDevices/SupportedDevicesHeader.tsx"],"names":[],"mappings":";AAAA,MAAM,UAAU,sBAAsB;IACpC,OAAO,CACL,0BACE,yBACE,cAAM,EACN,oCAAiB,EACjB,sCAAmB,EACnB,iDAA8B,EAC9B,2CAAwB,EACxB,kCAAe,IACZ,GACC,CACT,CAAA;AACH,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/lib/ui/SupportedDevices/types.ts"],"names":[],"mappings":""}