fix order
This commit is contained in:
1 parent
c6d732ff10
commit
93873228ff
3 files changed
+82
-37
No files matched your search
@@ -1,37 +1,30 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import ProductCategoryBox from '@/app/components/layout/shop/products-cat'
|
import ProductCategoryBox from '@/app/components/layout/shop/products-cat'
|
||||||
import Image from 'next/image'
|
|
||||||
import axiosInstance from '@/axios/axiosInstance'
|
import axiosInstance from '@/axios/axiosInstance'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useQuery,useQueryClient } from '@tanstack/react-query'
|
import { useQuery } from '@tanstack/react-query'
|
||||||
|
|
||||||
const Page = ()=>{
|
const Page = ()=>{
|
||||||
|
|
||||||
const [category, setCategory] = useState([])
|
|
||||||
|
|
||||||
const queryClient = useQueryClient()
|
|
||||||
|
|
||||||
useEffect(()=>{
|
|
||||||
|
|
||||||
},[])
|
|
||||||
|
|
||||||
const query = useQuery({ queryKey: ['categoryProducts'], queryFn: async ()=>{
|
const query = useQuery({ queryKey: ['categoryProducts'], queryFn: async ()=>{
|
||||||
|
|
||||||
return await axiosInstance.get("shop/v2/product-category/list/")
|
return await axiosInstance.get("shop/v2/product-category/list/")
|
||||||
},refetchOnWindowFocus:false, onSuccess(result:any) {
|
},refetchOnWindowFocus:true, })
|
||||||
|
|
||||||
setCategory(result.data)
|
const category = query.data?.data ?? []
|
||||||
|
useEffect(() => {
|
||||||
setTimeout(async ()=>{
|
if (!query.isSuccess) return
|
||||||
const scrollpos = localStorage.getItem('scrollY')
|
const frame = requestAnimationFrame(() => {
|
||||||
if (scrollpos){
|
try {
|
||||||
await window.scrollTo(0, parseInt(scrollpos));
|
const position = Number(localStorage.getItem('scrollY'))
|
||||||
|
if (Number.isFinite(position) && position > 0) window.scrollTo(0, position)
|
||||||
|
} catch {
|
||||||
|
console.warn('Could not restore the saved shop scroll position.')
|
||||||
}
|
}
|
||||||
|
})
|
||||||
},150)
|
return () => cancelAnimationFrame(frame)
|
||||||
|
}, [query.isSuccess])
|
||||||
}, })
|
|
||||||
|
|
||||||
if(query.isLoading){
|
if(query.isLoading){
|
||||||
return (
|
return (
|
||||||
@@ -53,10 +46,10 @@ const Page = ()=>{
|
|||||||
{query.isSuccess?category.map((iteam:any)=>{
|
{query.isSuccess?category.map((iteam:any)=>{
|
||||||
return <ProductCategoryBox key={iteam.id} iteam={iteam} />
|
return <ProductCategoryBox key={iteam.id} iteam={iteam} />
|
||||||
}):null}
|
}):null}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Page
|
export default Page
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import Products from '@/app/components/layout/shop/products'
|
import Products from '@/app/components/layout/shop/products'
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import Link from 'next/link'
|
|
||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
import { useQuery } from '@tanstack/react-query'
|
||||||
import axiosInstance from '@/axios/axiosInstance'
|
import axiosInstance from '@/axios/axiosInstance'
|
||||||
import { useState } from 'react'
|
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
@@ -21,16 +19,13 @@ const Page = ({ params }: { params: { id: string } })=>{
|
|||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const [products, setProducts] = useState<{category_name: string, category_img: string | null,
|
|
||||||
products:[{id:number, name:string, price: number, view_only: boolean}],
|
|
||||||
view_only_products:[{id:number, name:string, price: number, view_only: boolean}]
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const query = useQuery({ queryKey: ['productListByCat', params.id], queryFn: async ()=>{
|
const query = useQuery({ queryKey: ['productListByCat', params.id], queryFn: async ()=>{
|
||||||
return await axiosInstance.get(`shop/product/list/${params.id}/`)
|
return await axiosInstance.get<{category_name: string, category_img: string | null,
|
||||||
}, onSuccess(result:any) {
|
products: {id:number, name:string, price:number, view_only:boolean}[],
|
||||||
setProducts(result.data)
|
view_only_products: {id:number, name:string, price:number, view_only:boolean}[] | null
|
||||||
|
}>(`shop/product/list/${params.id}/`)
|
||||||
}, });
|
}, });
|
||||||
|
const products = query.data?.data
|
||||||
|
|
||||||
if(query.isLoading){
|
if(query.isLoading){
|
||||||
return (
|
return (
|
||||||
@@ -115,4 +110,4 @@ const Page = ({ params }: { params: { id: string } })=>{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Page
|
export default Page
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
const test = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
const vm = require('node:vm');
|
||||||
|
const ts = require('typescript');
|
||||||
|
|
||||||
|
// Render the actual pages with cached React Query responses; no onSuccess call.
|
||||||
|
function pageHarness(filename, data) {
|
||||||
|
const state = { data: { data }, isSuccess: true, isLoading: false, isError: false, dataUpdatedAt: 1 };
|
||||||
|
const module = { exports: {} }; let options;
|
||||||
|
const source = ts.transpileModule(fs.readFileSync(filename, 'utf8'), { compilerOptions: {
|
||||||
|
module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020,
|
||||||
|
esModuleInterop: true, jsx: ts.JsxEmit.ReactJSX,
|
||||||
|
} }).outputText;
|
||||||
|
const requireStub = name => {
|
||||||
|
if (name === 'react/jsx-runtime') return require(name);
|
||||||
|
if (name === 'react') return { useEffect() {}, useState: () => [undefined, () => {}] };
|
||||||
|
if (name === '@tanstack/react-query') return { useQuery: value => { options = value; return state; } };
|
||||||
|
if (name === 'next/navigation') return { useRouter: () => ({ push() {} }) };
|
||||||
|
if (name === '@/axios/axiosInstance') return { __esModule: true, default: { get() {} } };
|
||||||
|
if (name === '@/components/ui/table') return Object.fromEntries(['Table', 'TableBody', 'TableCaption', 'TableCell', 'TableFooter', 'TableHead', 'TableHeader', 'TableRow'].map(key => [key, key]));
|
||||||
|
return { __esModule: true, default: name.endsWith('products-cat') ? 'CategoryCard' : name.endsWith('products') ? 'ProductCard' : 'Image' };
|
||||||
|
};
|
||||||
|
vm.runInNewContext('(function(require,module,exports){' + source + '\n})', {})(requireStub, module, module.exports);
|
||||||
|
return { state, render: () => module.exports.default({ params: { id: '9' } }), get options() { return options; } };
|
||||||
|
}
|
||||||
|
function elements(tree, type) {
|
||||||
|
if (tree == null || typeof tree !== 'object') return [];
|
||||||
|
if (Array.isArray(tree)) return tree.flatMap(item => elements(item, type));
|
||||||
|
return [...(tree.type === type ? [tree] : []), ...elements(tree.props?.children, type)];
|
||||||
|
}
|
||||||
|
const categoryPage = 'src/app/(index)/shop/page.tsx';
|
||||||
|
const productPage = 'src/app/(index)/shop/product/[id]/page.tsx';
|
||||||
|
|
||||||
|
test('shop displays cached categories in the API order, including after updated data', () => {
|
||||||
|
const h = pageHarness(categoryPage, [{ id: 8, name: 'Second alphabetically' }, { id: 1, name: 'First alphabetically' }]);
|
||||||
|
assert.deepEqual(elements(h.render(), 'CategoryCard').map(card => card.props.iteam.id), [8, 1]);
|
||||||
|
h.state.data = { data: [{ id: 1 }, { id: 8 }] }; h.state.dataUpdatedAt++;
|
||||||
|
assert.deepEqual(elements(h.render(), 'CategoryCard').map(card => card.props.iteam.id), [1, 8]);
|
||||||
|
assert.equal(h.options.refetchOnWindowFocus, true);
|
||||||
|
});
|
||||||
|
test('category page preserves cached and refreshed product order for both product groups', () => {
|
||||||
|
const data = { category_name: 'Category', category_img: null,
|
||||||
|
products: [{ id: 20, name: 'Z', view_only: false }, { id: 2, name: 'A', view_only: false }],
|
||||||
|
view_only_products: [{ id: 19, name: 'Custom Z' }, { id: 1, name: 'Custom A' }] };
|
||||||
|
const h = pageHarness(productPage, data);
|
||||||
|
assert.deepEqual(elements(h.render(), 'ProductCard').map(card => card.props.iteam.id), [20, 2]);
|
||||||
|
assert.deepEqual(elements(h.render(), 'TableCell').filter(cell => cell.props.children !== '-----').map(cell => cell.props.children), ['Custom Z', 'Custom A']);
|
||||||
|
h.state.data = { data: { ...data, products: [...data.products].reverse(), view_only_products: [...data.view_only_products].reverse() } };
|
||||||
|
assert.deepEqual(elements(h.render(), 'ProductCard').map(card => card.props.iteam.id), [2, 20]);
|
||||||
|
assert.deepEqual(elements(h.render(), 'TableCell').filter(cell => cell.props.children !== '-----').map(cell => cell.props.children), ['Custom A', 'Custom Z']);
|
||||||
|
});
|
||||||
|
test('a category without custom products renders its ordered ordinary products', () => {
|
||||||
|
const h = pageHarness(productPage, { category_name: 'Category', category_img: null, products: [{ id: 3, view_only: false }], view_only_products: null });
|
||||||
|
assert.deepEqual(elements(h.render(), 'ProductCard').map(card => card.props.iteam.id), [3]);
|
||||||
|
assert.equal(elements(h.render(), 'TableRow').length, 0);
|
||||||
|
});
|
||||||
Reference in new issue
Block a user