Skip to content

Commit

Permalink
Fix small UI bugs after feedback (#401)
Browse files Browse the repository at this point in the history
* Fix email label in user info form

* Make user name required

* Highlight required fields

* Show plus in slideshow count if there are more items

* Include seconds in capture time label

* Show capture info all the time, not just on hover

* Show description as requires in project details form

* Show that saving was successful in user info form + setup shared constant for success timeout

* Do not show sign up if user is logged in

* Format code

* Fix overflowing timestamp

* Fix "not available" label bug
  • Loading branch information
annavik authored Jun 10, 2024
1 parent 936590f commit 1b4a707
Show file tree
Hide file tree
Showing 23 changed files with 90 additions and 75 deletions.
6 changes: 5 additions & 1 deletion ui/src/components/form/form-field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ export const FormField = <
<Input
{...field}
type={type}
label={fieldConfig.label}
label={
fieldConfig.rules?.required
? `${fieldConfig.label} *`
: fieldConfig.label
}
error={fieldState.error?.message}
description={fieldConfig.description}
onBlur={(e) => {
Expand Down
27 changes: 15 additions & 12 deletions ui/src/components/header/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,7 @@ export const Header = () => {
<InfoDialog key={page.id} name={page.name} slug={page.slug} />
))}
</div>
<Button
label={translate(STRING.SIGN_UP)}
theme={ButtonTheme.Plain}
onClick={() => navigate(APP_ROUTES.SIGN_UP)}
/>

{user.loggedIn ? (
<>
<Button
Expand All @@ -55,13 +51,20 @@ export const Header = () => {
<UserInfoDialog />
</>
) : (
<Button
label={translate(STRING.LOGIN)}
theme={ButtonTheme.Plain}
onClick={() =>
navigate(APP_ROUTES.LOGIN, { state: { to: location.pathname } })
}
/>
<>
<Button
label={translate(STRING.SIGN_UP)}
theme={ButtonTheme.Plain}
onClick={() => navigate(APP_ROUTES.SIGN_UP)}
/>
<Button
label={translate(STRING.LOGIN)}
theme={ButtonTheme.Plain}
onClick={() =>
navigate(APP_ROUTES.LOGIN, { state: { to: location.pathname } })
}
/>
</>
)}
</div>
</header>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,19 @@ import { STRING, translate } from 'utils/language'
import { useFormError } from 'utils/useFormError'
import { UserInfo } from 'utils/user/types'
import { UserInfoImageUpload } from '../user-info-image-upload/user-info-image-upload'
import { IconType } from 'design-system/components/icon/icon'

interface UserInfoFormValues {
name?: string
name: string
image?: File | null
}

const config: FormConfig = {
name: {
label: translate(STRING.FIELD_LABEL_NAME),
rules: {
required: true,
},
},
image: {
label: translate(STRING.FIELD_LABEL_ICON),
Expand Down Expand Up @@ -59,7 +63,7 @@ export const UserInfoForm = ({ userInfo }: { userInfo: UserInfo }) => {
},
mode: 'onChange',
})
const { updateUserInfo, isLoading, error } = useUpdateUserInfo()
const { updateUserInfo, error, isLoading, isSuccess } = useUpdateUserInfo()
const errorMessage = useFormError({ error, setFieldError })

return (
Expand All @@ -74,7 +78,7 @@ export const UserInfoForm = ({ userInfo }: { userInfo: UserInfo }) => {
<FormSection>
<FormRow>
<InputValue
label={translate(STRING.FIELD_LABEL_NAME)}
label={translate(STRING.FIELD_LABEL_EMAIL)}
value={userInfo.email}
/>
<InputValue
Expand Down Expand Up @@ -113,7 +117,8 @@ export const UserInfoForm = ({ userInfo }: { userInfo: UserInfo }) => {
</FormSection>
<FormActions>
<Button
label={translate(STRING.SAVE)}
label={isSuccess ? translate(STRING.SAVED) : translate(STRING.SAVE)}
icon={isSuccess ? IconType.RadixCheck : undefined}
type="submit"
theme={ButtonTheme.Success}
loading={isLoading}
Expand Down
2 changes: 2 additions & 0 deletions ui/src/data-services/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ export const API_ROUTES = {
export const STATUS_CODES = {
FORBIDDEN: 403,
}

export const SUCCESS_TIMEOUT = 1000 // Reset success after 1 second
5 changes: 3 additions & 2 deletions ui/src/data-services/hooks/auth/useUpdateUserInfo.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'
import axios from 'axios'
import { API_ROUTES, API_URL } from 'data-services/constants'
import { API_ROUTES, API_URL, SUCCESS_TIMEOUT } from 'data-services/constants'
import { getAuthHeader } from 'data-services/utils'
import { useUser } from 'utils/user/userContext'

export const useUpdateUserInfo = () => {
const { user } = useUser()
const queryClient = useQueryClient()

const { mutate, isLoading, error, isSuccess } = useMutation({
const { mutate, isLoading, isSuccess, reset, error } = useMutation({
mutationFn: (fieldValues: any) => {
const data = new FormData()
if (fieldValues.name) {
Expand All @@ -29,6 +29,7 @@ export const useUpdateUserInfo = () => {
},
onSuccess: () => {
queryClient.invalidateQueries([API_ROUTES.ME])
setTimeout(reset, SUCCESS_TIMEOUT)
},
})

Expand Down
4 changes: 1 addition & 3 deletions ui/src/data-services/hooks/entities/useCreateEntity.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'
import axios from 'axios'
import { API_URL } from 'data-services/constants'
import { API_URL, SUCCESS_TIMEOUT } from 'data-services/constants'
import { getAuthHeader } from 'data-services/utils'
import { useUser } from 'utils/user/userContext'
import { EntityFieldValues } from './types'
import { convertToServerFieldValues } from './utils'

const SUCCESS_TIMEOUT = 1000 // Reset success after 1 second

export const useCreateEntity = (collection: string, onSuccess?: () => void) => {
const { user } = useUser()
const queryClient = useQueryClient()
Expand Down
4 changes: 1 addition & 3 deletions ui/src/data-services/hooks/entities/useUpdateEntity.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'
import axios from 'axios'
import { API_URL } from 'data-services/constants'
import { API_URL, SUCCESS_TIMEOUT } from 'data-services/constants'
import { getAuthHeader } from 'data-services/utils'
import { useUser } from 'utils/user/userContext'
import { EntityFieldValues } from './types'
import { convertToServerFieldValues } from './utils'

const SUCCESS_TIMEOUT = 1000 // Reset success after 1 second

export const useUpdateEntity = (
id: string,
collection: string,
Expand Down
4 changes: 1 addition & 3 deletions ui/src/data-services/hooks/jobs/useCreateJob.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'
import axios from 'axios'
import { API_ROUTES, API_URL } from 'data-services/constants'
import { API_ROUTES, API_URL, SUCCESS_TIMEOUT } from 'data-services/constants'
import { getAuthHeader } from 'data-services/utils'
import { useUser } from 'utils/user/userContext'

const SUCCESS_TIMEOUT = 1000 // Reset success after 1 second

interface JobFieldValues {
delay?: number
name: string
Expand Down
4 changes: 1 addition & 3 deletions ui/src/data-services/hooks/projects/useCreateProject.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'
import axios from 'axios'
import { API_ROUTES, API_URL } from 'data-services/constants'
import { API_ROUTES, API_URL, SUCCESS_TIMEOUT } from 'data-services/constants'
import { getAuthHeader } from 'data-services/utils'
import { useUser } from 'utils/user/userContext'
import { convertToServerFormData } from './utils'

const SUCCESS_TIMEOUT = 1000 // Reset success after 1 second

export const useCreateProject = (onSuccess?: () => void) => {
const { user } = useUser()
const queryClient = useQueryClient()
Expand Down
4 changes: 1 addition & 3 deletions ui/src/data-services/hooks/projects/useUpdateProject.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'
import axios from 'axios'
import { API_ROUTES, API_URL } from 'data-services/constants'
import { API_ROUTES, API_URL, SUCCESS_TIMEOUT } from 'data-services/constants'
import { getAuthHeader } from 'data-services/utils'
import { useUser } from 'utils/user/userContext'
import { convertToServerFormData } from './utils'

const SUCCESS_TIMEOUT = 1000 // Reset success after 1 second

export const useUpdateProject = (id: string) => {
const { user } = useUser()
const queryClient = useQueryClient()
Expand Down
5 changes: 4 additions & 1 deletion ui/src/data-services/models/capture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,10 @@ export class Capture {
}

get timeLabel(): string {
return getFormatedTimeString({ date: new Date(this._capture.timestamp) })
return getFormatedTimeString({
date: new Date(this._capture.timestamp),
options: { second: true },
})
}

get width(): number {
Expand Down
1 change: 1 addition & 0 deletions ui/src/data-services/models/occurrence-details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export class OccurrenceDetails extends Occurrence {
label: label,
timeLabel: getFormatedTimeString({
date: new Date(detection.timestamp),
options: { second: true },
}),
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
.capture {
width: 100%;
display: grid;
grid-template-columns: 2fr 2fr 1fr;
grid-template-columns: 1fr 1fr 1fr;
align-items: center;
justify-content: flex-start;
gap: 16px;
Expand All @@ -16,10 +16,6 @@
color: $color-neutral-200;
box-sizing: border-box;

.numDetections {
opacity: 0;
}

.bar {
height: 8px;
width: 100%;
Expand All @@ -29,20 +25,12 @@
}

.timestamp {
opacity: 0;
text-align: right;
}

&:hover {
cursor: pointer;
opacity: 0.7;

.numDetections {
opacity: 1;
}

.timestamp {
opacity: 1;
}
}

&.empty {
Expand All @@ -54,16 +42,8 @@
&.active {
background-color: #383a3c;

.numDetections {
opacity: 1;
}

.bar {
background-color: $color-generic-white;
}

.timestamp {
opacity: 1;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const CaptureRow = ({
onClick,
}: {
capture: {
details: string
details?: string
scale: number
timeLabel: string
}
Expand All @@ -27,15 +27,13 @@ export const CaptureRow = ({
})}
onClick={onClick}
>
<div className={styles.numDetections}>{capture.details}</div>
<div className={styles.barContainer}>
<div
className={styles.bar}
style={{
width: `${capture.scale * 100}%`,
}}
/>
</div>
<div>{capture.details}</div>
<div
className={styles.bar}
style={{
width: `${capture.scale * 100}%`,
}}
/>
<div className={styles.timestamp}>{capture.timeLabel}</div>
</div>
)
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ interface ImageCarouselProps {
src: string
alt?: string
}[]
total?: number
size?: {
width: string | number
ratio: number
Expand All @@ -28,6 +29,7 @@ interface ImageCarouselProps {
export const ImageCarousel = ({
autoPlay,
images,
total,
size,
theme = CarouselTheme.Default,
to,
Expand All @@ -42,6 +44,7 @@ export const ImageCarousel = ({
<MultiImageCarousel
autoPlay={autoPlay}
images={images}
total={total}
size={size}
theme={theme}
to={to}
Expand Down Expand Up @@ -96,6 +99,7 @@ const DURATION = 10000 // Change image every 10 second
const MultiImageCarousel = ({
autoPlay,
images,
total,
size,
theme,
to,
Expand All @@ -106,6 +110,10 @@ const MultiImageCarousel = ({
const slideIndexRef = useRef(slideIndex)
const pausedRef = useRef(paused)

const totalLabel = total
? `${images.length}${images.length < total ? '+' : ''}`
: images.length

useEffect(() => {
if (!autoPlay) {
return
Expand Down Expand Up @@ -221,7 +229,7 @@ const MultiImageCarousel = ({
{slideIndex + 1} / {images.length}
</span>
) : (
<span>{images.length}</span>
<span>{totalLabel}</span>
)}
</>
</span>
Expand Down
6 changes: 4 additions & 2 deletions ui/src/design-system/components/info-block/info-block.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import classNames from 'classnames'
import { Link } from 'react-router-dom'
import { STRING } from 'utils/language'
import { STRING, translate } from 'utils/language'
import styles from './info-block.module.scss'

interface Field {
Expand All @@ -13,7 +13,9 @@ export const InfoBlock = ({ fields }: { fields: Field[] }) => (
<>
{fields.map((field, index) => {
const value =
field.value !== undefined ? field.value : STRING.VALUE_NOT_AVAILABLE
field.value === undefined
? translate(STRING.VALUE_NOT_AVAILABLE)
: field.value

return (
<p className={styles.field} key={index}>
Expand Down
Loading

0 comments on commit 1b4a707

Please sign in to comment.