Start work on the signin page

This commit is contained in:
Eli Ribble 2026-03-23 14:24:24 -07:00
parent da62cc8f98
commit ea318af65f
No known key found for this signature in database
5 changed files with 163 additions and 2 deletions

View file

@ -1,6 +1,6 @@
<template>
<div class="app-container">
<Sidebar />
<Sidebar v-if="$route.meta.showSidebar" />
<MainContent>
<div v-if="userStore.loading">Loading...</div>
<div v-else-if="userStore.error">Error: {{ userStore.error }}</div>

View file

@ -12,10 +12,12 @@ import ConfigurationRoot from "./view/configuration/Root.vue";
import ConfigurationUser from "./view/configuration/User.vue";
import ConfigurationUserAdd from "./view/configuration/UserAdd.vue";
import Intelligence from "./view/Intelligence.vue";
import NotFound from "./view/NotFound.vue";
import OAuthRefreshArcgis from "./view/OAuthRefreshArcgis.vue";
import Operations from "./view/Operations.vue";
import Planning from "./view/Planning.vue";
import Review from "./view/Review.vue";
import Signin from "./view/Signin.vue";
import Sudo from "./view/Sudo.vue";
const routes: RouteRecordRaw[] = [
@ -23,87 +25,137 @@ const routes: RouteRecordRaw[] = [
path: "/",
name: "Home",
component: Home,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/communication",
name: "Communication",
component: Communication,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/configuration",
name: "Configuration",
component: ConfigurationRoot,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/configuration/integration",
name: "Integration Configuration",
component: ConfigurationIntegration,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/configuration/integration/arcgis",
name: "Arcgis Integration Configuration",
component: ConfigurationIntegrationArcgis,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/configuration/organization",
name: "Organization Configuration",
component: ConfigurationOrganization,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/configuration/pesticide",
name: "Pesticide Configuration",
component: ConfigurationPesticide,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/configuration/pesticide/add",
name: "Pesticide Add",
component: ConfigurationPesticideAdd,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/configuration/user",
name: "User Configuration",
component: ConfigurationUser,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/configuration/user/add",
name: "User Add Configuration",
component: ConfigurationUserAdd,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/intelligence",
name: "Intelligence",
component: Intelligence,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/oauth/refresh/arcgis",
name: "Arcgis OAuth Refresh",
component: OAuthRefreshArcgis,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/operations",
name: "Operations",
component: Operations,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/planning",
name: "Planning",
component: Planning,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/review",
name: "Review",
component: Review,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/signin",
name: "Signin",
component: Signin,
meta: { requiresAuth: false, showSidebar: false },
},
{
path: "/sudo",
name: "Sudo",
component: Sudo,
meta: { requiresAuth: true, showSidebar: true },
},
// Catch-all route - must be last
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: NotFound
}
];
const router = createRouter({
history: createWebHistory("/"),
routes,
});
// Global navigation guard
router.beforeEach(async (to, from, next) => {
const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
if (requiresAuth) {
try {
// Check if user is authenticated (could be an API call)
const isAuthenticated = await checkAuth();
if (!isAuthenticated) {
next('/signin');
} else {
next();
}
} catch (error) {
console.log("check auth failed");
next('/signin');
}
} else {
next();
}
});
export default router;

3
ts/view/NotFound.vue Normal file
View file

@ -0,0 +1,3 @@
<template>
<p>No idea where you wanted to go with that one.</p>
</template>

102
ts/view/Signin.vue Normal file
View file

@ -0,0 +1,102 @@
<style scoped>
.login-container {
max-width: 900px;
margin: 0 auto;
}
.login-box {
box-shadow: 0 0 15px rgba(0, 0, 0, 0.1);
border-radius: 10px;
overflow: hidden;
}
.login-form-section {
padding: 40px;
}
.product-info-section {
padding: 40px;
background-color: #f8f9fa;
}
.login-header {
margin-bottom: 25px;
}
</style>
<template>
<div
class="container min-vh-100 d-flex align-items-center justify-content-center py-5"
>
<div class="login-container">
<div class="row login-box g-0">
<!-- Left side: Login Form -->
<div class="col-md-6 login-form-section">
<div class="login-header">
<h2>Welcome Back</h2>
<p class="text-muted">Please enter your credentials</p>
</div>
<form method="POST" action="/signin">
<input type="hidden" name="next" value="none" />
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<input
type="text"
class="form-control"
name="username"
required
/>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input
type="password"
class="form-control"
name="password"
required
/>
</div>
<!--
<div class="alert alert-danger" role="alert">
The credentials you provided weren't recognized.
</div>
-->
<div class="d-grid gap-2">
<button type="submit" class="btn btn-primary">Login</button>
</div>
<div class="mt-3 text-center">
<p>Don't have an account? <a href="/signup">Sign up</a></p>
<a href="forgot-password.html">Forgot password?</a>
</div>
</form>
</div>
<!-- Right side: Product Information -->
<div class="col-md-6 product-info-section">
<div>
<img src="/static/img/nidus-logo-256-transparent.png" />
<h2>Nidus Sync</h2>
<p class="lead mb-4">
All your field data, sync'd to all your techs
</p>
<div class="mb-4">
<p>Something intelligent and intriguing</p>
</div>
<div class="mb-4">
<h5>Key Features</h5>
<ul>
<li>Works with <b>Fieldseeker</b></li>
<li>Works <i>with</i> Fieldseeker</li>
<li><b>Works</b> with Fieldseeker</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</template>

View file

@ -51,7 +51,11 @@ export default defineConfig({
proxy: {
"/api": {
target: "http://127.0.0.1:9002",
changeOrigin: true,
changeOrigin: false,
},
"/signin": {
target: "http://localhost:9002",
changeOrigin: false,
},
"/signup": {
target: "http://localhost:9002",