diff --git a/backend/package.json b/backend/package.json index 048818b..90b95db 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "shuttle-platform-backend", - "version": "2.0.1", + "version": "2.0.2", "private": true, "scripts": { "start": "node src/index.js", diff --git a/backend/src/orders.js b/backend/src/orders.js index bc7a827..cb206ae 100644 --- a/backend/src/orders.js +++ b/backend/src/orders.js @@ -89,7 +89,22 @@ router.post('/:slug/orders/wipe', (req, res) => { } }); -// GET /api/shops/:slug/orders/po/:filename — Download a PO file (PDF) +// Content-type map for common PO file extensions +const PO_CONTENT_TYPES = { + '.pdf': 'application/pdf', + '.html': 'text/html', + '.htm': 'text/html', + '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + '.xls': 'application/vnd.ms-excel', + '.csv': 'text/csv', + '.doc': 'application/msword', + '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + '.png': 'image/png', + '.jpg': 'image/jpeg', + '.jpeg': 'image/jpeg', +}; + +// GET /api/shops/:slug/orders/po/:filename — Download/open a PO file router.get('/:slug/orders/po/:filename', (req, res) => { const { slug, filename } = req.params; @@ -114,8 +129,15 @@ router.get('/:slug/orders/po/:filename', (req, res) => { return res.status(404).json({ error: 'PO file not found' }); } - res.setHeader('Content-Type', 'application/pdf'); - res.setHeader('Content-Disposition', `inline; filename="${safeName}"`); + const ext = path.extname(safeName).toLowerCase(); + const contentType = PO_CONTENT_TYPES[ext] || 'application/octet-stream'; + + // PDFs, HTML, and images can be shown inline; everything else triggers download + const isInline = ext === '.pdf' || ext === '.html' || ext === '.htm' || ext === '.png' || ext === '.jpg' || ext === '.jpeg'; + const disposition = isInline ? 'inline' : 'attachment'; + + res.setHeader('Content-Type', contentType); + res.setHeader('Content-Disposition', `${disposition}; filename="${safeName}"`); fs.createReadStream(filePath).pipe(res); }); diff --git a/backend/src/shops.js b/backend/src/shops.js index cd7dd08..e6950f3 100644 --- a/backend/src/shops.js +++ b/backend/src/shops.js @@ -477,14 +477,15 @@ router.post('/', (req, res) => { `details: ${dr.details !== false}`, `extra_notes: ${dr.extra_notes !== false}`, `shipping_handler: ${dr.shipping_handler !== false}`, - `hotel_list: ${dr.hotel_list === true}`, + `hotel_list: ${dr.hotel_list === true || dr.hotel_collection === true}`, + `hotel_collection: ${dr.hotel_collection === true}`, ].join('\n'); fs.writeFileSync( path.join(shopDir, 'DATABASE', 'Presets', 'DataRequired.txt'), drContent ); - if (dr.hotel_list && hotelList) { + if ((dr.hotel_list || dr.hotel_collection) && hotelList) { fs.mkdirSync(path.join(shopDir, 'DATABASE', 'Design', 'Details'), { recursive: true }); fs.writeFileSync( path.join(shopDir, 'DATABASE', 'Design', 'Details', 'Hotels.txt'), @@ -523,7 +524,7 @@ router.post('/', (req, res) => { // Register in database db.prepare( 'INSERT INTO shops (slug, name, description, status, port, subdomain, shuttle_version) VALUES (?, ?, ?, ?, ?, ?, ?)' - ).run(slug, name, description || '', 'stopped', port, subdomain, 'STS-2.00'); + ).run(slug, name, description || '', 'stopped', port, subdomain, 'STS-2.01'); // Start the container using container-readable path const hostComposeFile = getComposeFilePath(slug); @@ -981,7 +982,7 @@ router.get('/:slug/version', (req, res) => { result.currentVersion = shop.shuttle_version; } - result.latestAvailable = 'STS-2.00'; + result.latestAvailable = 'STS-2.01'; res.json(result); } catch (err) { @@ -1078,7 +1079,7 @@ router.post('/:slug/update-template', (req, res) => { }).trim(); } catch { /* ignore */ } - db.prepare('UPDATE shops SET shuttle_version = ? WHERE slug = ?').run('STS-2.00', slug); + db.prepare('UPDATE shops SET shuttle_version = ? WHERE slug = ?').run('STS-2.01', slug); log.push(`Update complete. Now at commit ${newCommit}.`); res.json({ message: `Shop "${slug}" updated successfully`, commit: newCommit, log: log.join('\n') }); @@ -1169,7 +1170,7 @@ router.post('/:slug/upgrade', (req, res) => { } // Update version in DB - db.prepare('UPDATE shops SET shuttle_version = ?, status = ? WHERE slug = ?').run('STS-2.00', 'running', slug); + db.prepare('UPDATE shops SET shuttle_version = ?, status = ? WHERE slug = ?').run('STS-2.01', 'running', slug); log.push('Updated shop version to STS-2.00.'); res.json({ message: `Shop "${slug}" upgraded to STS-2.00`, log: log.join('\n') }); diff --git a/frontend/package.json b/frontend/package.json index 909c06b..576b644 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "shuttle-platform-frontend", "private": true, - "version": "2.0.1", + "version": "2.0.2", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/components/CollectionsEditor.jsx b/frontend/src/components/CollectionsEditor.jsx index e41a5ff..7a4d73a 100644 --- a/frontend/src/components/CollectionsEditor.jsx +++ b/frontend/src/components/CollectionsEditor.jsx @@ -7,6 +7,7 @@ import { listShopFiles, readShopFile, writeShopFile, deleteShopFile, uploadShopFiles, replaceShopFile, getShopImageUrl, } from '../lib/api'; +import FadeImage from './FadeImage'; const DETAIL_FIELDS = { 'Name.txt': { type: 'text', label: 'Name' }, @@ -517,10 +518,10 @@ export default function CollectionsEditor({ slug }) { }`} > {item.thumbnailFile ? ( - {item.name} ) : (
@@ -661,10 +662,10 @@ export default function CollectionsEditor({ slug }) { const imgUrl = getShopImageUrl(slug, photo.path) + (ts ? `&_t=${ts}` : ''); return (
- {photo.name}
- {/* Hotel List (conditional) */} - {dataRequired.hotel_list && ( + {/* Hotel Collection (conditional) */} + {(dataRequired.hotel_list || dataRequired.hotel_collection) && (