Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/api/devices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,27 @@ export const unpairDevice = async (dongleId: string) =>
method: 'POST',
})

export const shareDevice = async (dongleId: string, email: string) =>
fetcher<{ success: number }>(`/v1/devices/${dongleId}/add_user`, {
method: 'POST',
body: JSON.stringify({ email: email }),
headers: {
'Content-Type': 'application/json',
},
})

export const unshareDevice = async (dongleId: string, email: string) =>
fetcher<{ success: number }>(`/v1/devices/${dongleId}/del_user`, {
method: 'POST',
body: JSON.stringify({ email: email }),
headers: {
'Content-Type': 'application/json',
},
})

export const getDeviceUsers = async (dongleId: string): Promise<{ email: string; permission: string }[]> =>
fetcher<{ email: string; permission: string }[]>(`/v1/devices/${dongleId}/users`)

const validatePairToken = (
input: string,
): {
Expand Down
2 changes: 1 addition & 1 deletion src/components/material/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const Icons = [
'add', 'arrow_back', 'camera', 'check', 'chevron_right', 'clear', 'close', 'delete', 'description', 'directions_car', 'download', 'error',
'file_copy', 'flag', 'info', 'keyboard_arrow_down', 'keyboard_arrow_up', 'local_fire_department', 'logout', 'menu', 'my_location',
'open_in_new', 'payments', 'person', 'progress_activity', 'satellite_alt', 'search', 'settings', 'upload', 'videocam', 'refresh',
'login', 'person_off', 'autorenew', 'close_small', 'pause', 'play_arrow', 'clear_all',
'login', 'person_off', 'autorenew', 'close_small', 'pause', 'play_arrow', 'clear_all', 'share'
] as const

export type IconName = (typeof Icons)[number]
Expand Down
56 changes: 54 additions & 2 deletions src/pages/dashboard/activities/SettingsActivity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Accessor, VoidComponent, Setter, ParentComponent, Resource, JSXEle
import { useLocation } from '@solidjs/router'
import clsx from 'clsx'

import { getDevice, unpairDevice } from '~/api/devices'
import { getDevice, getDeviceUsers, shareDevice, unpairDevice, unshareDevice } from '~/api/devices'
import {
cancelSubscription,
getStripeCheckout,
Expand All @@ -22,6 +22,7 @@ import IconButton from '~/components/material/IconButton'
import TopAppBar from '~/components/material/TopAppBar'
import { createQuery } from '~/utils/createQuery'
import { getDeviceName } from '~/utils/device'
import TextField from '~/components/material/TextField'

const useAction = <T,>(action: () => Promise<T>): [() => void, Resource<T>] => {
const [source, setSource] = createSignal(false)
Expand Down Expand Up @@ -401,15 +402,66 @@ const PrimeManage: VoidComponent<{ dongleId: string }> = (props) => {

const DeviceSettingsForm: VoidComponent<{ dongleId: string; device: Resource<Device> }> = (props) => {
const [deviceName] = createResource(props.device, getDeviceName)

const [deviceUsers, { refetch: refetchDeviceUsers }] = createResource(props.dongleId, getDeviceUsers)
const [shareEmail, setShareEmail] = createSignal('')
const [unpair, unpairData] = useAction(async () => {
const { success } = await unpairDevice(props.dongleId)
if (success) window.location.href = window.location.origin
})
const [share, shareData] = useAction(async () => {
updateShareEmail()
const { success } = await shareDevice(props.dongleId, shareEmail())
if (success) refetchDeviceUsers()
clearShareEmail()
})

const updateShareEmail = () => {
const emailBox = document.getElementById('email-box') as HTMLInputElement
setShareEmail(emailBox.value)
}

const clearShareEmail = () => {
const emailBox = document.getElementById('email-box') as HTMLInputElement
emailBox.value = ''
setShareEmail('')
}

const [unshareLoading, setUnshareLoading] = createSignal(false)

const unshare = async (email: string) => {
setUnshareLoading(true)
const { success } = await unshareDevice(props.dongleId, email)
if (success) refetchDeviceUsers()
setUnshareLoading(false)
}

return (
<div class="flex flex-col gap-4">
<h2 class="text-lg">{deviceName()}</h2>
<Show when={props.device()?.is_owner}>
<div class="flex flex-col gap-2">
<h3 class="text-md">{(deviceUsers() || []).length - 1 > 0 ? 'shared with:' : 'share device'}</h3>
<For each={deviceUsers()} fallback={<div>loading</div>}>
{(user, _index) => (
<Show when={user.permission !== 'owner'}>
<div class="flex items-center gap-2">
<div>{user.email}</div>
<Button color="error" leading={<Icon name="delete" />} onClick={() => unshare(user.email)} loading={unshareLoading()}>
Remove
</Button>
</div>
</Show>
)}
</For>
<div class="flex items-center gap-2">
<TextField placeholder="email" id="email-box" value={shareEmail()} />
<Button color="secondary" leading={<Icon name="share" />} onClick={share} loading={shareData.loading}>
Share
</Button>
</div>
</div>
</Show>

<Show when={unpairData.error}>
<div class="flex gap-2 rounded-sm bg-surface-container-high p-2 text-sm text-on-surface">
<Icon class="text-error" name="error" size="20" />
Expand Down