236 lines
8.9 KiB
JavaScript
236 lines
8.9 KiB
JavaScript
/**
|
|
* Simple React-like Vanilla JS Implementation
|
|
*/
|
|
|
|
// --- 1. The "Library" Logic ---
|
|
|
|
// Helper to create DOM elements (like React.createElement)
|
|
function h(tag, props = {}, ...children) {
|
|
const el = document.createElement(tag);
|
|
|
|
// Handle props
|
|
if (props) {
|
|
Object.entries(props).forEach(([key, value]) => {
|
|
if (key.startsWith('on') && typeof value === 'function') {
|
|
el.addEventListener(key.substring(2).toLowerCase(), value);
|
|
} else if (key === 'className') {
|
|
el.className = value;
|
|
} else if (key === 'style' && typeof value === 'object') {
|
|
Object.assign(el.style, value);
|
|
} else {
|
|
el.setAttribute(key, value);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Handle children
|
|
children.forEach(child => {
|
|
if (typeof child === 'string' || typeof child === 'number') {
|
|
el.appendChild(document.createTextNode(child));
|
|
} else if (child instanceof Node) {
|
|
el.appendChild(child);
|
|
} else if (Array.isArray(child)) {
|
|
child.forEach(c => el.appendChild(c));
|
|
}
|
|
});
|
|
|
|
return el;
|
|
}
|
|
|
|
// Simple Rendering Logic
|
|
let _rootContainer = null;
|
|
let _rootComponent = null;
|
|
|
|
function render(component, container) {
|
|
_rootContainer = container;
|
|
_rootComponent = component;
|
|
_render();
|
|
}
|
|
|
|
function _render() {
|
|
_rootContainer.innerHTML = ''; // Clear previous tree (simple re-render)
|
|
_rootContainer.appendChild(_rootComponent());
|
|
}
|
|
|
|
// Simple State Hook (Global for simplicity, or localized using closures)
|
|
// Note: In a real app this would be more complex to handle multiple components.
|
|
// For this demo, we'll re-render the whole app on state change.
|
|
const createSignal = (initialValue) => {
|
|
let _val = initialValue;
|
|
const getValue = () => _val;
|
|
const setValue = (newValue) => {
|
|
_val = typeof newValue === 'function' ? newValue(_val) : newValue;
|
|
_render(); // Trigger re-render
|
|
};
|
|
return [getValue, setValue];
|
|
};
|
|
|
|
// --- 2. The Application Components ---
|
|
|
|
// Global View State: 'home', 'login', 'create'
|
|
const [getView, setView] = createSignal('home');
|
|
|
|
// Header Component
|
|
function Header({ title }) {
|
|
return h('div', { className: 'header' },
|
|
h('h1', {
|
|
style: { cursor: 'pointer' },
|
|
onClick: () => setView('home')
|
|
}, title),
|
|
h('p', null, 'Organization Registration & Management Portal')
|
|
);
|
|
}
|
|
|
|
// Login Form Component
|
|
function LoginForm() {
|
|
const handleSubmit = (e) => {
|
|
e.preventDefault(); // Critical for strict sandbox
|
|
const formData = new FormData(e.target);
|
|
const data = Object.fromEntries(formData.entries());
|
|
console.log('Login Attempt:', data);
|
|
// TODO: Handle authentication logic here
|
|
};
|
|
|
|
return h('div', { className: 'card', style: { maxWidth: '400px', margin: '0 auto' } },
|
|
h('h2', null, 'Organization Login'),
|
|
h('form', { onSubmit: handleSubmit },
|
|
h('div', null,
|
|
h('label', null, 'Email'),
|
|
h('input', { name: 'email', type: 'text', placeholder: 'admin@spearnet.mil' })
|
|
),
|
|
h('div', null,
|
|
h('label', null, 'Password'),
|
|
h('input', { name: 'password', type: 'password', placeholder: '••••••••' })
|
|
),
|
|
h('div', { className: 'form-actions' },
|
|
h('button', { type: 'submit', style: { width: '100%' } }, 'Access Authenticator'),
|
|
h('span', {
|
|
className: 'cancel-link',
|
|
onClick: () => setView('home')
|
|
}, 'Cancel / Return to Main')
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
// Create Org Form Component
|
|
function CreateOrgForm() {
|
|
const handleSubmit = (e) => {
|
|
e.preventDefault(); // Critical for strict sandbox
|
|
const formData = new FormData(e.target);
|
|
const data = Object.fromEntries(formData.entries());
|
|
console.log('Org Registration:', data);
|
|
// TODO: Handle registration logic here
|
|
};
|
|
|
|
return h('div', { className: 'split-container' },
|
|
h('div', { className: 'info-panel' },
|
|
h('h2', null, 'Registration Details'),
|
|
h('p', null, 'Complete the form to add your organization to the Global Organization Registry.'),
|
|
h('ul', { style: { textAlign: 'left', marginTop: '1.5rem', listStyleType: 'none', padding: 0 } },
|
|
h('li', { style: { marginBottom: '0.5rem' } }, '✅ Official Organization Designator'),
|
|
h('li', { style: { marginBottom: '0.5rem' } }, '✅ Secure Comms Channel'),
|
|
h('li', { style: { marginBottom: '0.5rem' } }, '✅ Deployment Roster Access'),
|
|
h('li', { style: { marginBottom: '0.5rem' } }, '✅ After-Action Report Tools')
|
|
),
|
|
h('div', { className: 'price-tag', style: { marginTop: '2rem', padding: '1rem', background: 'var(--bg-app)', borderRadius: 'var(--radius)', border: '1px solid var(--border)' } },
|
|
h('span', { style: { display: 'block', fontSize: '0.9rem', color: 'var(--text-muted)' } }, 'Registration Fee'),
|
|
h('span', { style: { display: 'block', fontSize: '2rem', fontWeight: '700', color: 'var(--primary)' } }, '$50,000')
|
|
)
|
|
),
|
|
h('div', { className: 'form-panel card', style: { margin: 0 } },
|
|
h('h2', null, 'Organization Registration'),
|
|
h('form', { onSubmit: handleSubmit },
|
|
h('div', null,
|
|
h('label', null, 'Organization Name'),
|
|
h('input', { name: 'orgName', type: 'text', placeholder: 'e.g. Task Force 141' })
|
|
),
|
|
h('div', null,
|
|
h('label', null, 'Organization Type'),
|
|
h('select', { name: 'type' },
|
|
h('option', { value: 'infantry' }, 'Infantry / Milsim'),
|
|
h('option', { value: 'aviation' }, 'Aviation Wing'),
|
|
h('option', { value: 'pmc' }, 'Private Military Company'),
|
|
h('option', { value: 'support' }, 'Logistics & Support')
|
|
)
|
|
),
|
|
h('div', { className: 'form-actions' },
|
|
h('button', { type: 'submit', style: { width: '100%' } }, 'Submit Registration'),
|
|
h('span', {
|
|
className: 'cancel-link',
|
|
onClick: () => setView('home')
|
|
}, 'Cancel / Return to Main')
|
|
)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
// Home View Component
|
|
function HomeView() {
|
|
return h('div', { className: 'content' },
|
|
h('div', { className: 'card' },
|
|
h('h2', null, 'Create Organization'),
|
|
h('p', null, 'Establish your Task Force, PMC, or Milsim unit with the Global Organization Network. Receive your official unit designator and TO&E authorization instantly.'),
|
|
h('button', { onClick: () => setView('create') }, 'Register')
|
|
),
|
|
h('div', { className: 'card' },
|
|
h('h2', null, 'Organization Dashboard'),
|
|
h('p', null, 'Access your unit dashboard to modify rosters, adjust active deployments, and submit after-action reports through the secure field uplink.'),
|
|
h('button', { onClick: () => setView('login') }, 'Login')
|
|
)
|
|
);
|
|
}
|
|
|
|
// Footer Component (unchanged)
|
|
function Footer() {
|
|
return h('div', { className: 'footer' },
|
|
h('div', { className: 'wrapper' },
|
|
h('div', null,
|
|
h('h3', null, 'Registry Resources'),
|
|
h('ul', { style: { listStyleType: 'none', padding: 0 } },
|
|
h('li', null, 'Registration Guidelines'),
|
|
h('li', null, 'Tax & Fee Schedule'),
|
|
h('li', null, 'Legal Compliance'),
|
|
h('li', null, 'Trademark Database')
|
|
)
|
|
),
|
|
h('div', null,
|
|
h('h3', null, 'Bureau Support'),
|
|
h('ul', { style: { listStyleType: 'none', padding: 0 } },
|
|
h('li', null, 'Office: Sector 7 Admin Block'),
|
|
h('li', null, 'Hours: 0800 - 1600 (GST)'),
|
|
h('li', null, 'Helpdesk: 555-01-REGISTRY'),
|
|
h('li', null, 'support@org-bureau.gov')
|
|
)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
// Main App Component
|
|
function App() {
|
|
const view = getView();
|
|
|
|
let mainContent;
|
|
if (view === 'home') {
|
|
mainContent = HomeView();
|
|
} else if (view === 'login') {
|
|
mainContent = LoginForm();
|
|
} else if (view === 'create') {
|
|
mainContent = CreateOrgForm();
|
|
}
|
|
|
|
return h('main', null,
|
|
h('div', { className: 'container' },
|
|
Header({ title: 'Global Organization Network' }),
|
|
mainContent
|
|
),
|
|
Footer()
|
|
);
|
|
}
|
|
|
|
// --- 3. Mount Application ---
|
|
const root = document.getElementById('app');
|
|
render(App, root);
|