Skip to content

Commit

Permalink
dash: show user status
Browse files Browse the repository at this point in the history
  • Loading branch information
kiahjh committed Feb 19, 2025
1 parent 68f0f2a commit 38d18cc
Show file tree
Hide file tree
Showing 16 changed files with 290 additions and 106 deletions.
29 changes: 14 additions & 15 deletions dash/components/src/Computers/ComputerCard.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,34 @@
import React from 'react';
import cx from 'classnames';
import { Button } from '@shared/components';
import type { ChildComputerStatus } from '@dash/types';
import UserStatus from '../UserStatus';

interface Props {
name?: string;
id: string;
modelTitle: string;
modelIdentifier: string;
onlineUser?: string;
user?: {
name: string;
status: ChildComputerStatus;
};
}

const ComputerCard: React.FC<Props> = ({
name,
modelTitle,
onlineUser,
user,
modelIdentifier,
id,
}) => (
<div className="border-[0.5px] border-slate-200 rounded-3xl shadow-lg shadow-slate-300/50 bg-white">
<div className="p-6 flex justify-between items-center gap-4">
<div>
{user?.name && (
<h3 className="text-sm font-semibold text-slate-500">
{user.name} is using{!name && ` the`}
</h3>
)}
<h2 className="text-2xl font-bold">{name || modelTitle}</h2>
{name && <h3 className="text-sm text-slate-500">{modelTitle}</h3>}
</div>
Expand All @@ -31,18 +40,8 @@ const ComputerCard: React.FC<Props> = ({
/>
</div>
</div>
<div className="p-4 bg-slate-50 rounded-b-3xl flex justify-between items-center">
<div className="flex justify-end items-center gap-2 ml-2">
<div
className={cx(
`w-3 h-3 rounded-full`,
onlineUser ? `bg-green-400` : `bg-slate-100 shadow-inner`,
)}
/>
<span className="text-xs text-slate-400">
{onlineUser ? `${onlineUser} is online` : `offline`}
</span>
</div>
<div className="py-3 pl-3 pr-5 border-t border-slate-200 rounded-b-3xl flex justify-between items-center @container">
<UserStatus status={user?.status || { case: `offline` }} />
<Button type="link" to={`/computers/${id}`} color="tertiary" size="small">
<i className="fa-solid fa-pen mr-2" />
Edit
Expand Down
36 changes: 3 additions & 33 deletions dash/components/src/Computers/EditComputer.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React from 'react';
import cx from 'classnames';
import { Button, SelectMenu, TextInput } from '@shared/components';
import { Link } from 'react-router-dom';
import Badge from '@shared/components/src/Badge';
import type { ChildComputerStatus, ReleaseChannel } from '@dash/types';
import PageHeading from '../PageHeading';
import UserStatus from '../UserStatus';

interface Props {
name: string;
Expand Down Expand Up @@ -118,9 +117,9 @@ const EditComputer: React.FC<Props> = ({
</div>
<div className="border border-slate-200 mt-4 sm:mt-6 rounded-3xl bg-white p-6 sm:p-8">
<h3 className="text-xl font-bold text-slate-900">Children using this computer:</h3>
<div className="mt-6">
<div className="mt-4 flex flex-col gap-2">
{users.map((user) => (
<ComputerUser key={user.id} {...user} />
<UserStatus key={user.id} {...user} />
))}
</div>
</div>
Expand All @@ -142,32 +141,3 @@ const EditComputer: React.FC<Props> = ({
);

export default EditComputer;

interface ComputerUserProps {
name: string;
id: string;
status: ChildComputerStatus;
}

const ComputerUser: React.FC<ComputerUserProps> = ({ name, id, status }) => {
const isOnline = status.case !== `offline`;
return (
<Link
to={`/children/${id}`}
className="flex justify-between items-center odd:bg-slate-50 hover:bg-slate-100 transition-[background-color] duration-100 px-4 py-3 rounded-xl"
>
<h4 className="text-slate-700 font-semibold sm:text-lg">{name}</h4>
<div className="flex items-center gap-2">
<span className={cx(`text-sm`, isOnline ? `text-slate-600` : `text-slate-400`)}>
{isOnline ? `online` : `offline`}
</span>
<div
className={cx(
`w-3 h-3 rounded-full`,
isOnline ? `bg-green-400` : ` shadow-inner bg-slate-100`,
)}
/>
</div>
</Link>
);
};
2 changes: 1 addition & 1 deletion dash/components/src/Computers/ListComputers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const ListComputers: React.FC<Props> = ({ devices }) => (
id={device.id}
modelTitle={device.modelTitle}
modelIdentifier={device.modelIdentifier}
onlineUser={onlineUser?.name}
user={onlineUser}
/>
);
})}
Expand Down
4 changes: 2 additions & 2 deletions dash/components/src/Dashboard/UserActivityWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ const UserActivityWidget: React.FC<Props> = ({ userActivity, className }) => {
);

return (
<DashboardWidget className={cx(`!p-0 !sm:p-0`, className)}>
<div className="p-3 sm:p-4 pb-2 sm:pb-2">
<DashboardWidget className={cx(`!p-0 !sm:p-0 flex flex-col`, className)}>
<div className="p-3 sm:p-4 pb-2 sm:pb-2 flex-grow">
<WidgetTitle icon="binoculars" text="Activity" />
<div className="mb-4 flex flex-col space-y-2">
{writable(userActivity)
Expand Down
28 changes: 7 additions & 21 deletions dash/components/src/Dashboard/UsersOverviewWidget.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react';
import cx from 'classnames';
import { Button, Badge } from '@shared/components';
import { Button } from '@shared/components';
import type { GetDashboardWidgets } from '@dash/types';
import UserStatus from '../UserStatus';
import DashboardWidget from './DashboardWidget';
import WidgetTitle from './WidgetTitle';

Expand All @@ -22,9 +23,11 @@ const UsersOverview: React.FC<Props> = ({ className, users }) => {
All children
</Button>
</div>
{users.map((user) => (
<UserOverview key={user.id} {...user} />
))}
<div className="flex flex-col gap-2 @container">
{users.map((user) => (
<UserStatus key={user.id} {...user} />
))}
</div>
</DashboardWidget>
);
return (
Expand All @@ -45,20 +48,3 @@ const UsersOverview: React.FC<Props> = ({ className, users }) => {
};

export default UsersOverview;

const UserOverview: React.FC<User> = ({ status, name }) => (
<div className="flex justify-between items-center rounded-xl py-4 px-4 even:bg-slate-50/50">
<h3 className="font-medium text-slate-900">{name}</h3>
{status.case !== `offline` ? (
<Badge size="large" className="!px-4" type="green">
<i className="mr-2 fa-solid fa-circle text-green-400 text-sm scale-50" />
online
</Badge>
) : (
<Badge size="large" className="!px-4" type="yellow">
<i className="mr-2 fa-solid fa-circle text-yellow-400 text-sm scale-50" />
offline
</Badge>
)}
</div>
);
104 changes: 104 additions & 0 deletions dash/components/src/UserStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React from 'react';
import cx from 'classnames';
import { relativeTime } from '@dash/datetime';
import type { ChildComputerStatus } from '@dash/types';

interface Props {
name?: string;
status: ChildComputerStatus;
}

const UserStatus: React.FC<Props> = ({ status, name }) => {
const description: {
color: string;
gradient?: string;
primaryText: string;
secondaryText?: string;
} = (() => {
switch (status.case) {
case `filterSuspended`:
return {
color: `bg-yellow-500`,
gradient: `[background:radial-gradient(#eab30820_0%,transparent_70%)]`,
primaryText: `Filter suspended`,
secondaryText: status.resuming && `Resuming ${relativeTime(status.resuming)}`,
};
case `downtime`:
return {
color: `bg-purple-500`,
gradient: `[background:radial-gradient(#a855f720_0%,transparent_70%)]`,
primaryText: `In downtime`,
secondaryText: status.ending && `Ending ${relativeTime(status.ending)}`,
};
case `downtimePaused`:
return {
color: `bg-yellow-500`,
gradient: `[background:radial-gradient(#eab30820_0%,transparent_70%)]`,
primaryText: `Downtime paused`,
secondaryText: status.resuming && `Resuming ${relativeTime(status.resuming)}`,
};
case `offline`:
return {
color: `bg-slate-200`,
primaryText: `Offline`,
};
case `filterOff`:
return {
color: `bg-red-500`,
gradient: `[background:radial-gradient(#ef444420_0%,transparent_70%)]`,
primaryText: `Filter off`,
};
case `filterOn`:
return {
color: `bg-green-500`,
gradient: `[background:radial-gradient(#22c55e20_0%,transparent_70%)]`,
primaryText: `Filter on`,
};
}
})();

return (
<div
className={cx(
`border-[0.5px] border-slate-300 relative overflow-hidden bg-gradient-to-b from-white to-slate-50/50 shadow shadow-slate-300/30`,
name
? `px-4 py-2 rounded-2xl`
: `px-2 @sm:px-3 py-1.5 @sm:py-2 rounded-xl @sm:rounded-2xl`,
)}
>
<div
className={cx(
`w-[600px] h-40 absolute -left-[300px] -bottom-20`,
description.gradient,
)}
/>
{name && <h3 className="text-lg font-semibold">{name}</h3>}
<div
className={cx(
`flex`,
name ? `items-start gap-2` : `items-center gap-2 @sm:gap-3`,
)}
>
<div
className={cx(
`w-2 h-2 rounded-full shrink-0`,
description.color,
name && `mt-1.5`,
)}
/>
<div className="flex flex-col">
<span className="font-medium text-black/60 text-xs @sm:text-sm shrink-0 whitespace-nowrap">
{description.primaryText}
</span>
{description.secondaryText && (
<span className="text-[11px] @sm:text-xs text-black/40 leading-[1]">
{description.secondaryText}
</span>
)}
</div>
</div>
</div>
);
};

export default UserStatus;
12 changes: 4 additions & 8 deletions dash/components/src/Users/EditUser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import KeychainCard from '../Keychains/KeychainCard';
import { ConfirmDeleteEntity } from '../Modal';
import PageHeading from '../PageHeading';
import TimeInput from '../Forms/TimeInput';
import BetaBadge from '../BetaBadge';
import EmptyState from '../EmptyState';
import AddKeychainDrawer from './AddKeychainDrawer';
import ConnectDeviceModal from './ConnectDeviceModal';
Expand Down Expand Up @@ -207,7 +206,7 @@ const EditUser: React.FC<Props> = ({
<h2 className="mt-5 text-lg font-bold text-slate-700">
{devices.length} {inflect(`computer`, devices.length)}:
</h2>
<div className="flex flex-col max-w-3xl">
<div className="flex flex-col max-w-3xl -mx-2 xs:mx-0">
{devices.map((userDevice) => (
<div key={userDevice.id} className="flex items-center mt-3">
<UserDevice
Expand All @@ -217,11 +216,11 @@ const EditUser: React.FC<Props> = ({
deviceId={userDevice.deviceId}
name={userDevice.name}
status={userDevice.status}
className="flex-grow mr-3"
className="flex-grow mr-1 xs:mr-3"
/>
<button
onClick={() => deleteDevice.start(userDevice.id)}
className="transition-colors duration-100 flex justify-center items-center w-10 h-10 rounded-full hover:bg-slate-100 cursor-pointer text-slate-500 hover:text-red-500"
className="transition-colors duration-100 flex justify-center items-center w-6 xs:w-10 h-6 xs:h-10 rounded-full hover:bg-slate-200/50 cursor-pointer text-slate-500 hover:text-red-500"
>
<i className="fa fa-trash" />
</button>
Expand Down Expand Up @@ -351,10 +350,7 @@ const EditUser: React.FC<Props> = ({
{/* blocked apps */}
{blockedApps && (
<div className="mt-12 max-w-3xl mb-12">
<div className="flex items-center gap-2">
<h2 className="text-lg font-bold text-slate-700">Blocked apps{` `}</h2>
<BetaBadge />
</div>
<h2 className="text-lg font-bold text-slate-700">Blocked apps{` `}</h2>
{blockedApps.length === 0 ? (
<div className="flex flex-col items-center justify-center p-8 bg-slate-100 mt-2 rounded-2xl shadow-inner">
<NoSymbolIcon className="w-8 h-8 text-slate-300" strokeWidth={2} />
Expand Down
2 changes: 1 addition & 1 deletion dash/components/src/Users/ListUsers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const Users: React.FC<Props> = ({
<div className="mt-8 flex flex-col">
{users.length > 0 ? (
<>
<div className="mb-16 grid grid-cols-1 lg+:grid-cols-2 gap-10 lg+:gap-8 xl:gap-10 2xl:grid-cols-3">
<div className="mb-16 grid grid-cols-1 xl:grid-cols-2 gap-10 lg+:gap-8 xl:gap-10 2xl:grid-cols-3">
{users.map((user) => (
<UserCard
key={user.id}
Expand Down
4 changes: 2 additions & 2 deletions dash/components/src/Users/UserCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const UserCard: React.FC<Props> = ({
className="rounded-3xl border-[0.5px] border-slate-200 flex flex-col justify-between shadow-lg shadow-slate-300/50 bg-white sm:min-w-[400px]"
data-test="user-card"
>
<div className="p-6">
<div className="p-4 xs:p-6">
<div className="flex justify-between items-center">
<h2 className="text-3xl font-extrabold text-slate-700 mr-3">{name}</h2>
<div className="flex items-center space-x-4">
Expand Down Expand Up @@ -72,7 +72,7 @@ const UserCard: React.FC<Props> = ({
{inflect(`computer`, devices.length)}:
</p>
</div>
<div className="flex flex-col mt-3 space-y-3 pt-3">
<div className="flex flex-col mt-3 gap-3 pt-3">
{devices.map((userDevice) => (
<UserDevice
key={userDevice.id}
Expand Down
Loading

0 comments on commit 38d18cc

Please sign in to comment.