forked from syntaxbullet/aurorabot
refactor: Abbreviate item rarity values from full names to single-letter codes across the application.
This commit is contained in:
@@ -23,7 +23,7 @@ export const renderWizard = (userId: string, isDraft = true) => {
|
|||||||
draft = {
|
draft = {
|
||||||
name: "New Item",
|
name: "New Item",
|
||||||
description: "No description",
|
description: "No description",
|
||||||
rarity: "Common",
|
rarity: "C",
|
||||||
type: ItemType.MATERIAL,
|
type: ItemType.MATERIAL,
|
||||||
price: null,
|
price: null,
|
||||||
iconUrl: "",
|
iconUrl: "",
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export const getDetailsModal = (current: DraftItem) => {
|
|||||||
modal.addComponents(
|
modal.addComponents(
|
||||||
new ActionRowBuilder<TextInputBuilder>().addComponents(new TextInputBuilder().setCustomId("name").setLabel("Name").setValue(current.name).setStyle(TextInputStyle.Short).setRequired(true)),
|
new ActionRowBuilder<TextInputBuilder>().addComponents(new TextInputBuilder().setCustomId("name").setLabel("Name").setValue(current.name).setStyle(TextInputStyle.Short).setRequired(true)),
|
||||||
new ActionRowBuilder<TextInputBuilder>().addComponents(new TextInputBuilder().setCustomId("desc").setLabel("Description").setValue(current.description).setStyle(TextInputStyle.Paragraph).setRequired(false)),
|
new ActionRowBuilder<TextInputBuilder>().addComponents(new TextInputBuilder().setCustomId("desc").setLabel("Description").setValue(current.description).setStyle(TextInputStyle.Paragraph).setRequired(false)),
|
||||||
new ActionRowBuilder<TextInputBuilder>().addComponents(new TextInputBuilder().setCustomId("rarity").setLabel("Rarity").setValue(current.rarity).setStyle(TextInputStyle.Short).setPlaceholder("Common, Rare, Legendary...").setRequired(true))
|
new ActionRowBuilder<TextInputBuilder>().addComponents(new TextInputBuilder().setCustomId("rarity").setLabel("Rarity").setValue(current.rarity).setStyle(TextInputStyle.Short).setPlaceholder("C, R, SR, SSR").setRequired(true))
|
||||||
);
|
);
|
||||||
return modal;
|
return modal;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export const items = pgTable('items', {
|
|||||||
id: serial('id').primaryKey(),
|
id: serial('id').primaryKey(),
|
||||||
name: varchar('name', { length: 255 }).unique().notNull(),
|
name: varchar('name', { length: 255 }).unique().notNull(),
|
||||||
description: text('description'),
|
description: text('description'),
|
||||||
rarity: varchar('rarity', { length: 20 }).default('Common'),
|
rarity: varchar('rarity', { length: 20 }).default('C'),
|
||||||
|
|
||||||
// Economy & Visuals
|
// Economy & Visuals
|
||||||
type: varchar('type', { length: 50 }).notNull().default('MATERIAL'),
|
type: varchar('type', { length: 50 }).notNull().default('MATERIAL'),
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import type { ItemType } from "@shared/lib/constants";
|
|||||||
export interface CreateItemDTO {
|
export interface CreateItemDTO {
|
||||||
name: string;
|
name: string;
|
||||||
description?: string | null;
|
description?: string | null;
|
||||||
rarity?: 'Common' | 'Uncommon' | 'Rare' | 'Epic' | 'Legendary';
|
rarity?: 'C' | 'R' | 'SR' | 'SSR';
|
||||||
type: 'MATERIAL' | 'CONSUMABLE' | 'EQUIPMENT' | 'QUEST';
|
type: 'MATERIAL' | 'CONSUMABLE' | 'EQUIPMENT' | 'QUEST';
|
||||||
price?: bigint | null;
|
price?: bigint | null;
|
||||||
iconUrl: string;
|
iconUrl: string;
|
||||||
@@ -27,7 +27,7 @@ export interface CreateItemDTO {
|
|||||||
export interface UpdateItemDTO {
|
export interface UpdateItemDTO {
|
||||||
name?: string;
|
name?: string;
|
||||||
description?: string | null;
|
description?: string | null;
|
||||||
rarity?: 'Common' | 'Uncommon' | 'Rare' | 'Epic' | 'Legendary';
|
rarity?: 'C' | 'R' | 'SR' | 'SSR';
|
||||||
type?: 'MATERIAL' | 'CONSUMABLE' | 'EQUIPMENT' | 'QUEST';
|
type?: 'MATERIAL' | 'CONSUMABLE' | 'EQUIPMENT' | 'QUEST';
|
||||||
price?: bigint | null;
|
price?: bigint | null;
|
||||||
iconUrl?: string;
|
iconUrl?: string;
|
||||||
@@ -122,7 +122,7 @@ export const itemsService = {
|
|||||||
.values({
|
.values({
|
||||||
name: data.name,
|
name: data.name,
|
||||||
description: data.description ?? null,
|
description: data.description ?? null,
|
||||||
rarity: data.rarity ?? 'Common',
|
rarity: data.rarity ?? 'C',
|
||||||
type: data.type,
|
type: data.type,
|
||||||
price: data.price ?? null,
|
price: data.price ?? null,
|
||||||
iconUrl: data.iconUrl,
|
iconUrl: data.iconUrl,
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import { Loader2, Coins, FileText, Image, Zap } from "lucide-react";
|
|||||||
const itemFormSchema = z.object({
|
const itemFormSchema = z.object({
|
||||||
name: z.string().min(1, "Name is required").max(255, "Name is too long"),
|
name: z.string().min(1, "Name is required").max(255, "Name is too long"),
|
||||||
description: z.string().optional().nullable(),
|
description: z.string().optional().nullable(),
|
||||||
rarity: z.enum(["Common", "Uncommon", "Rare", "Epic", "Legendary"]),
|
rarity: z.enum(["C", "R", "SR", "SSR"]),
|
||||||
type: z.enum(["MATERIAL", "CONSUMABLE", "EQUIPMENT", "QUEST"]),
|
type: z.enum(["MATERIAL", "CONSUMABLE", "EQUIPMENT", "QUEST"]),
|
||||||
price: z.string().optional().nullable(),
|
price: z.string().optional().nullable(),
|
||||||
consume: z.boolean(),
|
consume: z.boolean(),
|
||||||
@@ -62,11 +62,10 @@ const ITEM_TYPES = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const RARITIES = [
|
const RARITIES = [
|
||||||
{ value: "Common", label: "Common" },
|
{ value: "C", label: "C" },
|
||||||
{ value: "Uncommon", label: "Uncommon" },
|
{ value: "R", label: "R" },
|
||||||
{ value: "Rare", label: "Rare" },
|
{ value: "SR", label: "SR" },
|
||||||
{ value: "Epic", label: "Epic" },
|
{ value: "SSR", label: "SSR" },
|
||||||
{ value: "Legendary", label: "Legendary" },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export function ItemForm({ initialData, onSuccess, onCancel }: ItemFormProps) {
|
export function ItemForm({ initialData, onSuccess, onCancel }: ItemFormProps) {
|
||||||
@@ -81,7 +80,7 @@ export function ItemForm({ initialData, onSuccess, onCancel }: ItemFormProps) {
|
|||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: "",
|
name: "",
|
||||||
description: "",
|
description: "",
|
||||||
rarity: "Common" as const,
|
rarity: "C" as const,
|
||||||
type: "MATERIAL" as const,
|
type: "MATERIAL" as const,
|
||||||
price: "",
|
price: "",
|
||||||
consume: false,
|
consume: false,
|
||||||
@@ -95,7 +94,7 @@ export function ItemForm({ initialData, onSuccess, onCancel }: ItemFormProps) {
|
|||||||
form.reset({
|
form.reset({
|
||||||
name: initialData.name,
|
name: initialData.name,
|
||||||
description: initialData.description || "",
|
description: initialData.description || "",
|
||||||
rarity: (initialData.rarity as FormValues["rarity"]) || "Common",
|
rarity: (initialData.rarity as FormValues["rarity"]) || "C",
|
||||||
type: (initialData.type as FormValues["type"]) || "MATERIAL",
|
type: (initialData.type as FormValues["type"]) || "MATERIAL",
|
||||||
price: initialData.price ? String(initialData.price) : "",
|
price: initialData.price ? String(initialData.price) : "",
|
||||||
consume: initialData.usageData?.consume ?? false,
|
consume: initialData.usageData?.consume ?? false,
|
||||||
|
|||||||
@@ -31,11 +31,10 @@ const ITEM_TYPES = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const RARITIES = [
|
const RARITIES = [
|
||||||
{ value: "Common", label: "Common", color: "text-zinc-400" },
|
{ value: "C", label: "C", color: "text-zinc-400" },
|
||||||
{ value: "Uncommon", label: "Uncommon", color: "text-green-400" },
|
{ value: "R", label: "R", color: "text-blue-400" },
|
||||||
{ value: "Rare", label: "Rare", color: "text-blue-400" },
|
{ value: "SR", label: "SR", color: "text-purple-400" },
|
||||||
{ value: "Epic", label: "Epic", color: "text-purple-400" },
|
{ value: "SSR", label: "SSR", color: "text-amber-400" },
|
||||||
{ value: "Legendary", label: "Legendary", color: "text-amber-400" },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export function ItemsFilter({ filters, onFilterChange, onClearFilters }: ItemsFilterProps) {
|
export function ItemsFilter({ filters, onFilterChange, onClearFilters }: ItemsFilterProps) {
|
||||||
|
|||||||
@@ -85,9 +85,9 @@ export function ItemsTable({
|
|||||||
case 'type':
|
case 'type':
|
||||||
return direction * (a.type || '').localeCompare(b.type || '');
|
return direction * (a.type || '').localeCompare(b.type || '');
|
||||||
case 'rarity': {
|
case 'rarity': {
|
||||||
const rarityOrder = ['Common', 'Uncommon', 'Rare', 'Epic', 'Legendary'];
|
const rarityOrder = ['C', 'R', 'SR', 'SSR'];
|
||||||
const aIndex = rarityOrder.indexOf(a.rarity || 'Common');
|
const aIndex = rarityOrder.indexOf(a.rarity || 'C');
|
||||||
const bIndex = rarityOrder.indexOf(b.rarity || 'Common');
|
const bIndex = rarityOrder.indexOf(b.rarity || 'C');
|
||||||
return direction * (aIndex - bIndex);
|
return direction * (aIndex - bIndex);
|
||||||
}
|
}
|
||||||
case 'price': {
|
case 'price': {
|
||||||
@@ -280,7 +280,7 @@ export function ItemsTable({
|
|||||||
|
|
||||||
{/* Rarity (hidden on mobile) */}
|
{/* Rarity (hidden on mobile) */}
|
||||||
<div className="hidden md:block">
|
<div className="hidden md:block">
|
||||||
<RarityBadge rarity={item.rarity || 'Common'} size="sm" />
|
<RarityBadge rarity={item.rarity || 'C'} size="sm" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Price (hidden on mobile) */}
|
{/* Price (hidden on mobile) */}
|
||||||
@@ -297,7 +297,7 @@ export function ItemsTable({
|
|||||||
|
|
||||||
{/* Mobile: badges */}
|
{/* Mobile: badges */}
|
||||||
<div className="flex md:hidden items-center gap-2">
|
<div className="flex md:hidden items-center gap-2">
|
||||||
<RarityBadge rarity={item.rarity || 'Common'} size="sm" />
|
<RarityBadge rarity={item.rarity || 'C'} size="sm" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Actions */}
|
{/* Actions */}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export type Rarity = 'Common' | 'Uncommon' | 'Rare' | 'Epic' | 'Legendary';
|
export type Rarity = 'C' | 'R' | 'SR' | 'SSR';
|
||||||
|
|
||||||
interface RarityBadgeProps {
|
interface RarityBadgeProps {
|
||||||
rarity: Rarity | string;
|
rarity: Rarity | string;
|
||||||
@@ -14,23 +14,19 @@ interface RarityBadgeProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const rarityStyles: Record<Rarity, { bg: string; text: string; glow?: string }> = {
|
const rarityStyles: Record<Rarity, { bg: string; text: string; glow?: string }> = {
|
||||||
Common: {
|
C: {
|
||||||
bg: 'bg-zinc-600/30',
|
bg: 'bg-zinc-600/30',
|
||||||
text: 'text-zinc-300',
|
text: 'text-zinc-300',
|
||||||
},
|
},
|
||||||
Uncommon: {
|
R: {
|
||||||
bg: 'bg-emerald-600/30',
|
|
||||||
text: 'text-emerald-400',
|
|
||||||
},
|
|
||||||
Rare: {
|
|
||||||
bg: 'bg-blue-600/30',
|
bg: 'bg-blue-600/30',
|
||||||
text: 'text-blue-400',
|
text: 'text-blue-400',
|
||||||
},
|
},
|
||||||
Epic: {
|
SR: {
|
||||||
bg: 'bg-purple-600/30',
|
bg: 'bg-purple-600/30',
|
||||||
text: 'text-purple-400',
|
text: 'text-purple-400',
|
||||||
},
|
},
|
||||||
Legendary: {
|
SSR: {
|
||||||
bg: 'bg-amber-600/30',
|
bg: 'bg-amber-600/30',
|
||||||
text: 'text-amber-400',
|
text: 'text-amber-400',
|
||||||
glow: 'shadow-[0_0_10px_rgba(251,191,36,0.4)]',
|
glow: 'shadow-[0_0_10px_rgba(251,191,36,0.4)]',
|
||||||
@@ -44,7 +40,7 @@ const sizeStyles = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function RarityBadge({ rarity, className, size = 'md' }: RarityBadgeProps) {
|
export function RarityBadge({ rarity, className, size = 'md' }: RarityBadgeProps) {
|
||||||
const validRarity = (rarity in rarityStyles ? rarity : 'Common') as Rarity;
|
const validRarity = (rarity in rarityStyles ? rarity : 'C') as Rarity;
|
||||||
const styles = rarityStyles[validRarity];
|
const styles = rarityStyles[validRarity];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export interface ItemsResponse {
|
|||||||
export interface CreateItemData {
|
export interface CreateItemData {
|
||||||
name: string;
|
name: string;
|
||||||
description?: string | null;
|
description?: string | null;
|
||||||
rarity?: 'Common' | 'Uncommon' | 'Rare' | 'Epic' | 'Legendary';
|
rarity?: 'C' | 'R' | 'SR' | 'SSR';
|
||||||
type: 'MATERIAL' | 'CONSUMABLE' | 'EQUIPMENT' | 'QUEST';
|
type: 'MATERIAL' | 'CONSUMABLE' | 'EQUIPMENT' | 'QUEST';
|
||||||
price?: string | null;
|
price?: string | null;
|
||||||
iconUrl?: string;
|
iconUrl?: string;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ let mockItems: MockItem[] = [
|
|||||||
id: 1,
|
id: 1,
|
||||||
name: "Health Potion",
|
name: "Health Potion",
|
||||||
description: "Restores health",
|
description: "Restores health",
|
||||||
rarity: "Common",
|
rarity: "C",
|
||||||
type: "CONSUMABLE",
|
type: "CONSUMABLE",
|
||||||
price: 100n,
|
price: 100n,
|
||||||
iconUrl: "/assets/items/1.png",
|
iconUrl: "/assets/items/1.png",
|
||||||
@@ -39,7 +39,7 @@ let mockItems: MockItem[] = [
|
|||||||
id: 2,
|
id: 2,
|
||||||
name: "Iron Sword",
|
name: "Iron Sword",
|
||||||
description: "A basic sword",
|
description: "A basic sword",
|
||||||
rarity: "Uncommon",
|
rarity: "R",
|
||||||
type: "EQUIPMENT",
|
type: "EQUIPMENT",
|
||||||
price: 500n,
|
price: 500n,
|
||||||
iconUrl: "/assets/items/2.png",
|
iconUrl: "/assets/items/2.png",
|
||||||
@@ -96,7 +96,7 @@ mock.module("@shared/modules/items/items.service", () => ({
|
|||||||
id: mockIdCounter++,
|
id: mockIdCounter++,
|
||||||
name: data.name,
|
name: data.name,
|
||||||
description: data.description ?? null,
|
description: data.description ?? null,
|
||||||
rarity: data.rarity ?? "Common",
|
rarity: data.rarity ?? "C",
|
||||||
type: data.type,
|
type: data.type,
|
||||||
price: data.price ?? null,
|
price: data.price ?? null,
|
||||||
iconUrl: data.iconUrl,
|
iconUrl: data.iconUrl,
|
||||||
@@ -154,7 +154,7 @@ describe("Items API", () => {
|
|||||||
id: 1,
|
id: 1,
|
||||||
name: "Health Potion",
|
name: "Health Potion",
|
||||||
description: "Restores health",
|
description: "Restores health",
|
||||||
rarity: "Common",
|
rarity: "C",
|
||||||
type: "CONSUMABLE",
|
type: "CONSUMABLE",
|
||||||
price: 100n,
|
price: 100n,
|
||||||
iconUrl: "/assets/items/1.png",
|
iconUrl: "/assets/items/1.png",
|
||||||
@@ -165,7 +165,7 @@ describe("Items API", () => {
|
|||||||
id: 2,
|
id: 2,
|
||||||
name: "Iron Sword",
|
name: "Iron Sword",
|
||||||
description: "A basic sword",
|
description: "A basic sword",
|
||||||
rarity: "Uncommon",
|
rarity: "R",
|
||||||
type: "EQUIPMENT",
|
type: "EQUIPMENT",
|
||||||
price: 500n,
|
price: 500n,
|
||||||
iconUrl: "/assets/items/2.png",
|
iconUrl: "/assets/items/2.png",
|
||||||
@@ -217,11 +217,11 @@ describe("Items API", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("should filter items by rarity", async () => {
|
test("should filter items by rarity", async () => {
|
||||||
const response = await fetch(`${baseUrl}/api/items?rarity=Common`);
|
const response = await fetch(`${baseUrl}/api/items?rarity=C`);
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
|
|
||||||
const data = (await response.json()) as { items: MockItem[]; total: number };
|
const data = (await response.json()) as { items: MockItem[]; total: number };
|
||||||
expect(data.items.every((item) => item.rarity === "Common")).toBe(true);
|
expect(data.items.every((item) => item.rarity === "C")).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -255,7 +255,7 @@ describe("Items API", () => {
|
|||||||
const newItem = {
|
const newItem = {
|
||||||
name: "Magic Staff",
|
name: "Magic Staff",
|
||||||
description: "A powerful staff",
|
description: "A powerful staff",
|
||||||
rarity: "Rare",
|
rarity: "SR",
|
||||||
type: "EQUIPMENT",
|
type: "EQUIPMENT",
|
||||||
price: "1000",
|
price: "1000",
|
||||||
iconUrl: "/assets/items/placeholder.png",
|
iconUrl: "/assets/items/placeholder.png",
|
||||||
|
|||||||
Reference in New Issue
Block a user