feature/excel #1
@@ -197,6 +197,7 @@ interface ProductData {
|
|||||||
applicationHtml?: string;
|
applicationHtml?: string;
|
||||||
images?: string[];
|
images?: string[];
|
||||||
featuredImage?: string | null;
|
featuredImage?: string | null;
|
||||||
|
logoDataUrl?: string | null;
|
||||||
categories?: Array<{ name: string }>;
|
categories?: Array<{ name: string }>;
|
||||||
attributes?: Array<{ name: string; options: string[] }>;
|
attributes?: Array<{ name: string; options: string[] }>;
|
||||||
}
|
}
|
||||||
@@ -204,7 +205,7 @@ interface ProductData {
|
|||||||
export interface PDFDatasheetProps {
|
export interface PDFDatasheetProps {
|
||||||
product: ProductData;
|
product: ProductData;
|
||||||
locale: 'en' | 'de';
|
locale: 'en' | 'de';
|
||||||
logoUrl?: string;
|
logoDataUrl?: string | null;
|
||||||
technicalItems?: KeyValueItem[];
|
technicalItems?: KeyValueItem[];
|
||||||
voltageTables?: DatasheetVoltageTable[];
|
voltageTables?: DatasheetVoltageTable[];
|
||||||
legendItems?: KeyValueItem[];
|
legendItems?: KeyValueItem[];
|
||||||
@@ -485,8 +486,15 @@ export const PDFDatasheet: React.FC<PDFDatasheetProps> = ({
|
|||||||
<Page size="A4" style={styles.page}>
|
<Page size="A4" style={styles.page}>
|
||||||
<View style={styles.hero}>
|
<View style={styles.hero}>
|
||||||
<View style={styles.header}>
|
<View style={styles.header}>
|
||||||
<View>
|
<View style={{ width: 80 }}>
|
||||||
|
{product.logoDataUrl || (product as any).logoDataUrl ? (
|
||||||
|
<Image
|
||||||
|
src={product.logoDataUrl || (product as any).logoDataUrl}
|
||||||
|
style={{ width: '100%', objectFit: 'contain' }}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
<Text style={styles.logoText}>KLZ</Text>
|
<Text style={styles.logoText}>KLZ</Text>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
<Text style={styles.docTitle}>{labels.productDatasheet}</Text>
|
<Text style={styles.docTitle}>{labels.productDatasheet}</Text>
|
||||||
</View>
|
</View>
|
||||||
@@ -586,7 +594,16 @@ export const PDFDatasheet: React.FC<PDFDatasheetProps> = ({
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={styles.footer} fixed>
|
<View style={styles.footer} fixed>
|
||||||
|
<View style={{ width: 60 }}>
|
||||||
|
{product.logoDataUrl || (product as any).logoDataUrl ? (
|
||||||
|
<Image
|
||||||
|
src={product.logoDataUrl || (product as any).logoDataUrl}
|
||||||
|
style={{ width: '100%', objectFit: 'contain' }}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
<Text style={styles.footerBrand}>KLZ CABLES</Text>
|
<Text style={styles.footerBrand}>KLZ CABLES</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
<Text style={styles.footerText}>
|
<Text style={styles.footerText}>
|
||||||
{new Date().toLocaleDateString(locale === 'en' ? 'en-US' : 'de-DE', {
|
{new Date().toLocaleDateString(locale === 'en' ? 'en-US' : 'de-DE', {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
public/datasheets/high-voltage/n2xsfl2y-hv-de.pdf
Normal file
BIN
public/datasheets/high-voltage/n2xsfl2y-hv-de.pdf
Normal file
Binary file not shown.
BIN
public/datasheets/high-voltage/n2xsfl2y-hv-en.pdf
Normal file
BIN
public/datasheets/high-voltage/n2xsfl2y-hv-en.pdf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
public/datasheets/high-voltage/na2xsfl2y-hv-de.pdf
Normal file
BIN
public/datasheets/high-voltage/na2xsfl2y-hv-de.pdf
Normal file
Binary file not shown.
BIN
public/datasheets/high-voltage/na2xsfl2y-hv-en.pdf
Normal file
BIN
public/datasheets/high-voltage/na2xsfl2y-hv-en.pdf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -15,6 +15,7 @@ SOURCE_ENV="${1:-}" # local | testing | staging | prod
|
|||||||
TARGET_ENV="${2:-}" # testing | staging | prod
|
TARGET_ENV="${2:-}" # testing | staging | prod
|
||||||
SSH_HOST="root@alpha.mintel.me"
|
SSH_HOST="root@alpha.mintel.me"
|
||||||
LOCAL_MEDIA_DIR="./public/media"
|
LOCAL_MEDIA_DIR="./public/media"
|
||||||
|
LOCAL_DATASHEETS_DIR="./public/datasheets"
|
||||||
|
|
||||||
DRY_RUN=""
|
DRY_RUN=""
|
||||||
CHECKSUM=""
|
CHECKSUM=""
|
||||||
@@ -38,6 +39,16 @@ get_media_path() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get_datasheets_path() {
|
||||||
|
case "$1" in
|
||||||
|
local) echo "$LOCAL_DATASHEETS_DIR" ;;
|
||||||
|
testing) echo "/home/deploy/sites/testing.klz-cables.com/public/datasheets" ;;
|
||||||
|
staging) echo "/home/deploy/sites/staging.klz-cables.com/public/datasheets" ;;
|
||||||
|
prod|production) echo "/home/deploy/sites/klz-cables.com/public/datasheets" ;;
|
||||||
|
*) echo "❌ Unknown environment: $1"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
get_app_container() {
|
get_app_container() {
|
||||||
case "$1" in
|
case "$1" in
|
||||||
testing) echo "klz-testing-klz-app-1" ;;
|
testing) echo "klz-testing-klz-app-1" ;;
|
||||||
@@ -52,35 +63,39 @@ TGT_PATH=$(get_media_path "$TARGET_ENV")
|
|||||||
TGT_CONTAINER=$(get_app_container "$TARGET_ENV")
|
TGT_CONTAINER=$(get_app_container "$TARGET_ENV")
|
||||||
|
|
||||||
echo "🚀 Syncing assets: $SOURCE_ENV → $TARGET_ENV"
|
echo "🚀 Syncing assets: $SOURCE_ENV → $TARGET_ENV"
|
||||||
echo "📂 Source: $SRC_PATH"
|
|
||||||
echo "📂 Target: $TGT_PATH"
|
|
||||||
|
|
||||||
# ── Execution ──────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
if [[ ! -d "$SRC_PATH" ]] && [[ "$SOURCE_ENV" == "local" ]]; then
|
|
||||||
echo "❌ Source directory does not exist: $SRC_PATH"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
# ── Media Sync ─────────────────────────────────────────────────────────────
|
||||||
|
echo "🖼️ Syncing Media..."
|
||||||
if [[ "$SOURCE_ENV" == "local" ]]; then
|
if [[ "$SOURCE_ENV" == "local" ]]; then
|
||||||
# Local → Remote
|
|
||||||
echo "📡 Running rsync..."
|
|
||||||
rsync -avzi $CHECKSUM --delete --progress $DRY_RUN "$SRC_PATH/" "$SSH_HOST:$TGT_PATH/"
|
rsync -avzi $CHECKSUM --delete --progress $DRY_RUN "$SRC_PATH/" "$SSH_HOST:$TGT_PATH/"
|
||||||
elif [[ "$TARGET_ENV" == "local" ]]; then
|
elif [[ "$TARGET_ENV" == "local" ]]; then
|
||||||
# Remote → Local
|
|
||||||
mkdir -p "$LOCAL_MEDIA_DIR"
|
mkdir -p "$LOCAL_MEDIA_DIR"
|
||||||
echo "📡 Running rsync..."
|
|
||||||
rsync -avzi $CHECKSUM --delete --progress $DRY_RUN "$SSH_HOST:$SRC_PATH/" "$TGT_PATH/"
|
rsync -avzi $CHECKSUM --delete --progress $DRY_RUN "$SSH_HOST:$SRC_PATH/" "$TGT_PATH/"
|
||||||
else
|
else
|
||||||
# Remote → Remote (e.g., testing → staging)
|
|
||||||
echo "📡 Running remote rsync..."
|
|
||||||
ssh "$SSH_HOST" "rsync -avzi $CHECKSUM --delete --progress $DRY_RUN $SRC_PATH/ $TGT_PATH/"
|
ssh "$SSH_HOST" "rsync -avzi $CHECKSUM --delete --progress $DRY_RUN $SRC_PATH/ $TGT_PATH/"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ── Datasheets Sync ────────────────────────────────────────────────────────
|
||||||
|
echo "📄 Syncing Datasheets..."
|
||||||
|
SRC_DS_PATH=$(get_datasheets_path "$SOURCE_ENV")
|
||||||
|
TGT_DS_PATH=$(get_datasheets_path "$TARGET_ENV")
|
||||||
|
|
||||||
|
if [[ "$SOURCE_ENV" == "local" ]]; then
|
||||||
|
ssh "$SSH_HOST" "mkdir -p $TGT_DS_PATH"
|
||||||
|
rsync -avzi $CHECKSUM --delete --progress $DRY_RUN "$SRC_DS_PATH/" "$SSH_HOST:$TGT_DS_PATH/"
|
||||||
|
elif [[ "$TARGET_ENV" == "local" ]]; then
|
||||||
|
mkdir -p "$LOCAL_DATASHEETS_DIR"
|
||||||
|
rsync -avzi $CHECKSUM --delete --progress $DRY_RUN "$SSH_HOST:$SRC_DS_PATH/" "$TGT_DS_PATH/"
|
||||||
|
else
|
||||||
|
ssh "$SSH_HOST" "mkdir -p $TGT_DS_PATH && rsync -avzi $CHECKSUM --delete --progress $DRY_RUN $SRC_DS_PATH/ $TGT_DS_PATH/"
|
||||||
|
fi
|
||||||
|
|
||||||
# Fix ownership on remote target if it's not local
|
# Fix ownership on remote target if it's not local
|
||||||
if [[ "$TARGET_ENV" != "local" && -z "$DRY_RUN" ]]; then
|
if [[ "$TARGET_ENV" != "local" && -z "$DRY_RUN" ]]; then
|
||||||
echo "🔑 Fixing media file permissions on $TARGET_ENV..."
|
echo "🔑 Fixing media file permissions on $TARGET_ENV..."
|
||||||
ssh "$SSH_HOST" "docker exec -u 0 $TGT_CONTAINER chown -R 1001:65533 /app/public/media/ 2>/dev/null || true"
|
ssh "$SSH_HOST" "docker exec -u 0 $TGT_CONTAINER chown -R 1001:65533 /app/public/media/ 2>/dev/null || true"
|
||||||
|
echo "🔑 Fixing datasheet permissions..."
|
||||||
|
ssh "$SSH_HOST" "chown -R 1001:1001 $TGT_DS_PATH 2>/dev/null || true"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "✅ Asset sync complete!"
|
echo "✅ Asset sync complete!"
|
||||||
|
|||||||
@@ -268,7 +268,10 @@ async function processChunk(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load assets as Data URLs for React-PDF
|
// Load assets as Data URLs for React-PDF
|
||||||
const heroDataUrl = await loadImageAsPngDataUrl(model.product.heroSrc);
|
const [heroDataUrl, logoDataUrl] = await Promise.all([
|
||||||
|
loadImageAsPngDataUrl(model.product.heroSrc),
|
||||||
|
loadImageAsPngDataUrl('/logo-black.svg'),
|
||||||
|
]);
|
||||||
|
|
||||||
const fileName = generateFileName(product, locale);
|
const fileName = generateFileName(product, locale);
|
||||||
const voltageType = (product as any).voltageType || 'other';
|
const voltageType = (product as any).voltageType || 'other';
|
||||||
@@ -281,14 +284,18 @@ async function processChunk(
|
|||||||
// Render using the unified component
|
// Render using the unified component
|
||||||
const element = (
|
const element = (
|
||||||
<PDFDatasheet
|
<PDFDatasheet
|
||||||
product={{
|
product={
|
||||||
|
{
|
||||||
...model.product,
|
...model.product,
|
||||||
featuredImage: heroDataUrl,
|
featuredImage: heroDataUrl,
|
||||||
}}
|
logoDataUrl,
|
||||||
|
} as any
|
||||||
|
}
|
||||||
locale={locale}
|
locale={locale}
|
||||||
technicalItems={model.technicalItems}
|
technicalItems={model.technicalItems}
|
||||||
voltageTables={model.voltageTables}
|
voltageTables={model.voltageTables}
|
||||||
legendItems={model.legendItems}
|
legendItems={model.legendItems}
|
||||||
|
logoDataUrl={logoDataUrl}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -147,7 +147,10 @@ function compactCellForDenseTable(
|
|||||||
|
|
||||||
function resolveMediaToLocalPath(urlOrPath: string | null | undefined): string | null {
|
function resolveMediaToLocalPath(urlOrPath: string | null | undefined): string | null {
|
||||||
if (!urlOrPath) return null;
|
if (!urlOrPath) return null;
|
||||||
if (urlOrPath.startsWith('/')) return urlOrPath;
|
if (urlOrPath.startsWith('/')) {
|
||||||
|
// Handle Payload API URL prefix: /api/media/file/filename.ext -> /media/filename.ext
|
||||||
|
return urlOrPath.replace(/^\/api\/media\/file\//, '/media/');
|
||||||
|
}
|
||||||
if (/^media\//i.test(urlOrPath)) return `/${urlOrPath}`;
|
if (/^media\//i.test(urlOrPath)) return `/${urlOrPath}`;
|
||||||
const mapped = ASSET_MAP[urlOrPath];
|
const mapped = ASSET_MAP[urlOrPath];
|
||||||
if (mapped) {
|
if (mapped) {
|
||||||
|
|||||||
Reference in New Issue
Block a user