-
Notifications
You must be signed in to change notification settings - Fork 528
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
wip(web/actionModal): ids tab and partial info tab
- Loading branch information
Showing
9 changed files
with
370 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { txToast } from "@/components/TxToaster"; | ||
import { cn, copyToClipboard } from "@/lib/utils"; | ||
import { CopyIcon } from "lucide-react"; | ||
import { useState } from "react"; | ||
import { DatabaseActionType } from "../../../../core/components/PlayerDatabase/databaseTypes"; | ||
|
||
|
||
type IdsBlockProps = { | ||
title: string, | ||
emptyMessage: string, | ||
ids: string[] | undefined, | ||
isSmaller?: boolean, | ||
} | ||
function IdsBlock({ title, emptyMessage, ids, isSmaller }: IdsBlockProps) { | ||
const [hasCopiedIds, setHasCopiedIds] = useState(false); | ||
|
||
const handleCopyIds = () => { | ||
if(!ids) return; | ||
copyToClipboard(ids.join('\n')).then((res) => { | ||
if (res !== false) { | ||
setHasCopiedIds(true); | ||
} else { | ||
txToast.error('Failed to copy to clipboard :('); | ||
} | ||
}).catch((error) => { | ||
txToast.error({ | ||
title: 'Failed to copy to clipboard:', | ||
msg: error.message, | ||
}); | ||
}); | ||
} | ||
|
||
return <div> | ||
<div className="flex justify-between items-center pb-1"> | ||
<h3 className="text-xl">{title}</h3> | ||
{/* {hasCopiedIds ? ( | ||
<span className="text-sm text-success-inline">Copied!</span> | ||
) : ( | ||
// TODO: a button to erase the ids from the database can be added here, | ||
// requires tooltip and confirm modal though | ||
<button onClick={handleCopyIds}> | ||
<CopyIcon className="h-4 text-secondary hover:text-primary" /> | ||
</button> | ||
)} */} | ||
</div> | ||
<p className={cn( | ||
"font-mono break-all whitespace-pre-wrap border rounded divide-y divide-border/50 text-muted-foreground", | ||
isSmaller ? "text-2xs leading-5 font-extralight tracking-widest" : "text-xs leading-6 tracking-wider" | ||
)}> | ||
{!Array.isArray(ids) || ids.length === 0 && <span className="block px-1 opacity-50 italic">{emptyMessage}</span>} | ||
{ids!.map((id) => ( | ||
<span key={id} className="block px-1 font-semibold">{id}</span> | ||
))} | ||
</p> | ||
</div> | ||
} | ||
|
||
|
||
export default function ActionIdsTab({ action }: { action: DatabaseActionType }) { | ||
return <div className="flex flex-col gap-4 p-1"> | ||
<IdsBlock | ||
title="Target Identifiers" | ||
emptyMessage="This action targets no identifiers." | ||
ids={action.ids} | ||
/> | ||
<IdsBlock | ||
title="Target Hardware IDs" | ||
emptyMessage="This action targets no hardware IDs." | ||
ids={action.hwids} | ||
isSmaller | ||
/> | ||
</div>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { Button } from "@/components/ui/button"; | ||
import { Label } from "@/components/ui/label"; | ||
import { Textarea } from "@/components/ui/textarea"; | ||
import { tsToLocaleDateTime } from "@/lib/utils"; | ||
import { useRef, useState } from "react"; | ||
import { DatabaseActionType } from "../../../../core/components/PlayerDatabase/databaseTypes"; | ||
import { useOpenPlayerModal } from "@/hooks/playerModal"; | ||
|
||
|
||
|
||
const calcTextAreaLines = (text?: string) => { | ||
if (!text) return 3; | ||
const lines = text.trim().split('\n').length + 1; | ||
return Math.min(Math.max(lines, 3), 16); | ||
} | ||
|
||
function ActionReasonBox({ actionReason }: { actionReason: string }) { | ||
const textAreaRef = useRef<HTMLTextAreaElement>(null); | ||
const [textAreaLines, setTextAreaLines] = useState(calcTextAreaLines(actionReason)); | ||
|
||
return <> | ||
<Label htmlFor="playerNotes"> | ||
Reason: | ||
</Label> | ||
<Textarea | ||
ref={textAreaRef} | ||
id="playerNotes" | ||
className="w-full mt-1" | ||
readOnly={true} | ||
value={actionReason} | ||
//1rem of padding + 1.25rem per line | ||
style={{ height: `${1 + 1.25 * textAreaLines}rem` }} | ||
/> | ||
</> | ||
} | ||
|
||
|
||
type ActionInfoTabProps = { | ||
actionId: string; | ||
action: DatabaseActionType; | ||
setSelectedTab: (t: string) => void; | ||
refreshModalData: () => void; | ||
} | ||
|
||
export default function ActionInfoTab({ actionId, action, setSelectedTab, refreshModalData }: ActionInfoTabProps) { | ||
const actionDateTimeText = tsToLocaleDateTime(action.timestamp); | ||
const openPlayerModal = useOpenPlayerModal(); | ||
|
||
const targetLicenses = action.ids.filter(id => id.startsWith('license:')); | ||
const linkedPlayer = targetLicenses.length === 1 ? targetLicenses[0].split(':')[1] : false; | ||
const handleViewPlayerClick = () => { | ||
if (!linkedPlayer) return; | ||
openPlayerModal({ license: linkedPlayer }); | ||
} | ||
|
||
return <div className="p-1"> | ||
<dl className="pb-2"> | ||
<div className="py-0.5 grid grid-cols-3 gap-4 px-0"> | ||
<dt className="text-sm font-medium leading-6 text-muted-foreground">Date/Time</dt> | ||
<dd className="text-sm leading-6 col-span-2 mt-0">{actionDateTimeText}</dd> | ||
</div> | ||
<div className="py-0.5 grid grid-cols-3 gap-4 px-0"> | ||
<dt className="text-sm font-medium leading-6 text-muted-foreground">Admin</dt> | ||
<dd className="text-sm leading-6 col-span-2 mt-0">{action.author}</dd> | ||
</div> | ||
<div className="py-0.5 grid grid-cols-3 gap-4 px-0"> | ||
<dt className="text-sm font-medium leading-6 text-muted-foreground">Player</dt> | ||
<dd className="text-sm leading-6 col-span-2x mt-0">{action.playerName}</dd> | ||
<dd className="text-right"> | ||
<Button | ||
variant="outline" | ||
size='inline' | ||
style={{ minWidth: '8.25ch' }} | ||
onClick={handleViewPlayerClick} | ||
disabled={!linkedPlayer} | ||
> | ||
View | ||
</Button> | ||
</dd> | ||
</div> | ||
<div className="py-0.5 grid grid-cols-3 gap-4 px-0"> | ||
<dt className="text-sm font-medium leading-6 text-muted-foreground">Status</dt> | ||
<dd className="text-sm leading-6 col-span-2 mt-0">FIXME:</dd> | ||
</div> | ||
|
||
</dl> | ||
|
||
<ActionReasonBox actionReason={action.reason} /> | ||
</div>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.