From cfef3f8d05e0a2f43f4a7839597a678593a2d5e7 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Fri, 16 Oct 2026 11:17:26 +0800 Subject: [PATCH] fix(products): stop saving the uploaded icon file record into a category's icon Uploading an icon in the new and edit product category modals set the category's `icon` string attribute to the uploaded File record as well as `icon_file_uuid` and `icon_url`. The string transform turned the record into "", which the save sent and core-api stored in `categories.icon`, in place of any icon name the category had. The upload now sets only `icon_file_uuid` and `icon_url`, as the catalog category modal does. --- addon/controllers/products/index.js | 6 +- addon/controllers/products/index/category.js | 6 +- tests/dummy/app/models/category.js | 4 ++ .../products/category-icon-upload-test.js | 63 +++++++++++++++++++ 4 files changed, 69 insertions(+), 10 deletions(-) create mode 100644 tests/unit/controllers/products/category-icon-upload-test.js diff --git a/addon/controllers/products/index.js b/addon/controllers/products/index.js index 1e5de133..fdc0335f 100644 --- a/addon/controllers/products/index.js +++ b/addon/controllers/products/index.js @@ -421,11 +421,7 @@ export default class ProductsIndexController extends BaseController { type: `category_icon`, }, (uploadedFile) => { - category.setProperties({ - icon_file_uuid: uploadedFile.id, - icon_url: uploadedFile.url, - icon: uploadedFile, - }); + category.setProperties({ icon_file_uuid: uploadedFile.id, icon_url: uploadedFile.url }); } ); }, diff --git a/addon/controllers/products/index/category.js b/addon/controllers/products/index/category.js index a7ea68e4..5787a66f 100644 --- a/addon/controllers/products/index/category.js +++ b/addon/controllers/products/index/category.js @@ -140,11 +140,7 @@ export default class ProductsIndexCategoryController extends BaseController { type: `category_icon`, }, (uploadedFile) => { - category.setProperties({ - icon_file_uuid: uploadedFile.id, - icon_url: uploadedFile.url, - icon: uploadedFile, - }); + category.setProperties({ icon_file_uuid: uploadedFile.id, icon_url: uploadedFile.url }); } ); }, diff --git a/tests/dummy/app/models/category.js b/tests/dummy/app/models/category.js index eb704177..58719231 100644 --- a/tests/dummy/app/models/category.js +++ b/tests/dummy/app/models/category.js @@ -5,7 +5,11 @@ export default class CategoryModel extends Model { @attr('string') name; @attr('string') slug; @attr('string') description; + @attr('string') icon; + @attr('string') icon_color; + @attr('string') icon_file_uuid; @attr('string') icon_url; + @attr('string') company_uuid; @attr('string') owner_uuid; @attr('string') owner_type; @attr('string') parent_uuid; diff --git a/tests/unit/controllers/products/category-icon-upload-test.js b/tests/unit/controllers/products/category-icon-upload-test.js new file mode 100644 index 00000000..2acd5737 --- /dev/null +++ b/tests/unit/controllers/products/category-icon-upload-test.js @@ -0,0 +1,63 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'dummy/tests/helpers'; +import { run } from '@ember/runloop'; + +module('Unit | Controller | products | category icon upload', function (hooks) { + setupTest(hooks); + + // fetch.uploadFile hands its callback the File record it pushed into the store. + function stub(owner, controller) { + const store = owner.lookup('service:store'); + const shown = []; + const uploads = []; + + controller.intl = { t: (key) => key }; + controller.notifications = { success: () => {} }; + controller.modalsManager = { show: (name, options) => shown.push({ name, options }) }; + controller.currentUser = { companyId: 'company-session', getOption: () => 'store-1' }; + controller.fetch = { + uploadFile: { + perform: (file, params, callback) => { + uploads.push(params); + callback(run(() => store.push(store.normalize('file', { uuid: 'file-new', url: 'https://cdn.test/new.png' })))); + }, + }, + }; + + return { store, shown, uploads }; + } + + test('editing a category links the uploaded icon file without writing it to icon', function (assert) { + const controller = this.owner.lookup('controller:products/index/category'); + const { store, shown, uploads } = stub(this.owner, controller); + const category = run(() => + store.push(store.normalize('category', { uuid: 'cat-uuid-1', name: 'Hot Drinks', icon: 'mug-hot', icon_file_uuid: 'file-old', company_uuid: 'company-1' })) + ); + + controller.editCategory(category); + shown[0].options.uploadNewPhoto({ name: 'icon.png' }); + + assert.deepEqual(uploads, [{ path: 'uploads/company-1/product-category-icon/hot-drinks', subject_uuid: 'cat-uuid-1', subject_type: 'category', type: 'category_icon' }]); + assert.strictEqual(category.icon_file_uuid, 'file-new'); + assert.strictEqual(category.icon_url, 'https://cdn.test/new.png'); + assert.strictEqual(category.icon, 'mug-hot', 'the icon name is left alone'); + assert.strictEqual(category.serialize().icon, 'mug-hot', 'the save payload carries no stringified file record'); + }); + + test('a new product category links the uploaded icon file without writing it to icon', function (assert) { + const controller = this.owner.lookup('controller:products/index'); + const { shown, uploads } = stub(this.owner, controller); + + controller.createNewProductCategory(); + const { category, uploadNewPhoto } = shown[0].options; + run(() => category.set('name', 'Cold Drinks')); + uploadNewPhoto({ name: 'icon.png' }); + + assert.strictEqual(uploads.length, 1); + assert.strictEqual(uploads[0].path, 'uploads/company-session/product-category-icon/cold-drinks'); + assert.strictEqual(category.icon_file_uuid, 'file-new'); + assert.strictEqual(category.icon_url, 'https://cdn.test/new.png'); + assert.strictEqual(category.icon, undefined, 'icon is not set to the file'); + assert.strictEqual(category.serialize().icon, null, 'the save payload carries no stringified file record'); + }); +});