Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
48 changes: 48 additions & 0 deletions apps/stardew.app/src/components/cards/card-quick-actions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { IconPlus } from "@tabler/icons-react";

import { usePlayers } from "@/contexts/players-context";

import { cn } from "@/lib/utils";

import { Button, type ButtonProps } from "@/components/ui/button";

interface CardQuickActionsProps {
addLabel: string;
onAdd: () => void;
className?: string;
disabled?: boolean;
variant?: ButtonProps["variant"];
size?: ButtonProps["size"];
}

export const CardQuickActions = ({
addLabel,
onAdd,
className,
disabled = false,
variant = "outline",
size = "icon",
}: CardQuickActionsProps) => {
const { activePlayer } = usePlayers();

if (!activePlayer) return null;

return (
<Button
aria-label={addLabel}
disabled={disabled}
size={size}
type="button"
variant={variant}
className={cn(
"flex-shrink-0 rounded-lg text-neutral-950 dark:text-neutral-50",
className,
)}
onClick={() => {
onAdd();
}}
>
<IconPlus className="h-4 w-4" />
</Button>
);
};
108 changes: 66 additions & 42 deletions apps/stardew.app/src/components/cards/shipping-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { usePlayers } from "@/contexts/players-context";
import { CreatePlayerRedirect } from "@/components/createPlayerRedirect";
import { NewItemBadge } from "@/components/new-item-badge";
import { Button } from "@/components/ui/button";
import { CardQuickActions } from "@/components/cards/card-quick-actions";
import {
Dialog,
DialogContent,
Expand Down Expand Up @@ -88,69 +89,92 @@ export const ShippingCard = ({ item, show, setPromptOpen }: Props) => {
const iconURL = `https://cdn.stardew.app/images/(O)${item.itemID}.webp`;
const name = objects[item.itemID as keyof typeof objects].name;
const description = objects[item.itemID as keyof typeof objects].description;
const isNewItemHidden =
item.minVersion === "1.6.0" && !show && _status < 1;

async function handleSave() {
async function updateShippedCount(nextCount: number) {
if (!activePlayer) return;

// don't make any requests if the value hasn't changed
if (value === _count || value < 0) {
setOpen(false);
return;
}

const patch = {
shipping: {
shipped: {
[item.itemID]: value === 0 ? null : value,
[item.itemID]: nextCount === 0 ? null : nextCount,
},
},
};

await patchPlayer(patch);
}

async function handleSave() {
// don't make any requests if the value hasn't changed
if (value === _count || value < 0) {
setOpen(false);
return;
}

await updateShippedCount(value);
setOpen(false);
}

async function incrementShippedCount() {
if (isNewItemHidden) {
setPromptOpen?.(true);
return;
}

await updateShippedCount(_count + 1);
}
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<div
className={cn(
"relative flex select-none items-center justify-between rounded-lg border px-5 py-4 text-left text-neutral-950 shadow-sm transition-colors hover:cursor-pointer dark:text-neutral-50",
classes[_status],
)}
onClick={(e) => {
if (item.minVersion === "1.6.0" && !show && _status < 1) {
e.preventDefault();
setPromptOpen?.(true);
return;
}
}}
>
{item.minVersion === "1.6.0" && (
<NewItemBadge version={item.minVersion} />
)}
<div className="flex w-full items-center gap-2">
<DialogTrigger asChild>
<div
className={cn(
"flex items-center space-x-3 truncate text-left",
item.minVersion === "1.6.0" && !show && _status < 1 && "blur-sm",
"relative flex min-w-0 flex-1 select-none items-center justify-between rounded-lg border px-5 py-4 text-left text-neutral-950 shadow-sm transition-colors hover:cursor-pointer dark:text-neutral-50",
classes[_status],
)}
onClick={(e) => {
if (isNewItemHidden) {
e.preventDefault();
setPromptOpen?.(true);
}
}}
>
<Image
src={iconURL}
alt={name}
className="rounded-sm"
width={32}
height={32}
/>
<div className="min-w-0 flex-1 pr-3">
<p className="truncate font-medium">{`${name} (${_count}x)`}</p>
<p className="truncate text-sm text-neutral-500 dark:text-neutral-400">
{description}
</p>
{item.minVersion === "1.6.0" && (
<NewItemBadge version={item.minVersion} />
)}
<div
className={cn(
"flex items-center space-x-3 truncate text-left",
isNewItemHidden && "blur-sm",
)}
>
<Image
src={iconURL}
alt={name}
className="rounded-sm"
width={32}
height={32}
/>
<div className="min-w-0 flex-1 pr-3">
<p className="truncate font-medium">{`${name} (${_count}x)`}</p>
<p className="truncate text-sm text-neutral-500 dark:text-neutral-400">
{description}
</p>
</div>
</div>
<IconChevronRight className="h-5 w-5 flex-shrink-0 text-neutral-500 dark:text-neutral-400" />
</div>
<IconChevronRight className="h-5 w-5 flex-shrink-0 text-neutral-500 dark:text-neutral-400" />
</div>
</DialogTrigger>
</DialogTrigger>
<CardQuickActions
addLabel={`Increment ${name} shipped count`}
className={classes[_status]}
onAdd={() => {
incrementShippedCount();
}}
/>
</div>
<DialogContent>
<DialogHeader>
<Image
Expand Down