refactor: rebrand project to HartOMat
This commit is contained in:
+2
-2
@@ -2,9 +2,9 @@
|
||||
<html lang="en" class="" data-accent="green">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/schaeffler.svg" />
|
||||
<link rel="icon" type="image/svg+xml" href="/hartomat.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Hart.O.Mat — Hartomatisierung</title>
|
||||
<title>HartOMat</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet" />
|
||||
|
||||
Generated
+2
-2
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "schaefflerautomat-frontend",
|
||||
"name": "hartomat-frontend",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "schaefflerautomat-frontend",
|
||||
"name": "hartomat-frontend",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@react-three/drei": "^9.102.3",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "schaefflerautomat-frontend",
|
||||
"name": "hartomat-frontend",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" role="img" aria-labelledby="title">
|
||||
<title>HartOMat</title>
|
||||
<rect width="128" height="128" rx="28" fill="#0b3d2e"/>
|
||||
<path d="M28 32h18v24h36V32h18v64H82V72H46v24H28z" fill="#f3efe2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 259 B |
@@ -9,7 +9,7 @@ const api = axios.create({
|
||||
api.interceptors.request.use((config) => {
|
||||
const token = useAuthStore.getState().token
|
||||
if (token) config.headers.Authorization = `Bearer ${token}`
|
||||
const tenantId = localStorage.getItem('schaeffler_tenant_id')
|
||||
const tenantId = localStorage.getItem('hartomat_tenant_id')
|
||||
if (tenantId) config.headers['X-Tenant-ID'] = tenantId
|
||||
return config
|
||||
})
|
||||
|
||||
@@ -5,7 +5,7 @@ export interface Material {
|
||||
name: string
|
||||
description: string | null
|
||||
source: string
|
||||
schaeffler_code: number | null
|
||||
hartomat_code: number | null
|
||||
created_by_name: string | null
|
||||
aliases: string[]
|
||||
created_at: string
|
||||
@@ -27,7 +27,7 @@ export async function createMaterial(data: {
|
||||
name: string
|
||||
description?: string
|
||||
source?: string
|
||||
schaeffler_code?: number | null
|
||||
hartomat_code?: number | null
|
||||
}) {
|
||||
const res = await api.post<Material>('/materials', data)
|
||||
return res.data
|
||||
@@ -54,8 +54,8 @@ export async function saveCadPartMaterials(
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function seedSchaefflerMaterials() {
|
||||
const res = await api.post<{ inserted: number; total: number }>('/materials/seed-schaeffler')
|
||||
export async function seedHartOMatMaterials() {
|
||||
const res = await api.post<{ inserted: number; total: number }>('/materials/seed-hartomat')
|
||||
return res.data
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ export async function seedAliases(): Promise<{ inserted: number; total: number }
|
||||
export interface MaterialSuggestion {
|
||||
id: string
|
||||
name: string
|
||||
schaeffler_code: string
|
||||
hartomat_code: string
|
||||
}
|
||||
|
||||
export interface UnmappedMaterial {
|
||||
|
||||
@@ -98,10 +98,10 @@ export default function MaterialWizard({ open, onClose, onCreated }: Props) {
|
||||
.replace(/^-|-$/g, '')
|
||||
|
||||
const fullMaterialName = fullCode && sanitizedName
|
||||
? `SCHAEFFLER_${fullCode}_${sanitizedName}`
|
||||
? `HARTOMAT_${fullCode}_${sanitizedName}`
|
||||
: null
|
||||
|
||||
const schaefflerCodeInt = fullCode ? parseInt(fullCode, 10) : null
|
||||
const hartomatCodeInt = fullCode ? parseInt(fullCode, 10) : null
|
||||
|
||||
const createMut = useMutation({
|
||||
mutationFn: () =>
|
||||
@@ -109,7 +109,7 @@ export default function MaterialWizard({ open, onClose, onCreated }: Props) {
|
||||
name: fullMaterialName!,
|
||||
description: description.trim() || undefined,
|
||||
source: 'manual',
|
||||
schaeffler_code: schaefflerCodeInt,
|
||||
hartomat_code: hartomatCodeInt,
|
||||
}),
|
||||
onSuccess: () => {
|
||||
toast.success('Material created')
|
||||
@@ -133,7 +133,7 @@ export default function MaterialWizard({ open, onClose, onCreated }: Props) {
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between px-6 py-4 border-b border-border-default">
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-content">Schaeffler Material Wizard</h2>
|
||||
<h2 className="text-lg font-semibold text-content">HartOMat Material Wizard</h2>
|
||||
<p className="text-xs text-content-muted mt-0.5">Step {step} of 3</p>
|
||||
</div>
|
||||
<button onClick={onClose} className="text-content-muted hover:text-content-secondary">
|
||||
@@ -267,7 +267,7 @@ export default function MaterialWizard({ open, onClose, onCreated }: Props) {
|
||||
<p className="font-mono text-sm font-semibold text-content truncate">
|
||||
{fullMaterialName || (
|
||||
<span className="text-content-muted">
|
||||
SCHAEFFLER_{typeCode || 'XX'}{effectiveSubType || 'YY'}{consecutive !== null ? String(consecutive).padStart(2, '0') : 'ZZ'}_{sanitizedName || 'Name'}
|
||||
HARTOMAT_{typeCode || 'XX'}{effectiveSubType || 'YY'}{consecutive !== null ? String(consecutive).padStart(2, '0') : 'ZZ'}_{sanitizedName || 'Name'}
|
||||
</span>
|
||||
)}
|
||||
</p>
|
||||
|
||||
@@ -47,7 +47,7 @@ export default function OutputTypeTable() {
|
||||
queryKey: ['materials'],
|
||||
queryFn: listMaterials,
|
||||
})
|
||||
const libraryMaterials = (allMaterials ?? []).filter((m: Material) => m.schaeffler_code !== null).sort((a: Material, b: Material) => a.name.localeCompare(b.name))
|
||||
const libraryMaterials = (allMaterials ?? []).filter((m: Material) => m.hartomat_code !== null).sort((a: Material, b: Material) => a.name.localeCompare(b.name))
|
||||
|
||||
const { data: workflows } = useQuery({
|
||||
queryKey: ['workflows'],
|
||||
@@ -856,7 +856,7 @@ export default function OutputTypeTable() {
|
||||
<td className="px-4 py-2">
|
||||
{ot.material_override ? (
|
||||
<span className="text-xs px-1.5 py-0.5 rounded bg-amber-50 text-amber-700 font-mono truncate block max-w-[140px]" title={ot.material_override}>
|
||||
{ot.material_override.replace('SCHAEFFLER_', '').replace(/_/g, ' ')}
|
||||
{ot.material_override.replace('HARTOMAT_', '').replace(/_/g, ' ')}
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-xs text-content-muted">—</span>
|
||||
|
||||
@@ -15,7 +15,7 @@ export interface MaterialOut {
|
||||
id: string
|
||||
name: string
|
||||
description: string | null
|
||||
schaeffler_code: number | null
|
||||
hartomat_code: number | null
|
||||
source: string
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ export function pbrColorHex(pbr: MaterialPBR): string {
|
||||
|
||||
/**
|
||||
* Get a preview hex color for a material entry, using PBR data when available.
|
||||
* Replaces the old hardcoded SCHAEFFLER_COLORS lookup.
|
||||
* Replaces the old hardcoded HARTOMAT_COLORS lookup.
|
||||
*/
|
||||
export function previewColorForEntry(
|
||||
entry: PartMaterialEntry,
|
||||
|
||||
@@ -23,7 +23,7 @@ export default function ChatPanel({ open, onClose, contextType, contextId }: Cha
|
||||
const [messages, setMessages] = useState<ChatMessage[]>([])
|
||||
const [sessionId, setSessionId] = useState<string | undefined>(() => {
|
||||
// Restore last session from localStorage
|
||||
try { return localStorage.getItem('schaeffler-chat-session') || undefined } catch { return undefined }
|
||||
try { return localStorage.getItem('hartomat-chat-session') || undefined } catch { return undefined }
|
||||
})
|
||||
const [input, setInput] = useState('')
|
||||
const [showSessions, setShowSessions] = useState(false)
|
||||
@@ -31,8 +31,8 @@ export default function ChatPanel({ open, onClose, contextType, contextId }: Cha
|
||||
// Persist sessionId to localStorage
|
||||
useEffect(() => {
|
||||
try {
|
||||
if (sessionId) localStorage.setItem('schaeffler-chat-session', sessionId)
|
||||
else localStorage.removeItem('schaeffler-chat-session')
|
||||
if (sessionId) localStorage.setItem('hartomat-chat-session', sessionId)
|
||||
else localStorage.removeItem('hartomat-chat-session')
|
||||
} catch { /* ignore */ }
|
||||
}, [sessionId])
|
||||
const messagesEndRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
@@ -27,7 +27,7 @@ export default function UnmappedMaterialsDialog({ unmapped, onResolved, onCancel
|
||||
})
|
||||
|
||||
const libraryMaterials = (allMaterials ?? []).filter(
|
||||
(m: Material) => m.schaeffler_code !== null
|
||||
(m: Material) => m.hartomat_code !== null
|
||||
)
|
||||
|
||||
const allMapped = unmapped.every((u) => mappings[u.raw_name])
|
||||
|
||||
@@ -11,14 +11,14 @@ const TYPE_GROUPS: Record<string, { label: string; color: string }> = {
|
||||
}
|
||||
|
||||
function getTypeCode(mat: Material): string | null {
|
||||
if (mat.schaeffler_code == null) return null
|
||||
const s = String(mat.schaeffler_code).padStart(6, '0')
|
||||
if (mat.hartomat_code == null) return null
|
||||
const s = String(mat.hartomat_code).padStart(6, '0')
|
||||
return s.slice(0, 2)
|
||||
}
|
||||
|
||||
/** Extract the human-readable short name after the last underscore: SCHAEFFLER_010101_Steel-Bare -> Steel-Bare */
|
||||
/** Extract the human-readable short name after the last underscore: HARTOMAT_010101_Steel-Bare -> Steel-Bare */
|
||||
function shortName(name: string): string {
|
||||
const match = name.match(/^SCHAEFFLER_\d{6}_(.+)$/)
|
||||
const match = name.match(/^HARTOMAT_\d{6}_(.+)$/)
|
||||
return match ? match[1].replace(/-/g, ' ') : name
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ export default function MaterialInput({ value, onChange, library, missing, onOpe
|
||||
buckets.get(tc)!.push(m)
|
||||
}
|
||||
|
||||
// Sorted type codes first, then non-schaeffler
|
||||
// Sorted type codes first, then non-hartomat
|
||||
const sortedKeys = [...buckets.keys()].sort((a, b) => {
|
||||
if (a === null) return 1
|
||||
if (b === null) return -1
|
||||
|
||||
@@ -50,7 +50,7 @@ export const HELP_TEXTS: Record<string, HelpText> = {
|
||||
},
|
||||
'action.seed_aliases': {
|
||||
title: 'Seed Material Aliases',
|
||||
body: 'Loads the default Schaeffler material alias mappings (Steel→SCHAEFFLER_010101_Steel-Bare, etc). Safe to run multiple times — existing aliases are not overwritten.',
|
||||
body: 'Loads the default HartOMat material alias mappings (Steel→HARTOMAT_010101_Steel-Bare, etc). Safe to run multiple times — existing aliases are not overwritten.',
|
||||
},
|
||||
// Template fields
|
||||
'template.lighting_only': {
|
||||
@@ -64,7 +64,7 @@ export const HELP_TEXTS: Record<string, HelpText> = {
|
||||
},
|
||||
'template.material_replace_enabled': {
|
||||
title: 'Material Replacement',
|
||||
body: 'When enabled, Blender will replace part materials with the mapped Schaeffler library materials. When disabled, the original .blend materials are used.',
|
||||
body: 'When enabled, Blender will replace part materials with the mapped HartOMat library materials. When disabled, the original .blend materials are used.',
|
||||
},
|
||||
// Wizard fields
|
||||
'wizard.output_type': {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
Applied via data-accent="<key>" on <html>
|
||||
============================================================ */
|
||||
|
||||
/* Default / Schaeffler Green */
|
||||
/* Default / HartOMat Green */
|
||||
:root,
|
||||
[data-accent="green"] {
|
||||
--color-accent: #00893d;
|
||||
|
||||
@@ -12,7 +12,7 @@ import { useThemeStore, applyTheme, resolveTheme, type ThemeMode, type AccentKey
|
||||
--------------------------------------------------------------- */
|
||||
;(function () {
|
||||
try {
|
||||
const raw = localStorage.getItem('schaeffler-theme')
|
||||
const raw = localStorage.getItem('hartomat-theme')
|
||||
if (raw) {
|
||||
const { state } = JSON.parse(raw) as { state: { mode: ThemeMode; accent: AccentKey; customHex?: string } }
|
||||
applyTheme(state.mode ?? 'light', state.accent ?? 'green', state.customHex)
|
||||
|
||||
@@ -1549,7 +1549,7 @@ export default function AdminPage() {
|
||||
type="email"
|
||||
value={smtp.smtp_from_address ?? ''}
|
||||
onChange={(e) => setSmtpDraft(d => ({ ...d, smtp_from_address: e.target.value }))}
|
||||
placeholder="noreply@schaeffler.com"
|
||||
placeholder="noreply@hartomat.com"
|
||||
className="w-full px-3 py-1.5 rounded-md border border-border-default text-sm bg-surface text-content focus:outline-none focus:ring-2 focus:ring-accent"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -55,7 +55,7 @@ function UploadModal({ onClose }: { onClose: () => void }) {
|
||||
</label>
|
||||
<input
|
||||
className="input-base"
|
||||
placeholder="e.g. Schaeffler Materials v2"
|
||||
placeholder="e.g. HartOMat Materials v2"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
/>
|
||||
|
||||
@@ -36,7 +36,7 @@ export default function LoginPage() {
|
||||
<div className="w-16 h-16 bg-accent rounded-full flex items-center justify-center mx-auto mb-4">
|
||||
<span className="text-white text-2xl font-bold">S</span>
|
||||
</div>
|
||||
<h1 className="text-2xl font-bold text-content">Schaeffler Automat</h1>
|
||||
<h1 className="text-2xl font-bold text-content">HartOMat</h1>
|
||||
<p className="text-content-muted text-sm mt-1">Media Creation Pipeline</p>
|
||||
</div>
|
||||
|
||||
@@ -49,7 +49,7 @@ export default function LoginPage() {
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
className="input-base w-full"
|
||||
placeholder="admin@schaeffler.com"
|
||||
placeholder="admin@hartomat.com"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
} from 'lucide-react'
|
||||
import {
|
||||
listMaterials, createMaterial, updateMaterial, deleteMaterial,
|
||||
seedSchaefflerMaterials, addAlias, deleteAlias, seedAliases,
|
||||
seedHartOMatMaterials, addAlias, deleteAlias, seedAliases,
|
||||
batchCreateAliases,
|
||||
} from '../api/materials'
|
||||
import type { Material } from '../api/materials'
|
||||
@@ -24,8 +24,8 @@ const TYPE_GROUPS = [
|
||||
] as const
|
||||
|
||||
function getTypeCode(mat: Material): string | null {
|
||||
if (mat.schaeffler_code == null) return null
|
||||
return String(mat.schaeffler_code).padStart(6, '0').slice(0, 2)
|
||||
if (mat.hartomat_code == null) return null
|
||||
return String(mat.hartomat_code).padStart(6, '0').slice(0, 2)
|
||||
}
|
||||
|
||||
interface MaterialGroup {
|
||||
@@ -90,12 +90,12 @@ export default function MaterialsPage() {
|
||||
})
|
||||
|
||||
const seedMut = useMutation({
|
||||
mutationFn: seedSchaefflerMaterials,
|
||||
mutationFn: seedHartOMatMaterials,
|
||||
onSuccess: (data) => {
|
||||
if (data.inserted > 0) {
|
||||
toast.success(`Imported ${data.inserted} of ${data.total} Schaeffler standard materials`)
|
||||
toast.success(`Imported ${data.inserted} of ${data.total} HartOMat standard materials`)
|
||||
} else {
|
||||
toast.info('All Schaeffler standard materials already exist')
|
||||
toast.info('All HartOMat standard materials already exist')
|
||||
}
|
||||
qc.invalidateQueries({ queryKey: ['materials'] })
|
||||
},
|
||||
@@ -147,9 +147,9 @@ export default function MaterialsPage() {
|
||||
onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed to create alias'),
|
||||
})
|
||||
|
||||
// Library materials (have schaeffler_code) for quick-map dropdown
|
||||
// Library materials (have hartomat_code) for quick-map dropdown
|
||||
const libraryMaterials = useMemo(
|
||||
() => materials.filter((m) => m.schaeffler_code !== null).sort((a, b) => a.name.localeCompare(b.name)),
|
||||
() => materials.filter((m) => m.hartomat_code !== null).sort((a, b) => a.name.localeCompare(b.name)),
|
||||
[materials]
|
||||
)
|
||||
|
||||
@@ -203,7 +203,7 @@ export default function MaterialsPage() {
|
||||
buckets.delete(tg.code)
|
||||
}
|
||||
}
|
||||
// Custom / non-schaeffler materials
|
||||
// Custom / non-hartomat materials
|
||||
const custom = buckets.get(null)
|
||||
if (custom && custom.length > 0) {
|
||||
result.push({ code: null, label: 'Custom', icon: Plus, bg: 'bg-surface-alt', border: 'border-border-default', text: 'text-content-secondary', items: custom })
|
||||
@@ -239,7 +239,7 @@ export default function MaterialsPage() {
|
||||
setConfirmState({
|
||||
open: true,
|
||||
title: 'Import Standard Materials',
|
||||
message: 'Import 35 Schaeffler standard materials? Existing entries will be skipped.',
|
||||
message: 'Import 35 HartOMat standard materials? Existing entries will be skipped.',
|
||||
onConfirm: () => {
|
||||
seedMut.mutate()
|
||||
setConfirmState((s) => ({ ...s, open: false }))
|
||||
@@ -248,7 +248,7 @@ export default function MaterialsPage() {
|
||||
}}
|
||||
disabled={seedMut.isPending}
|
||||
className="btn-secondary text-sm flex items-center gap-1.5"
|
||||
title="Import the 35 standard Schaeffler SCHAEFFLER_... materials used in Blender material libraries. Existing entries are skipped."
|
||||
title="Import the 35 standard HartOMat HARTOMAT_... materials used in Blender material libraries. Existing entries are skipped."
|
||||
>
|
||||
<Download size={14} /> {seedMut.isPending ? 'Importing...' : 'Import Standards'}
|
||||
</button>
|
||||
@@ -266,16 +266,16 @@ export default function MaterialsPage() {
|
||||
}}
|
||||
disabled={seedAliasMut.isPending}
|
||||
className="btn-secondary text-sm flex items-center gap-1.5"
|
||||
title="Seed ~100 material aliases from the Schaeffler naming scheme (German descriptions, intermediate codes → SCHAEFFLER_... library names). Existing aliases are skipped."
|
||||
title="Seed ~100 material aliases from the HartOMat naming scheme (German descriptions, intermediate codes → HARTOMAT_... library names). Existing aliases are skipped."
|
||||
>
|
||||
<Tag size={14} /> {seedAliasMut.isPending ? 'Seeding...' : 'Seed Aliases'}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setShowWizard(true)}
|
||||
className="btn-secondary text-sm flex items-center gap-1.5"
|
||||
title="Open the Schaeffler Wizard — guided tool to set up SCHAEFFLER_... materials and aliases from the standard naming scheme"
|
||||
title="Open the HartOMat Wizard — guided tool to set up HARTOMAT_... materials and aliases from the standard naming scheme"
|
||||
>
|
||||
<Wand2 size={14} /> Schaeffler Wizard
|
||||
<Wand2 size={14} /> HartOMat Wizard
|
||||
</button>
|
||||
<button onClick={() => setShowAdd(!showAdd)} className="btn-primary">
|
||||
<Plus size={16} /> Add Material
|
||||
@@ -407,10 +407,10 @@ export default function MaterialsPage() {
|
||||
<>
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm font-medium text-content truncate">{mat.name}</p>
|
||||
{mat.schaeffler_code != null && (
|
||||
<p className="text-xs text-content-muted font-mono">Nr: {mat.schaeffler_code}</p>
|
||||
{mat.hartomat_code != null && (
|
||||
<p className="text-xs text-content-muted font-mono">Nr: {mat.hartomat_code}</p>
|
||||
)}
|
||||
{mat.schaeffler_code == null && mat.aliases.length === 0 && (
|
||||
{mat.hartomat_code == null && mat.aliases.length === 0 && (
|
||||
<div className="flex items-center gap-1.5 mt-1">
|
||||
<span className="inline-flex items-center gap-1 text-[10px] font-medium text-amber-600 bg-amber-50 px-1.5 py-0.5 rounded">
|
||||
<AlertTriangle size={10} /> No alias
|
||||
@@ -614,7 +614,7 @@ function AliasPill({
|
||||
}
|
||||
|
||||
function SourceBadge({ source }: { source: string }) {
|
||||
if (source === 'schaeffler_standard') {
|
||||
if (source === 'hartomat_standard') {
|
||||
return (
|
||||
<span className="inline-flex items-center gap-1 text-xs font-medium bg-status-success-bg text-status-success-text px-2 py-0.5 rounded-full">
|
||||
Standard
|
||||
|
||||
@@ -81,7 +81,7 @@ export default function NewProductOrderPage() {
|
||||
queryFn: listMaterials,
|
||||
enabled: step >= 3,
|
||||
})
|
||||
const libMaterials = (allMaterials ?? []).filter((m: Material) => m.schaeffler_code !== null).sort((a: Material, b: Material) => a.name.localeCompare(b.name))
|
||||
const libMaterials = (allMaterials ?? []).filter((m: Material) => m.hartomat_code !== null).sort((a: Material, b: Material) => a.name.localeCompare(b.name))
|
||||
|
||||
function initPositionsForProduct(product: Product, globals: GlobalRenderPosition[] = []) {
|
||||
// Pre-select all per-product positions (if any)
|
||||
@@ -822,10 +822,10 @@ export default function NewProductOrderPage() {
|
||||
value={lineOverrides[line.key] ?? ''}
|
||||
onChange={(e) => setLineOverrides((prev) => ({ ...prev, [line.key]: e.target.value }))}
|
||||
>
|
||||
<option value="">{materialOverride ? `Global: ${materialOverride.replace('SCHAEFFLER_', '').replace(/_/g, ' ')}` : 'No override'}</option>
|
||||
<option value="">{materialOverride ? `Global: ${materialOverride.replace('HARTOMAT_', '').replace(/_/g, ' ')}` : 'No override'}</option>
|
||||
{materialOverride && <option value="__none__">— No override (clear) —</option>}
|
||||
{libMaterials.map((m: Material) => (
|
||||
<option key={m.id} value={m.name}>{m.name.replace('SCHAEFFLER_', '').replace(/_/g, ' ')}</option>
|
||||
<option key={m.id} value={m.name}>{m.name.replace('HARTOMAT_', '').replace(/_/g, ' ')}</option>
|
||||
))}
|
||||
</select>
|
||||
</td>
|
||||
|
||||
@@ -140,7 +140,7 @@ export default function OrderDetailPage() {
|
||||
}
|
||||
|
||||
const { data: matList } = useQuery({ queryKey: ['materials'], queryFn: listMaterials })
|
||||
const orderLibMats = (matList ?? []).filter((m: Material) => m.schaeffler_code !== null).sort((a: Material, b: Material) => a.name.localeCompare(b.name))
|
||||
const orderLibMats = (matList ?? []).filter((m: Material) => m.hartomat_code !== null).sort((a: Material, b: Material) => a.name.localeCompare(b.name))
|
||||
|
||||
const batchOverrideMut = useMutation({
|
||||
mutationFn: (val: string | null) => batchMaterialOverride(id!, val),
|
||||
@@ -660,7 +660,7 @@ export default function OrderDetailPage() {
|
||||
<option value="">Apply to all lines…</option>
|
||||
<option value="__clear__">— Clear all overrides —</option>
|
||||
{orderLibMats.map((m: Material) => (
|
||||
<option key={m.id} value={m.name}>{m.name.replace('SCHAEFFLER_', '').replace(/_/g, ' ')}</option>
|
||||
<option key={m.id} value={m.name}>{m.name.replace('HARTOMAT_', '').replace(/_/g, ' ')}</option>
|
||||
))}
|
||||
</select>
|
||||
{batchOverrideMut.isPending && <Loader2 size={14} className="animate-spin text-accent" />}
|
||||
@@ -1017,7 +1017,7 @@ function OrderLineRow({
|
||||
})
|
||||
|
||||
const { data: allMats } = useQuery({ queryKey: ['materials'], queryFn: listMaterials })
|
||||
const libMats = (allMats ?? []).filter((m: Material) => m.schaeffler_code !== null).sort((a: Material, b: Material) => a.name.localeCompare(b.name))
|
||||
const libMats = (allMats ?? []).filter((m: Material) => m.hartomat_code !== null).sort((a: Material, b: Material) => a.name.localeCompare(b.name))
|
||||
|
||||
const overrideMut = useMutation({
|
||||
mutationFn: (val: string | null) => patchOrderLine(orderId, line.id, { material_override: val }),
|
||||
@@ -1112,7 +1112,7 @@ function OrderLineRow({
|
||||
onClick={() => setShowOverride(!showOverride)}
|
||||
title="Click to change material override"
|
||||
>
|
||||
{line.material_override.replace('SCHAEFFLER_', '').replace(/_/g, ' ')}
|
||||
{line.material_override.replace('HARTOMAT_', '').replace(/_/g, ' ')}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => overrideMut.mutate(null)}
|
||||
@@ -1131,7 +1131,7 @@ function OrderLineRow({
|
||||
>
|
||||
<option value="">No material override</option>
|
||||
{libMats.map((m: Material) => (
|
||||
<option key={m.id} value={m.name}>{m.name.replace('SCHAEFFLER_', '').replace(/_/g, ' ')}</option>
|
||||
<option key={m.id} value={m.name}>{m.name.replace('HARTOMAT_', '').replace(/_/g, ' ')}</option>
|
||||
))}
|
||||
</select>
|
||||
)}
|
||||
@@ -1147,7 +1147,7 @@ function OrderLineRow({
|
||||
>
|
||||
<option value="">No material override</option>
|
||||
{libMats.map((m: Material) => (
|
||||
<option key={m.id} value={m.name}>{m.name.replace('SCHAEFFLER_', '').replace(/_/g, ' ')}</option>
|
||||
<option key={m.id} value={m.name}>{m.name.replace('HARTOMAT_', '').replace(/_/g, ' ')}</option>
|
||||
))}
|
||||
</select>
|
||||
) : (
|
||||
|
||||
@@ -14,7 +14,7 @@ export default function PreferencesPage() {
|
||||
return (
|
||||
<div className="p-8 max-w-2xl">
|
||||
<h1 className="text-2xl font-bold text-content mb-1">Preferences</h1>
|
||||
<p className="text-sm text-content-muted mb-8">Customize your Schaeffler Automat experience.</p>
|
||||
<p className="text-sm text-content-muted mb-8">Customize your HartOMat experience.</p>
|
||||
|
||||
{/* Appearance */}
|
||||
<section className="card p-6 space-y-6">
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
} from '../api/tenants'
|
||||
import type { Tenant, TenantCreate, TenantUpdate, TenantAIConfig, TenantAIConfigUpdate } from '../api/tenants'
|
||||
|
||||
const TENANT_CONTEXT_KEY = 'schaeffler_tenant_id'
|
||||
const TENANT_CONTEXT_KEY = 'hartomat_tenant_id'
|
||||
|
||||
function slugify(name: string): string {
|
||||
return name
|
||||
@@ -392,7 +392,7 @@ export default function TenantsPage() {
|
||||
type="text"
|
||||
value={createForm.name}
|
||||
onChange={(e) => handleCreateNameChange(e.target.value)}
|
||||
placeholder="e.g. Schaeffler GmbH"
|
||||
placeholder="e.g. HartOMat GmbH"
|
||||
className="w-full px-3 py-2 rounded-md border border-border-default bg-surface text-content text-sm focus:outline-none focus:ring-2 focus:ring-accent/50"
|
||||
/>
|
||||
</div>
|
||||
@@ -406,7 +406,7 @@ export default function TenantsPage() {
|
||||
type="text"
|
||||
value={createForm.slug}
|
||||
onChange={(e) => handleCreateSlugChange(e.target.value)}
|
||||
placeholder="e.g. schaeffler-gmbh"
|
||||
placeholder="e.g. hartomat-gmbh"
|
||||
className="w-full px-3 py-2 rounded-md border border-border-default bg-surface text-content text-sm font-mono focus:outline-none focus:ring-2 focus:ring-accent/50"
|
||||
/>
|
||||
</div>
|
||||
@@ -677,7 +677,7 @@ export default function TenantsPage() {
|
||||
rows={4}
|
||||
value={aiForm.ai_validation_prompt ?? ''}
|
||||
onChange={(e) => setAIForm((prev) => ({ ...prev, ai_validation_prompt: e.target.value || null }))}
|
||||
placeholder="Optional: override the default Schaeffler bearing analysis prompt"
|
||||
placeholder="Optional: override the default HartOMat bearing analysis prompt"
|
||||
className="w-full px-3 py-2 rounded-md border border-border-default bg-surface text-content text-sm resize-y focus:outline-none focus:ring-2 focus:ring-accent/50"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -32,6 +32,6 @@ export const useAuthStore = create<AuthState>()(
|
||||
setAuth: (token, user) => set({ token, user }),
|
||||
logout: () => set({ token: null, user: null }),
|
||||
}),
|
||||
{ name: 'schaeffler-auth' },
|
||||
{ name: 'hartomat-auth' },
|
||||
),
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ export type ThemeMode = 'light' | 'dark' | 'system'
|
||||
export type AccentKey = 'green' | 'blue' | 'purple' | 'amber' | 'teal' | 'custom'
|
||||
|
||||
export const ACCENT_PRESETS: { key: AccentKey; label: string; hex: string }[] = [
|
||||
{ key: 'green', label: 'Schaeffler Green', hex: '#00893d' },
|
||||
{ key: 'green', label: 'HartOMat Green', hex: '#00893d' },
|
||||
{ key: 'blue', label: 'Blue', hex: '#2563eb' },
|
||||
{ key: 'purple', label: 'Purple', hex: '#7c3aed' },
|
||||
{ key: 'amber', label: 'Amber', hex: '#d97706' },
|
||||
@@ -115,6 +115,6 @@ export const useThemeStore = create<ThemeState>()(
|
||||
applyTheme(get().mode, 'custom', hex)
|
||||
},
|
||||
}),
|
||||
{ name: 'schaeffler-theme' },
|
||||
{ name: 'hartomat-theme' },
|
||||
),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user