Compare commits
7 commits
b06149cf22
...
c7cf1d2111
Author | SHA1 | Date | |
---|---|---|---|
c7cf1d2111 | |||
c13c6e7bd8 | |||
00bc9c3bf7 | |||
e2d8a86f79 | |||
3a76dbb368 | |||
453d6783c4 | |||
c60e222faa |
11 changed files with 117 additions and 55 deletions
|
@ -115,7 +115,7 @@ class OutfitsController < ApplicationController
|
||||||
|
|
||||||
def outfit_params
|
def outfit_params
|
||||||
params.require(:outfit).permit(
|
params.require(:outfit).permit(
|
||||||
:name, :starred, item_ids: {worn: [], closeted: []},
|
:name, :starred, :alt_style_id, item_ids: {worn: [], closeted: []},
|
||||||
biology: [:species_id, :color_id, :pose])
|
biology: [:species_id, :color_id, :pose])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ import {
|
||||||
useToast,
|
useToast,
|
||||||
useToken,
|
useToken,
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import { ChevronDownIcon } from "@chakra-ui/icons";
|
import { ChevronDownIcon, WarningTwoIcon } from "@chakra-ui/icons";
|
||||||
import { loadable } from "../util";
|
import { loadable } from "../util";
|
||||||
|
|
||||||
import { petAppearanceFragment } from "../components/useOutfitAppearance";
|
import { petAppearanceFragment } from "../components/useOutfitAppearance";
|
||||||
|
@ -42,6 +42,7 @@ import twemojiSunglasses from "../images/twemoji/sunglasses.svg";
|
||||||
import twemojiQuestion from "../images/twemoji/question.svg";
|
import twemojiQuestion from "../images/twemoji/question.svg";
|
||||||
import twemojiMasc from "../images/twemoji/masc.svg";
|
import twemojiMasc from "../images/twemoji/masc.svg";
|
||||||
import twemojiFem from "../images/twemoji/fem.svg";
|
import twemojiFem from "../images/twemoji/fem.svg";
|
||||||
|
import twemojiHourglass from "../images/twemoji/hourglass.svg";
|
||||||
|
|
||||||
const PosePickerSupport = loadable(() => import("./support/PosePickerSupport"));
|
const PosePickerSupport = loadable(() => import("./support/PosePickerSupport"));
|
||||||
|
|
||||||
|
@ -218,18 +219,11 @@ function PosePicker({
|
||||||
gap="2"
|
gap="2"
|
||||||
index={tabIndex}
|
index={tabIndex}
|
||||||
onChange={setTabIndex}
|
onChange={setTabIndex}
|
||||||
// HACK: To only apply `initialFocusRef` to the selected input
|
|
||||||
// in the *active* tab, we just use `isLazy` to only *render*
|
|
||||||
// the active tab. We could also watch the tab state and set
|
|
||||||
// the ref accordingly!
|
|
||||||
isLazy
|
|
||||||
>
|
>
|
||||||
<SupportOnly>
|
|
||||||
<TabList paddingX="2" paddingY="0">
|
<TabList paddingX="2" paddingY="0">
|
||||||
<Tab width="50%">Expressions</Tab>
|
<Tab width="50%">Expressions</Tab>
|
||||||
<Tab width="50%">Styles</Tab>
|
<Tab width="50%">Styles</Tab>
|
||||||
</TabList>
|
</TabList>
|
||||||
</SupportOnly>
|
|
||||||
<TabPanels position="relative">
|
<TabPanels position="relative">
|
||||||
<TabPanel paddingX="4" paddingY="0">
|
<TabPanel paddingX="4" paddingY="0">
|
||||||
{isInSupportMode ? (
|
{isInSupportMode ? (
|
||||||
|
@ -238,7 +232,9 @@ function PosePicker({
|
||||||
colorId={colorId}
|
colorId={colorId}
|
||||||
pose={pose}
|
pose={pose}
|
||||||
appearanceId={appearanceId}
|
appearanceId={appearanceId}
|
||||||
initialFocusRef={initialFocusRef}
|
initialFocusRef={
|
||||||
|
tabIndex === 0 ? initialFocusRef : null
|
||||||
|
}
|
||||||
dispatchToOutfit={dispatchToOutfit}
|
dispatchToOutfit={dispatchToOutfit}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
@ -246,7 +242,9 @@ function PosePicker({
|
||||||
<PosePickerTable
|
<PosePickerTable
|
||||||
poseInfos={poseInfos}
|
poseInfos={poseInfos}
|
||||||
onChange={onChangePose}
|
onChange={onChangePose}
|
||||||
initialFocusRef={initialFocusRef}
|
initialFocusRef={
|
||||||
|
tabIndex === 0 ? initialFocusRef : null
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
{numStandardPoses == 0 && (
|
{numStandardPoses == 0 && (
|
||||||
<PosePickerEmptyExplanation />
|
<PosePickerEmptyExplanation />
|
||||||
|
@ -267,7 +265,7 @@ function PosePicker({
|
||||||
selectedStyleId={altStyleId}
|
selectedStyleId={altStyleId}
|
||||||
altStyles={altStyles}
|
altStyles={altStyles}
|
||||||
onChange={onChangeStyle}
|
onChange={onChangeStyle}
|
||||||
initialFocusRef={initialFocusRef}
|
initialFocusRef={tabIndex === 1 ? initialFocusRef : null}
|
||||||
/>
|
/>
|
||||||
<StyleExplanation />
|
<StyleExplanation />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
@ -424,14 +422,22 @@ function PosePickerTable({ poseInfos, onChange, initialFocusRef }) {
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{poseInfos.unconverted.isAvailable && (
|
{poseInfos.unconverted.isAvailable && (
|
||||||
|
<Flex
|
||||||
|
align="center"
|
||||||
|
justify="center"
|
||||||
|
gap="1"
|
||||||
|
marginTop="2"
|
||||||
|
marginBottom="2"
|
||||||
|
>
|
||||||
<PoseOption
|
<PoseOption
|
||||||
poseInfo={poseInfos.unconverted}
|
poseInfo={poseInfos.unconverted}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
inputRef={poseInfos.unconverted.isSelected && initialFocusRef}
|
inputRef={poseInfos.unconverted.isSelected && initialFocusRef}
|
||||||
size="sm"
|
size="sm"
|
||||||
label="Unconverted"
|
label="Retired UC"
|
||||||
marginTop="2"
|
|
||||||
/>
|
/>
|
||||||
|
<RetiredUCWarning isSelected={poseInfos.unconverted.isSelected} />
|
||||||
|
</Flex>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
@ -624,6 +630,40 @@ function PosePickerEmptyExplanation() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function RetiredUCWarning({ isSelected }) {
|
||||||
|
return (
|
||||||
|
<Popover placement="right" trigger="hover">
|
||||||
|
<PopoverTrigger>
|
||||||
|
<Box
|
||||||
|
as="button"
|
||||||
|
tabIndex="0"
|
||||||
|
aria-label="Warning"
|
||||||
|
cursor="help"
|
||||||
|
lineHeight="1"
|
||||||
|
opacity={isSelected ? "1" : "0.75"}
|
||||||
|
transform={isSelected ? "scale(1)" : "scale(0.8)"}
|
||||||
|
color={isSelected ? "yellow.500" : "inherit"}
|
||||||
|
transition="all 0.2s"
|
||||||
|
padding="1"
|
||||||
|
>
|
||||||
|
<WarningTwoIcon />
|
||||||
|
</Box>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent
|
||||||
|
background="blackAlpha.800"
|
||||||
|
borderColor="blackAlpha.900"
|
||||||
|
color="white"
|
||||||
|
padding="2"
|
||||||
|
fontSize="sm"
|
||||||
|
>
|
||||||
|
"Unconverted" pets are no longer available on Neopets.com, and have been
|
||||||
|
replaced with the very similar Styles feature. We're just keeping this
|
||||||
|
as an archive!
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function StyleSelect({
|
function StyleSelect({
|
||||||
selectedStyleId,
|
selectedStyleId,
|
||||||
altStyles,
|
altStyles,
|
||||||
|
@ -748,10 +788,6 @@ function StyleExplanation() {
|
||||||
Styling Chamber
|
Styling Chamber
|
||||||
</Box>
|
</Box>
|
||||||
. Not all items fit Alt Style pets. The pet's color doesn't have to match.
|
. Not all items fit Alt Style pets. The pet's color doesn't have to match.
|
||||||
<SupportOnly>
|
|
||||||
<br />
|
|
||||||
WIP: Only Support staff see this tab for now! 💖
|
|
||||||
</SupportOnly>
|
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -889,7 +925,7 @@ function getIcon(pose) {
|
||||||
} else if (["SICK_MASC", "SICK_FEM"].includes(pose)) {
|
} else if (["SICK_MASC", "SICK_FEM"].includes(pose)) {
|
||||||
return twemojiSick;
|
return twemojiSick;
|
||||||
} else if (pose === "UNCONVERTED") {
|
} else if (pose === "UNCONVERTED") {
|
||||||
return twemojiSunglasses;
|
return twemojiHourglass;
|
||||||
} else {
|
} else {
|
||||||
return twemojiSmile;
|
return twemojiSmile;
|
||||||
}
|
}
|
||||||
|
@ -903,7 +939,7 @@ function getLabel(pose) {
|
||||||
} else if (pose === "SICK_MASC" || pose === "SICK_FEM") {
|
} else if (pose === "SICK_MASC" || pose === "SICK_FEM") {
|
||||||
return "Sick";
|
return "Sick";
|
||||||
} else if (pose === "UNCONVERTED") {
|
} else if (pose === "UNCONVERTED") {
|
||||||
return "Classic UC";
|
return "Retired UC";
|
||||||
} else {
|
} else {
|
||||||
return "Default";
|
return "Default";
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,7 @@ function useOutfitSaving(outfitState, dispatchToOutfit) {
|
||||||
speciesId: outfitState.speciesId,
|
speciesId: outfitState.speciesId,
|
||||||
colorId: outfitState.colorId,
|
colorId: outfitState.colorId,
|
||||||
pose: outfitState.pose,
|
pose: outfitState.pose,
|
||||||
|
altStyleId: outfitState.altStyleId,
|
||||||
wornItemIds: [...outfitState.wornItemIds],
|
wornItemIds: [...outfitState.wornItemIds],
|
||||||
closetedItemIds: [...outfitState.closetedItemIds],
|
closetedItemIds: [...outfitState.closetedItemIds],
|
||||||
})
|
})
|
||||||
|
|
|
@ -447,6 +447,7 @@ function getOutfitStateFromOutfitData(outfit) {
|
||||||
speciesId: outfit.speciesId,
|
speciesId: outfit.speciesId,
|
||||||
colorId: outfit.colorId,
|
colorId: outfit.colorId,
|
||||||
pose: outfit.pose,
|
pose: outfit.pose,
|
||||||
|
altStyleId: outfit.altStyleId,
|
||||||
wornItemIds: new Set(outfit.wornItemIds),
|
wornItemIds: new Set(outfit.wornItemIds),
|
||||||
closetedItemIds: new Set(outfit.closetedItemIds),
|
closetedItemIds: new Set(outfit.closetedItemIds),
|
||||||
};
|
};
|
||||||
|
@ -703,12 +704,6 @@ function buildOutfitQueryString(outfitState) {
|
||||||
color: colorId || "",
|
color: colorId || "",
|
||||||
pose: pose || "",
|
pose: pose || "",
|
||||||
});
|
});
|
||||||
for (const itemId of wornItemIds) {
|
|
||||||
params.append("objects[]", itemId);
|
|
||||||
}
|
|
||||||
for (const itemId of closetedItemIds) {
|
|
||||||
params.append("closet[]", itemId);
|
|
||||||
}
|
|
||||||
if (altStyleId != null) {
|
if (altStyleId != null) {
|
||||||
params.append("style", altStyleId);
|
params.append("style", altStyleId);
|
||||||
}
|
}
|
||||||
|
@ -717,6 +712,12 @@ function buildOutfitQueryString(outfitState) {
|
||||||
// refers to "PetState", the database table name for pet appearances.
|
// refers to "PetState", the database table name for pet appearances.
|
||||||
params.append("state", appearanceId);
|
params.append("state", appearanceId);
|
||||||
}
|
}
|
||||||
|
for (const itemId of wornItemIds) {
|
||||||
|
params.append("objects[]", itemId);
|
||||||
|
}
|
||||||
|
for (const itemId of closetedItemIds) {
|
||||||
|
params.append("closet[]", itemId);
|
||||||
|
}
|
||||||
|
|
||||||
return params.toString();
|
return params.toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#FFE8B6" d="M21 18c0-2.001 3.246-3.369 5-6 2-3 2-10 2-10H8s0 7 2 10c1.754 2.631 5 3.999 5 6s-3.246 3.369-5 6c-2 3-2 10-2 10h20s0-7-2-10c-1.754-2.631-5-3.999-5-6z"/><path fill="#FFAC33" d="M20.999 24c-.999 0-2.057-1-2.057-2C19 20.287 19 19.154 19 18c0-3.22 3.034-4.561 4.9-7H12.1c1.865 2.439 4.9 3.78 4.9 7 0 1.155 0 2.289.058 4 0 1-1.058 2-2.058 2-2 0-3.595 1.784-4 3-1 3-1 7-1 7h16s0-4-1-7c-.405-1.216-2.001-3-4.001-3z"/><path fill="#3B88C3" d="M30 34c0 1.104-.896 2-2 2H8c-1.104 0-2-.896-2-2s.896-2 2-2h20c1.104 0 2 .896 2 2zm0-32c0 1.104-.896 2-2 2H8c-1.104 0-2-.896-2-2s.896-2 2-2h20c1.104 0 2 .896 2 2z"/></svg>
|
After Width: | Height: | Size: 688 B |
|
@ -30,7 +30,9 @@ export function useDeleteOutfitMutation(options = {}) {
|
||||||
...options,
|
...options,
|
||||||
mutationFn: deleteOutfit,
|
mutationFn: deleteOutfit,
|
||||||
onSuccess: (emptyData, id, context) => {
|
onSuccess: (emptyData, id, context) => {
|
||||||
queryClient.invalidateQueries({ queryKey: ["outfits", String(id)] });
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: ["outfits", String(id)],
|
||||||
|
});
|
||||||
if (options.onSuccess) {
|
if (options.onSuccess) {
|
||||||
options.onSuccess(emptyData, id, context);
|
options.onSuccess(emptyData, id, context);
|
||||||
}
|
}
|
||||||
|
@ -42,7 +44,9 @@ async function loadSavedOutfit(id) {
|
||||||
const res = await fetch(`/outfits/${encodeURIComponent(id)}.json`);
|
const res = await fetch(`/outfits/${encodeURIComponent(id)}.json`);
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
throw new Error(`loading outfit failed: ${res.status} ${res.statusText}`);
|
throw new Error(
|
||||||
|
`loading outfit failed: ${res.status} ${res.statusText}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.json().then(normalizeOutfit);
|
return res.json().then(normalizeOutfit);
|
||||||
|
@ -54,6 +58,7 @@ async function saveOutfit({
|
||||||
speciesId,
|
speciesId,
|
||||||
colorId,
|
colorId,
|
||||||
pose,
|
pose,
|
||||||
|
altStyleId,
|
||||||
wornItemIds,
|
wornItemIds,
|
||||||
closetedItemIds,
|
closetedItemIds,
|
||||||
}) {
|
}) {
|
||||||
|
@ -65,6 +70,7 @@ async function saveOutfit({
|
||||||
color_id: colorId,
|
color_id: colorId,
|
||||||
pose: pose,
|
pose: pose,
|
||||||
},
|
},
|
||||||
|
alt_style_id: altStyleId,
|
||||||
item_ids: { worn: wornItemIds, closeted: closetedItemIds },
|
item_ids: { worn: wornItemIds, closeted: closetedItemIds },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -91,7 +97,9 @@ async function saveOutfit({
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
throw new Error(`saving outfit failed: ${res.status} ${res.statusText}`);
|
throw new Error(
|
||||||
|
`saving outfit failed: ${res.status} ${res.statusText}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.json().then(normalizeOutfit);
|
return res.json().then(normalizeOutfit);
|
||||||
|
@ -106,7 +114,9 @@ async function deleteOutfit(id) {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
throw new Error(`deleting outfit failed: ${res.status} ${res.statusText}`);
|
throw new Error(
|
||||||
|
`deleting outfit failed: ${res.status} ${res.statusText}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,8 +127,11 @@ function normalizeOutfit(outfit) {
|
||||||
speciesId: String(outfit.species_id),
|
speciesId: String(outfit.species_id),
|
||||||
colorId: String(outfit.color_id),
|
colorId: String(outfit.color_id),
|
||||||
pose: outfit.pose,
|
pose: outfit.pose,
|
||||||
|
altStyleId: outfit.alt_style_id ? String(outfit.alt_style_id) : null,
|
||||||
wornItemIds: (outfit.item_ids?.worn || []).map((id) => String(id)),
|
wornItemIds: (outfit.item_ids?.worn || []).map((id) => String(id)),
|
||||||
closetedItemIds: (outfit.item_ids?.closeted || []).map((id) => String(id)),
|
closetedItemIds: (outfit.item_ids?.closeted || []).map((id) =>
|
||||||
|
String(id),
|
||||||
|
),
|
||||||
creator: outfit.user ? { id: String(outfit.user.id) } : null,
|
creator: outfit.user ? { id: String(outfit.user.id) } : null,
|
||||||
createdAt: outfit.created_at,
|
createdAt: outfit.created_at,
|
||||||
updatedAt: outfit.updated_at,
|
updatedAt: outfit.updated_at,
|
||||||
|
|
|
@ -4,6 +4,7 @@ class Outfit < ApplicationRecord
|
||||||
class_name: 'ItemOutfitRelationship'
|
class_name: 'ItemOutfitRelationship'
|
||||||
has_many :worn_items, through: :worn_item_outfit_relationships, source: :item
|
has_many :worn_items, through: :worn_item_outfit_relationships, source: :item
|
||||||
|
|
||||||
|
belongs_to :alt_style, optional: true
|
||||||
belongs_to :pet_state, optional: true # We validate presence below!
|
belongs_to :pet_state, optional: true # We validate presence below!
|
||||||
belongs_to :user, optional: true
|
belongs_to :user, optional: true
|
||||||
|
|
||||||
|
@ -82,7 +83,8 @@ class Outfit < ApplicationRecord
|
||||||
|
|
||||||
def as_json(more_options={})
|
def as_json(more_options={})
|
||||||
serializable_hash(
|
serializable_hash(
|
||||||
only: [:id, :name, :pet_state_id, :starred, :created_at, :updated_at],
|
only: [:id, :name, :pet_state_id, :starred, :created_at, :updated_at,
|
||||||
|
:alt_style_id],
|
||||||
methods: [:color_id, :species_id, :pose, :item_ids, :user]
|
methods: [:color_id, :species_id, :pose, :item_ids, :user]
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
- title "Styling Studio"
|
- title "Styling Studio"
|
||||||
|
|
||||||
%p
|
%p
|
||||||
We're getting set up with the new NC Pet Styles! They're not ready in the app
|
Here's all the new NC Pet Styles we have! They're available in the app too,
|
||||||
yet, but here's what we have so far!
|
by opening the emotion picker and clicking the "Styles" tab.
|
||||||
|
|
||||||
%p
|
%p
|
||||||
If you have one we don't, please model it by entering your pet's name on the
|
If you have an Alt Style we don't, please model it by entering your pet's
|
||||||
homepage! Thank you! 💖
|
name on the homepage! Thank you! 💖
|
||||||
|
|
||||||
%p
|
%p
|
||||||
Also, heads-up: Style tokens are pretty different from normal wearables, so
|
Also, heads-up: Style tokens are pretty different from normal wearables, so
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
= advertise_campaign_progress @campaign
|
= advertise_campaign_progress @campaign
|
||||||
|
|
||||||
.notice
|
.notice
|
||||||
%strong Happy NC UC day!
|
%strong Alt styles are ready now!
|
||||||
We're working on Styling Studio support,
|
You can find them by opening the emotion picker, then clicking "Styles".
|
||||||
= link_to("here's what we have so far", alt_styles_path) + "!"
|
|
||||||
%br
|
%br
|
||||||
Thank you for helping us model the new styles, we appreciate it lots!!! 💖
|
= link_to("Here's our reference page, too!", alt_styles_path)
|
||||||
|
Thanks again for all your help, let us know how it works for you! 💖
|
||||||
|
|
||||||
%p#pet-not-found.alert= t 'pets.load.not_found'
|
%p#pet-not-found.alert= t 'pets.load.not_found'
|
||||||
|
|
||||||
|
|
5
db/migrate/20240201134440_add_alt_style_id_to_outfits.rb
Normal file
5
db/migrate/20240201134440_add_alt_style_id_to_outfits.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
class AddAltStyleIdToOutfits < ActiveRecord::Migration[7.1]
|
||||||
|
def change
|
||||||
|
add_reference :outfits, :alt_style, null: true, foreign_key: true
|
||||||
|
end
|
||||||
|
end
|
15
db/schema.rb
15
db/schema.rb
|
@ -10,13 +10,13 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[7.1].define(version: 2024_01_29_114639) do
|
ActiveRecord::Schema[7.1].define(version: 2024_02_01_134440) do
|
||||||
create_table "alt_styles", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t|
|
create_table "alt_styles", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t|
|
||||||
t.integer "species_id", null: false
|
t.integer "species_id", null: false
|
||||||
t.integer "color_id", null: false
|
t.integer "color_id", null: false
|
||||||
t.integer "body_id", null: false
|
t.integer "body_id", null: false
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", precision: nil, null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", precision: nil, null: false
|
||||||
t.index ["color_id"], name: "index_alt_styles_on_color_id"
|
t.index ["color_id"], name: "index_alt_styles_on_color_id"
|
||||||
t.index ["species_id"], name: "index_alt_styles_on_species_id"
|
t.index ["species_id"], name: "index_alt_styles_on_species_id"
|
||||||
end
|
end
|
||||||
|
@ -125,11 +125,11 @@ ActiveRecord::Schema[7.1].define(version: 2024_01_29_114639) do
|
||||||
t.index ["outfit_id", "is_worn"], name: "index_item_outfit_relationships_on_outfit_id_and_is_worn"
|
t.index ["outfit_id", "is_worn"], name: "index_item_outfit_relationships_on_outfit_id_and_is_worn"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "item_translations", id: :integer, charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t|
|
create_table "item_translations", id: :integer, charset: "latin1", collation: "latin1_swedish_ci", force: :cascade do |t|
|
||||||
t.integer "item_id"
|
t.integer "item_id"
|
||||||
t.string "locale"
|
t.string "locale"
|
||||||
t.string "name"
|
t.string "name"
|
||||||
t.text "description", size: :medium
|
t.text "description"
|
||||||
t.string "rarity"
|
t.string "rarity"
|
||||||
t.datetime "created_at", precision: nil
|
t.datetime "created_at", precision: nil
|
||||||
t.datetime "updated_at", precision: nil
|
t.datetime "updated_at", precision: nil
|
||||||
|
@ -191,6 +191,8 @@ ActiveRecord::Schema[7.1].define(version: 2024_01_29_114639) do
|
||||||
t.string "image"
|
t.string "image"
|
||||||
t.string "image_layers_hash"
|
t.string "image_layers_hash"
|
||||||
t.boolean "image_enqueued", default: false, null: false
|
t.boolean "image_enqueued", default: false, null: false
|
||||||
|
t.bigint "alt_style_id"
|
||||||
|
t.index ["alt_style_id"], name: "index_outfits_on_alt_style_id"
|
||||||
t.index ["pet_state_id"], name: "index_outfits_on_pet_state_id"
|
t.index ["pet_state_id"], name: "index_outfits_on_pet_state_id"
|
||||||
t.index ["user_id"], name: "index_outfits_on_user_id"
|
t.index ["user_id"], name: "index_outfits_on_user_id"
|
||||||
end
|
end
|
||||||
|
@ -314,4 +316,5 @@ ActiveRecord::Schema[7.1].define(version: 2024_01_29_114639) do
|
||||||
|
|
||||||
add_foreign_key "alt_styles", "colors"
|
add_foreign_key "alt_styles", "colors"
|
||||||
add_foreign_key "alt_styles", "species"
|
add_foreign_key "alt_styles", "species"
|
||||||
|
add_foreign_key "outfits", "alt_styles"
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue