{error || '職人が見つかりませんでした'}
+ + 職人一覧に戻る + +{craftsman.user_display_name}
+ )} ++ 経済産業大臣指定番号: {craftsman.meti_certification_number} + {craftsman.meti_craft_category && ` · ${craftsman.meti_craft_category}`} +
+ )} +{craftsman.bio}
+{craftsman.story}
+{craftsman.years_of_practice}年
+職人歴
+{workshopLabel}
+工房規模
+{productionLabel}
+制作方法
+現在、出品中の商品はありません
+ ) : ( +{product.name}
++ ¥{product.price.toLocaleString('ja-JP')} +
+ {product.stock_quantity != null && product.stock_quantity === 0 && ( +{c.prefecture}
} - {c.craft_category &&{c.craft_category}
} +📍 {c.prefecture}
+ )} + {c.years_of_practice != null && ( +職人歴 {c.years_of_practice}年
+ )}{c.bio}
} - {c.rating && c.rating > 0 && ( + {c.rating != null && c.rating > 0 && (⭐ {c.rating.toFixed(1)}
)} diff --git a/src/routes/craftsmen.js b/src/routes/craftsmen.js index b77c449..503aa73 100644 --- a/src/routes/craftsmen.js +++ b/src/routes/craftsmen.js @@ -34,12 +34,41 @@ router.get('/', async (req, res) => { } }); +// Featured craftsmen — top 6 by product count (must be BEFORE /:id to avoid conflict) +router.get('/featured', async (req, res) => { + try { + const pool = getPool(); + const { rows } = await pool.query( + `SELECT c.*, u.email, u.display_name as user_display_name, + COUNT(p.id) AS product_count + FROM craftsmen c + JOIN users u ON c.user_id = u.id + LEFT JOIN products p ON p.craftsman_id = c.id AND p.is_active = true + WHERE c.is_active = true + GROUP BY c.id, u.email, u.display_name + ORDER BY product_count DESC + LIMIT 6` + ); + res.json(rows); + } catch (err) { + console.error(err); + res.status(500).json({ error: 'Failed to fetch featured craftsmen' }); + } +}); + // Get craftsman by ID router.get('/:id', async (req, res) => { try { const pool = getPool(); const { rows } = await pool.query( - `SELECT c.*, u.email, u.display_name as user_display_name + `SELECT c.id, c.shop_name, c.bio, c.story, c.location, c.prefecture, + c.craft_region, c.regional_designation, c.guild_association, + c.meti_certified, c.meti_certification_number, c.meti_craft_category, + c.years_of_practice, c.apprenticeship_lineage, c.primary_materials, + c.workshop_size, c.languages_spoken, c.production_method, + c.craft_category, c.social_links, c.rating, c.review_count, + c.is_active, c.profile_image_url, + u.email, u.display_name as user_display_name FROM craftsmen c JOIN users u ON c.user_id = u.id WHERE c.id = $1 AND c.is_active = true`, [req.params.id] @@ -47,14 +76,15 @@ router.get('/:id', async (req, res) => { if (rows.length === 0) return res.status(404).json({ error: 'Craftsman not found' }); - // Get their products + // Get their last 12 products const products = await pool.query( - 'SELECT * FROM products WHERE craftsman_id = $1 AND is_active = true ORDER BY created_at DESC LIMIT 10', + 'SELECT * FROM products WHERE craftsman_id = $1 AND is_active = true ORDER BY created_at DESC LIMIT 12', [req.params.id] ); res.json({ ...rows[0], products: products.rows }); } catch (err) { + console.error(err); res.status(500).json({ error: 'Failed to fetch craftsman' }); } });