Skip to content

Commit 710e980

Browse files
committed
Setup UI for example captures edit mode
1 parent b3eda7d commit 710e980

File tree

6 files changed

+125
-42
lines changed

6 files changed

+125
-42
lines changed

ui/src/components/header/user-info-dialog/user-info-image-upload/user-info-image-upload.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ export const UserInfoImageUpload = ({
4040
accept={FileInputAccept.Images}
4141
label={imageUrl ? 'Change image' : 'Choose image'}
4242
name="user-image"
43-
onChange={onChange}
43+
withClear
44+
onChange={(files) => onChange(files ? files[0] : null)}
4445
/>
4546
</>
4647
)

ui/src/design-system/components/file-input/file-input.tsx

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,19 @@ interface FileInputProps {
1212
accept?: FileInputAccept
1313
label?: string
1414
loading?: boolean
15+
multiple?: boolean
1516
name: string
16-
onChange: (file: File | null) => void
17+
withClear?: boolean
18+
onChange: (files: FileList | null) => void
1719
}
1820

1921
export const FileInput = ({
2022
accept = FileInputAccept.All,
2123
label = 'Choose file',
2224
loading,
25+
multiple,
2326
name,
27+
withClear,
2428
onChange,
2529
}: FileInputProps) => {
2630
const inputRef = useRef<HTMLInputElement>(null)
@@ -32,29 +36,32 @@ export const FileInput = ({
3236
className={styles.fileInput}
3337
disabled={loading}
3438
id={name}
39+
multiple={multiple}
3540
name={name}
3641
ref={inputRef}
3742
type="file"
3843
onChange={(e) => {
39-
const file = e.currentTarget.files?.[0]
40-
if (!file) {
44+
const files = e.currentTarget.files
45+
if (!files?.length) {
4146
return
4247
}
43-
onChange(file)
48+
onChange(files)
4449
}}
4550
/>
4651
<label htmlFor={name}>{!loading ? label : `${label}...`}</label>
47-
<Button
48-
label="Clear"
49-
theme={ButtonTheme.Plain}
50-
onClick={() => {
51-
if (inputRef.current) {
52-
inputRef.current.value = ''
53-
inputRef.current.files = null
54-
}
55-
onChange(null)
56-
}}
57-
/>
52+
{withClear && (
53+
<Button
54+
label="Clear"
55+
theme={ButtonTheme.Plain}
56+
onClick={() => {
57+
if (inputRef.current) {
58+
inputRef.current.value = ''
59+
inputRef.current.files = null
60+
}
61+
onChange(null)
62+
}}
63+
/>
64+
)}
5865
</div>
5966
)
6067
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
@import 'design-system/variables/variables.scss';
2+
@import 'design-system/variables/colors.scss';
3+
@import 'design-system/variables/typography.scss';
4+
5+
.collection {
6+
display: grid;
7+
grid-template-columns: 1fr 1fr 1fr;
8+
gap: 16px;
9+
}
10+
11+
.card {
12+
background-color: $color-primary-2-50;
13+
width: 100%;
14+
border: 1px solid $color-neutral-100;
15+
border-radius: 4px;
16+
box-sizing: border-box;
17+
position: relative;
18+
overflow: hidden;
19+
}
20+
21+
.cardContent {
22+
position: absolute;
23+
width: 100%;
24+
height: 100%;
25+
display: flex;
26+
align-items: center;
27+
justify-content: center;
28+
29+
img {
30+
width: 100%;
31+
height: 100%;
32+
object-fit: contain;
33+
}
34+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { DeploymentDetails } from 'data-services/models/deployment-details'
2+
import { FileInput } from 'design-system/components/file-input/file-input'
3+
import { FileInputAccept } from 'design-system/components/file-input/types'
4+
import { InputContent } from 'design-system/components/input/input'
5+
import { ReactNode, useEffect, useState } from 'react'
6+
import styles from './section-example-captures.module.scss'
7+
8+
const IMAGE_CONFIG = {
9+
MAX_SIZE: 1024 * 1024, // 1MB
10+
NUM_IMAGES: 12,
11+
RATIO: 16 / 9,
12+
}
13+
14+
export const SectionExampleCaptures = ({
15+
deployment,
16+
}: {
17+
deployment: DeploymentDetails
18+
}) => {
19+
const [files, setFiles] = useState<File[]>([])
20+
21+
return (
22+
<InputContent
23+
label="Example captures"
24+
description={`Upload a maximum of ${IMAGE_CONFIG.NUM_IMAGES} images. Valid formats are PNG, GIF and JPEG.`}
25+
>
26+
<div className={styles.collection}>
27+
{deployment.exampleCaptures.map((exampelCapture, index) => (
28+
<Card key={index}>
29+
<img src={exampelCapture.src} />
30+
</Card>
31+
))}
32+
{files.map((file, index) => (
33+
<Card key={index}>
34+
<img src={URL.createObjectURL(file)} />
35+
</Card>
36+
))}
37+
<Card>
38+
<FileInput
39+
accept={FileInputAccept.Images}
40+
label="Choose images"
41+
multiple
42+
name="example-captures"
43+
onChange={(newFiles) => {
44+
setFiles([...files, ...Array.from(newFiles ?? [])])
45+
}}
46+
/>
47+
</Card>
48+
</div>
49+
</InputContent>
50+
)
51+
}
52+
53+
const Card = ({ children }: { children: ReactNode }) => (
54+
<div
55+
className={styles.card}
56+
style={{
57+
paddingBottom: `${(1 / IMAGE_CONFIG.RATIO) * 100}%`,
58+
}}
59+
>
60+
<div className={styles.cardContent}>{children}</div>
61+
</div>
62+
)

ui/src/pages/deployment-details/deployment-details-form/section-source-images/section-source-images.tsx

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,7 @@ import {
99
DeploymentFieldValues,
1010
} from 'data-services/models/deployment-details'
1111
import { Button } from 'design-system/components/button/button'
12-
import { ImageCarousel } from 'design-system/components/image-carousel/image-carousel'
13-
import { InputValue } from 'design-system/components/input/input'
1412
import _ from 'lodash'
15-
import { Status } from 'pages/deployment-details/connection-status/types'
1613
import { useContext } from 'react'
1714
import { useForm } from 'react-hook-form'
1815
import { FormContext } from 'utils/formContext/formContext'
@@ -21,8 +18,8 @@ import { STRING, translate } from 'utils/language'
2118
import { useSyncSectionStatus } from 'utils/useSyncSectionStatus'
2219
import { ConnectionStatus } from '../../connection-status/connection-status'
2320
import { useConnectionStatus } from '../../connection-status/useConnectionStatus'
24-
import styles from '../../styles.module.scss'
2521
import { config } from '../config'
22+
import { SectionExampleCaptures } from '../section-example-captures/section-example-captures'
2623
import { Section } from '../types'
2724

2825
type SectionSourceImagesFieldValues = Pick<DeploymentFieldValues, 'path'>
@@ -71,26 +68,7 @@ export const SectionSourceImages = ({
7168
lastUpdated={lastUpdated}
7269
/>
7370
</FormRow>
74-
{status === Status.Connected ? (
75-
<>
76-
<FormRow>
77-
<InputValue
78-
label={translate(STRING.FIELD_LABEL_CAPTURES)}
79-
value={deployment.numImages}
80-
/>
81-
<InputValue
82-
label={translate(STRING.FIELD_LABEL_EXAMPLE_CAPTURES)}
83-
value={deployment.exampleCaptures.length}
84-
/>
85-
</FormRow>
86-
<div className={styles.exampleCapturesContainer}>
87-
<ImageCarousel
88-
images={deployment.exampleCaptures}
89-
size={{ width: '100%', ratio: 16 / 9 }}
90-
/>
91-
</div>
92-
</>
93-
) : null}
71+
<SectionExampleCaptures deployment={deployment} />
9472
</FormSection>
9573
<FormActions>
9674
<Button label={translate(STRING.BACK)} onClick={onBack} />

ui/src/pages/project-details/project-image-upload/project-image-upload.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ export const ProjectImageUpload = ({
3434
<FileInput
3535
accept={FileInputAccept.Images}
3636
label={imageUrl ? 'Change image' : 'Choose image'}
37-
name="image"
38-
onChange={onChange}
37+
name="project-image"
38+
withClear
39+
onChange={(files) => onChange(files ? files[0] : null)}
3940
/>
4041
</>
4142
)

0 commit comments

Comments
 (0)