From 7462d47d9a6708d3eddc00191c1783696af74819 Mon Sep 17 00:00:00 2001 From: Vineet J Karni <42497152+vineetjk@users.noreply.github.com> Date: Thu, 19 Oct 2023 20:57:05 +0530 Subject: [PATCH 1/5] feat: #450 [Feature] Made category a required field for creating an asset --- app/components/assets/form.tsx | 2 +- app/components/category/category-select.tsx | 5 ++ .../category/category-checkbox-dropdown.tsx | 11 +++ app/modules/asset/service.server.ts | 90 +++++++++++-------- app/routes/_layout+/assets.$assetId.tsx | 21 +++-- app/routes/_layout+/assets._index.tsx | 6 +- 6 files changed, 89 insertions(+), 46 deletions(-) diff --git a/app/components/assets/form.tsx b/app/components/assets/form.tsx index 666e36597..14b341d85 100644 --- a/app/components/assets/form.tsx +++ b/app/components/assets/form.tsx @@ -138,7 +138,7 @@ export const AssetForm = ({ className="border-b-0 pb-[10px]" required={zodFieldIsRequired(FormSchema.shape.category)} > - + {
+ + + Uncategorized + + {refinedCategories.map((c) => ( diff --git a/app/components/list/filters/category/category-checkbox-dropdown.tsx b/app/components/list/filters/category/category-checkbox-dropdown.tsx index d00f8a89c..4c14ccd1e 100644 --- a/app/components/list/filters/category/category-checkbox-dropdown.tsx +++ b/app/components/list/filters/category/category-checkbox-dropdown.tsx @@ -40,6 +40,12 @@ export const CategoryCheckboxDropdown = () => { const [, setInitialSelect] = useAtom(addInitialSelectedCategoriesAtom); const [, clearFilters] = useAtom(clearCategoryFiltersAtom); + const uncategorizedItemObj: any = { + id: "uncategorized", + name: "uncategorized", + color: "#808080", + }; + const hasCategories = useMemo( () => refinedCategories.length > 0, [refinedCategories] @@ -121,6 +127,11 @@ export const CategoryCheckboxDropdown = () => { )}
+ {refinedCategories.map((c) => ( ))} diff --git a/app/modules/asset/service.server.ts b/app/modules/asset/service.server.ts index cc21c3f4a..f552b49fd 100644 --- a/app/modules/asset/service.server.ts +++ b/app/modules/asset/service.server.ts @@ -127,9 +127,22 @@ export async function getAssets({ } if (categoriesIds && categoriesIds.length > 0 && where.asset) { - where.asset.categoryId = { - in: categoriesIds, - }; + if (categoriesIds.includes("uncategorized")) { + where.OR.asset = [ + { + categoryId: { + in: categoriesIds, + }, + }, + { + categoryId: null, + }, + ]; + } else { + where.asset.categoryId = { + in: categoriesIds, + }; + } } if (tagsIds && tagsIds.length > 0 && where.asset) { @@ -217,14 +230,14 @@ export async function createAsset({ qr && qr.userId === userId && qr.assetId === null ? { connect: { id: qrId } } : { - create: [ - { - version: 0, - errorCorrection: ErrorCorrection["L"], - user, - }, - ], - }; + create: [ + { + version: 0, + errorCorrection: ErrorCorrection["L"], + user, + }, + ], + }; /** Data object we send via prisma to create Asset */ const data = { @@ -235,7 +248,7 @@ export async function createAsset({ }; /** If a categoryId is passed, link the category to the asset. */ - if (categoryId) { + if (categoryId !== "uncategorized") { Object.assign(data, { category: { connect: { @@ -603,9 +616,8 @@ export async function duplicateAsset({ for (const i of [...Array(amountOfDuplicates)].keys()) { const duplicatedAsset = await createAsset({ - title: `${asset.title} (copy ${ - amountOfDuplicates > 1 ? i : "" - } ${Date.now()})`, + title: `${asset.title} (copy ${amountOfDuplicates > 1 ? i : "" + } ${Date.now()})`, description: asset.description, userId, categoryId: asset.categoryId, @@ -850,10 +862,10 @@ export const createAssetsFromContentImport = async ({ tags: asset.tags.length > 0 ? { - set: asset.tags - .filter((t) => tags[t]) - .map((t) => ({ id: tags[t] })), - } + set: asset.tags + .filter((t) => tags[t]) + .map((t) => ({ id: tags[t] })), + } : undefined, customFieldsValues, }); @@ -1060,8 +1072,8 @@ export const createAssetsFromBackupImport = async ({ tags: asset.tags.length > 0 ? { - connect: asset.tags.map((tag) => ({ id: tags[tag.name] })), - } + connect: asset.tags.map((tag) => ({ id: tags[tag.name] })), + } : undefined, }); } @@ -1117,28 +1129,28 @@ export interface CreateAssetFromBackupImportPayload title: string; description?: string; category: - | { - id: string; - name: string; - description: string; - color: string; - createdAt: string; - updatedAt: string; - userId: string; - } - | {}; + | { + id: string; + name: string; + description: string; + color: string; + createdAt: string; + updatedAt: string; + userId: string; + } + | {}; tags: { name: string; }[]; location: - | { - name: string; - description?: string; - address?: string; - createdAt: string; - updatedAt: string; - } - | {}; + | { + name: string; + description?: string; + address?: string; + createdAt: string; + updatedAt: string; + } + | {}; customFields: AssetCustomFieldsValuesWithFields[]; } diff --git a/app/routes/_layout+/assets.$assetId.tsx b/app/routes/_layout+/assets.$assetId.tsx index 48b701ce9..cb4124c61 100644 --- a/app/routes/_layout+/assets.$assetId.tsx +++ b/app/routes/_layout+/assets.$assetId.tsx @@ -61,10 +61,10 @@ export async function loader({ request, params }: LoaderFunctionArgs) { */ const lastScan = asset.qrCodes[0]?.id ? parseScanData({ - scan: (await getScanByQrId({ qrId: asset.qrCodes[0].id })) || null, - userId, - request, - }) + scan: (await getScanByQrId({ qrId: asset.qrCodes[0].id })) || null, + userId, + request, + }) : null; const notes = asset.notes.map((note) => ({ @@ -251,7 +251,18 @@ export default function AssetDetailsPage() {
- ) : null} + ) : ( +
  • + + Category + +
    + + Uncategorized + +
    +
  • + )} {location ? (
  • diff --git a/app/routes/_layout+/assets._index.tsx b/app/routes/_layout+/assets._index.tsx index 97d59c7de..fa48d62d5 100644 --- a/app/routes/_layout+/assets._index.tsx +++ b/app/routes/_layout+/assets._index.tsx @@ -286,7 +286,11 @@ const ListAssetContent = ({ {category.name} - ) : null} + ) : ( + + {"Uncategorized"} + + )} {/* Tags */} From 79c3fd22919618514ccbc1e7a27f5939f61ea98c Mon Sep 17 00:00:00 2001 From: Vineet J Karni <42497152+vineetjk@users.noreply.github.com> Date: Thu, 19 Oct 2023 23:01:01 +0530 Subject: [PATCH 2/5] updated fix --- app/modules/asset/service.server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/modules/asset/service.server.ts b/app/modules/asset/service.server.ts index f552b49fd..5ab545dd3 100644 --- a/app/modules/asset/service.server.ts +++ b/app/modules/asset/service.server.ts @@ -128,7 +128,7 @@ export async function getAssets({ if (categoriesIds && categoriesIds.length > 0 && where.asset) { if (categoriesIds.includes("uncategorized")) { - where.OR.asset = [ + where.asset.OR = [ { categoryId: { in: categoriesIds, From e9056101caf125d42dd05c11e5769e4401cf0615 Mon Sep 17 00:00:00 2001 From: Vineet J Karni <42497152+vineetjk@users.noreply.github.com> Date: Fri, 20 Oct 2023 19:30:00 +0530 Subject: [PATCH 3/5] fix: addressed review comments --- app/modules/asset/service.server.ts | 77 ++++++++++++++----------- app/routes/_layout+/assets.$assetId.tsx | 8 +-- 2 files changed, 46 insertions(+), 39 deletions(-) diff --git a/app/modules/asset/service.server.ts b/app/modules/asset/service.server.ts index 5ab545dd3..a1e7137ac 100644 --- a/app/modules/asset/service.server.ts +++ b/app/modules/asset/service.server.ts @@ -230,14 +230,14 @@ export async function createAsset({ qr && qr.userId === userId && qr.assetId === null ? { connect: { id: qrId } } : { - create: [ - { - version: 0, - errorCorrection: ErrorCorrection["L"], - user, - }, - ], - }; + create: [ + { + version: 0, + errorCorrection: ErrorCorrection["L"], + user, + }, + ], + }; /** Data object we send via prisma to create Asset */ const data = { @@ -361,7 +361,7 @@ export async function updateAsset(payload: UpdateAssetPayload) { }; /** Delete the category id from the payload so we can use connect syntax from prisma */ - if (categoryId) { + if (categoryId !== "uncategorized") { Object.assign(data, { category: { connect: { @@ -369,6 +369,12 @@ export async function updateAsset(payload: UpdateAssetPayload) { }, }, }); + } else { + Object.assign(data, { + category: { + disconnect: true, + }, + }); } /** Delete the category id from the payload so we can use connect syntax from prisma */ @@ -616,8 +622,9 @@ export async function duplicateAsset({ for (const i of [...Array(amountOfDuplicates)].keys()) { const duplicatedAsset = await createAsset({ - title: `${asset.title} (copy ${amountOfDuplicates > 1 ? i : "" - } ${Date.now()})`, + title: `${asset.title} (copy ${ + amountOfDuplicates > 1 ? i : "" + } ${Date.now()})`, description: asset.description, userId, categoryId: asset.categoryId, @@ -862,10 +869,10 @@ export const createAssetsFromContentImport = async ({ tags: asset.tags.length > 0 ? { - set: asset.tags - .filter((t) => tags[t]) - .map((t) => ({ id: tags[t] })), - } + set: asset.tags + .filter((t) => tags[t]) + .map((t) => ({ id: tags[t] })), + } : undefined, customFieldsValues, }); @@ -1072,8 +1079,8 @@ export const createAssetsFromBackupImport = async ({ tags: asset.tags.length > 0 ? { - connect: asset.tags.map((tag) => ({ id: tags[tag.name] })), - } + connect: asset.tags.map((tag) => ({ id: tags[tag.name] })), + } : undefined, }); } @@ -1129,28 +1136,28 @@ export interface CreateAssetFromBackupImportPayload title: string; description?: string; category: - | { - id: string; - name: string; - description: string; - color: string; - createdAt: string; - updatedAt: string; - userId: string; - } - | {}; + | { + id: string; + name: string; + description: string; + color: string; + createdAt: string; + updatedAt: string; + userId: string; + } + | {}; tags: { name: string; }[]; location: - | { - name: string; - description?: string; - address?: string; - createdAt: string; - updatedAt: string; - } - | {}; + | { + name: string; + description?: string; + address?: string; + createdAt: string; + updatedAt: string; + } + | {}; customFields: AssetCustomFieldsValuesWithFields[]; } diff --git a/app/routes/_layout+/assets.$assetId.tsx b/app/routes/_layout+/assets.$assetId.tsx index cb4124c61..8bbf8036d 100644 --- a/app/routes/_layout+/assets.$assetId.tsx +++ b/app/routes/_layout+/assets.$assetId.tsx @@ -61,10 +61,10 @@ export async function loader({ request, params }: LoaderFunctionArgs) { */ const lastScan = asset.qrCodes[0]?.id ? parseScanData({ - scan: (await getScanByQrId({ qrId: asset.qrCodes[0].id })) || null, - userId, - request, - }) + scan: (await getScanByQrId({ qrId: asset.qrCodes[0].id })) || null, + userId, + request, + }) : null; const notes = asset.notes.map((note) => ({ From 90a81ff864647cf4a401336f0239e04a05435202 Mon Sep 17 00:00:00 2001 From: Donkoko Date: Mon, 23 Oct 2023 12:55:28 +0300 Subject: [PATCH 4/5] destroying session when user cannot be found --- app/modules/tag/service.server.ts | 2 +- app/routes/_index.tsx | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/modules/tag/service.server.ts b/app/modules/tag/service.server.ts index b210d5e08..86d2f7b6c 100644 --- a/app/modules/tag/service.server.ts +++ b/app/modules/tag/service.server.ts @@ -22,7 +22,7 @@ export async function getTags({ const take = perPage >= 1 ? perPage : 8; // min 1 and max 25 per page /** Default value of where. Takes the items belonging to current user */ - let where: Prisma.CategoryWhereInput = { userId }; + let where: Prisma.TagWhereInput = { userId }; /** If the search string exists, add it to the where object */ if (search) { diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx index c22f66a25..d6795185f 100644 --- a/app/routes/_index.tsx +++ b/app/routes/_index.tsx @@ -1,7 +1,7 @@ import type { LoaderFunctionArgs } from "@remix-run/node"; import { redirect } from "@remix-run/node"; -import { getAuthSession } from "~/modules/auth"; +import { destroyAuthSession, getAuthSession } from "~/modules/auth"; import { getUserByEmail } from "~/modules/user"; export const loader = async ({ request }: LoaderFunctionArgs) => { @@ -18,5 +18,8 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { if (user) { return redirect(user.onboarded ? "/assets" : "onboarding"); } - return redirect("login"); + /** Not finding user for the current session is sus + * So we just destroy the session and redirect to / + */ + return destroyAuthSession(request); }; From 2eea0493bdd78ea7c092d96f2af0414e82159a6a Mon Sep 17 00:00:00 2001 From: Donkoko Date: Mon, 23 Oct 2023 14:40:57 +0300 Subject: [PATCH 5/5] fixing issue with how uncategorized is handled in updateAsset --- app/modules/asset/service.server.ts | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/app/modules/asset/service.server.ts b/app/modules/asset/service.server.ts index a1e7137ac..7ad6682d9 100644 --- a/app/modules/asset/service.server.ts +++ b/app/modules/asset/service.server.ts @@ -326,6 +326,7 @@ interface UpdateAssetPayload { id: Asset["id"]; title?: Asset["title"]; description?: Asset["description"]; + /** Pass 'uncategorized' to clear the category */ categoryId?: Asset["categoryId"]; newLocationId?: Asset["locationId"]; currentLocationId?: Asset["locationId"]; @@ -360,24 +361,27 @@ export async function updateAsset(payload: UpdateAssetPayload) { mainImageExpiration, }; - /** Delete the category id from the payload so we can use connect syntax from prisma */ - if (categoryId !== "uncategorized") { + /** If uncategorized is passed, disconnect the category */ + if (categoryId === "uncategorized") { Object.assign(data, { category: { - connect: { - id: categoryId, - }, + disconnect: true, }, }); - } else { + } + + // If category id is passed and is differenent than uncategorized, connect the category + if (categoryId && categoryId !== "uncategorized") { Object.assign(data, { category: { - disconnect: true, + connect: { + id: categoryId, + }, }, }); } - /** Delete the category id from the payload so we can use connect syntax from prisma */ + /** Connect the new location id */ if (newLocationId) { Object.assign(data, { location: {