fixed build issues. its builds now
This commit is contained in:
@@ -4,7 +4,7 @@ import { useEffect, useMemo, useState } from "react";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useParams, useRouter, useSearchParams } from "next/navigation";
|
import { useParams, useRouter, useSearchParams } from "next/navigation";
|
||||||
|
|
||||||
import type { CategoryId } from "@/types/builderSlots";
|
import type { BuilderSlotKey } from "@/types/builderSlots";
|
||||||
import { PART_ROLE_TO_CATEGORY, normalizePartRole } from "@/lib/catalogMappings";
|
import { PART_ROLE_TO_CATEGORY, normalizePartRole } from "@/lib/catalogMappings";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,7 +46,7 @@ type GunbuilderProductFromApi = {
|
|||||||
offers?: OfferFromApi[] | null;
|
offers?: OfferFromApi[] | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
type BuildState = Partial<Record<CategoryId, string>>;
|
type BuildState = Partial<Record<BuilderSlotKey, string>>;
|
||||||
|
|
||||||
const API_BASE_URL =
|
const API_BASE_URL =
|
||||||
process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://localhost:8080";
|
process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://localhost:8080";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { useAuth } from "@/context/AuthContext";
|
import { useAuth } from "@/context/AuthContext";
|
||||||
import {
|
import {
|
||||||
fetchEmailRequests,
|
fetchEmailRequests,
|
||||||
@@ -32,13 +32,13 @@ export default function AdminEmailPage() {
|
|||||||
|
|
||||||
const [statusTab, setStatusTab] = useState<EmailStatusTab>("ALL");
|
const [statusTab, setStatusTab] = useState<EmailStatusTab>("ALL");
|
||||||
|
|
||||||
const loadEmails = async () => {
|
const loadEmails = useCallback(async () => {
|
||||||
if (!token) return;
|
if (!token) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const data = await fetchEmailRequests(token);
|
const data = await fetchEmailRequests(token);
|
||||||
setEmails(data.data);
|
setEmails(data);
|
||||||
setError(null);
|
setError(null);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
@@ -46,11 +46,11 @@ export default function AdminEmailPage() {
|
|||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
};
|
}, [token]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadEmails();
|
loadEmails();
|
||||||
}, [token]);
|
}, [loadEmails]);
|
||||||
|
|
||||||
const normalizeStatus = (s: unknown) => String(s ?? "").trim().toUpperCase();
|
const normalizeStatus = (s: unknown) => String(s ?? "").trim().toUpperCase();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { useAuth } from "@/context/AuthContext";
|
import { useAuth } from "@/context/AuthContext";
|
||||||
import {
|
import {
|
||||||
fetchEmailRequests,
|
fetchEmailRequests,
|
||||||
@@ -27,13 +27,13 @@ export default function AdminEmailPage() {
|
|||||||
});
|
});
|
||||||
const [submitting, setSubmitting] = useState(false);
|
const [submitting, setSubmitting] = useState(false);
|
||||||
|
|
||||||
const loadEmails = async () => {
|
const loadEmails = useCallback(async () => {
|
||||||
if (!token) return;
|
if (!token) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const data = await fetchEmailRequests(token);
|
const data = await fetchEmailRequests(token);
|
||||||
setEmails(data.data);
|
setEmails(data);
|
||||||
setError(null);
|
setError(null);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
@@ -41,11 +41,11 @@ export default function AdminEmailPage() {
|
|||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
};
|
}, [token]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadEmails();
|
loadEmails();
|
||||||
}, [token]);
|
}, [loadEmails]);
|
||||||
|
|
||||||
const handleCreate = () => {
|
const handleCreate = () => {
|
||||||
setModalMode("create");
|
setModalMode("create");
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { sendEmailAction, type ApiResponse, type EmailRequest } from "/app/actions/sendEmail";
|
import { sendEmailAction, type ApiResponse, type EmailRequest } from "@/app/actions/sendEmail";
|
||||||
import { Button, Field, Input, Textarea } from "@/components/ui/form";
|
import { Button, Field, Input, Textarea } from "@/components/ui/form";
|
||||||
|
|
||||||
export default function SendEmailForm(): JSX.Element {
|
export default function SendEmailForm(): JSX.Element {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { useApi } from "@/lib/useApi";
|
import { useApi } from "@/lib/useApi";
|
||||||
|
|
||||||
type Merchant = {
|
type Merchant = {
|
||||||
@@ -91,7 +91,7 @@ export default function MerchantCategoryMappingPage() {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
// 2) Load mappings when merchant changes (THIS sends merchantId)
|
// 2) Load mappings when merchant changes (THIS sends merchantId)
|
||||||
useEffect(() => {
|
const loadMappings = useCallback(() => {
|
||||||
if (selectedMerchantId == null) return;
|
if (selectedMerchantId == null) return;
|
||||||
|
|
||||||
setLoadingMappings(true);
|
setLoadingMappings(true);
|
||||||
@@ -112,7 +112,11 @@ export default function MerchantCategoryMappingPage() {
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
.finally(() => setLoadingMappings(false));
|
.finally(() => setLoadingMappings(false));
|
||||||
}, [selectedMerchantId]);
|
}, [selectedMerchantId, get]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadMappings();
|
||||||
|
}, [loadMappings]);
|
||||||
|
|
||||||
// 3) Save a single mapping row (adjust endpoint if yours differs)
|
// 3) Save a single mapping row (adjust endpoint if yours differs)
|
||||||
const handleSaveMapping = async (
|
const handleSaveMapping = async (
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useMemo, useState } from "react";
|
import { useCallback, useMemo, useState } from "react";
|
||||||
import type { CaliberDto, PlatformDto } from "../_lib/types";
|
import type { CaliberDto, PlatformDto } from "../_lib/types";
|
||||||
import { RightDrawer } from "./RightDrawer";
|
import { RightDrawer } from "./RightDrawer";
|
||||||
|
|
||||||
@@ -91,12 +91,10 @@ export function BulkBar(props: {
|
|||||||
|
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
if (selectedCount <= 0) return null;
|
|
||||||
|
|
||||||
const disabled = loading || selectedCount <= 0;
|
const disabled = loading || selectedCount <= 0;
|
||||||
|
|
||||||
// one button to apply staged field updates
|
// one button to apply staged field updates
|
||||||
const applyFieldChanges = () => {
|
const applyFieldChanges = useCallback(() => {
|
||||||
const patch: BulkUpdateSet = { classificationReason: "Admin bulk override" };
|
const patch: BulkUpdateSet = { classificationReason: "Admin bulk override" };
|
||||||
|
|
||||||
if (bulkPlatformKey) {
|
if (bulkPlatformKey) {
|
||||||
@@ -121,7 +119,9 @@ export function BulkBar(props: {
|
|||||||
if (keys.length === 0) return;
|
if (keys.length === 0) return;
|
||||||
|
|
||||||
runBulk(patch);
|
runBulk(patch);
|
||||||
};
|
}, [bulkPlatformKey, bulkPlatformLock, bulkRole, bulkRoleLock, bulkCaliber, bulkCaliberGroup, bulkCaliberLock, bulkForceCaliber, runBulk]);
|
||||||
|
|
||||||
|
if (selectedCount <= 0) return null;
|
||||||
|
|
||||||
let footer: JSX.Element;
|
let footer: JSX.Element;
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ export default function BetaMagicPage() {
|
|||||||
// We can simulate "login" by directly setting localStorage like AuthContext does,
|
// We can simulate "login" by directly setting localStorage like AuthContext does,
|
||||||
// but easiest is just to store it here in the same shape.
|
// but easiest is just to store it here in the same shape.
|
||||||
setSession(data.token ?? data.accessToken, {
|
setSession(data.token ?? data.accessToken, {
|
||||||
|
uuid: data.uuid ?? data.id,
|
||||||
email: data.email,
|
email: data.email,
|
||||||
displayName: data.displayName ?? null,
|
displayName: data.displayName ?? null,
|
||||||
role: data.role ?? "USER",
|
role: data.role ?? "USER",
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import type { PriceHistoryPoint } from "@/app/(app)/(builder)/parts/__DELETE[partRole]/_old_prod_details/data";
|
type PriceHistoryPoint = {
|
||||||
|
date: string;
|
||||||
|
price: number;
|
||||||
|
};
|
||||||
|
|
||||||
interface PricingHistoryGraphProps {
|
interface PricingHistoryGraphProps {
|
||||||
data: PriceHistoryPoint[];
|
data: PriceHistoryPoint[];
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import type { RetailerOffer } from "@/app/(app)/(builder)/parts/__DELETE[partRole]/_old_prod_details/data";
|
type RetailerOffer = {
|
||||||
|
id?: string | number;
|
||||||
|
retailer: string;
|
||||||
|
price: number;
|
||||||
|
originalPrice?: number;
|
||||||
|
url: string;
|
||||||
|
affiliateUrl?: string;
|
||||||
|
inStock: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
interface RetailersListProps {
|
interface RetailersListProps {
|
||||||
retailers: RetailerOffer[];
|
retailers: RetailerOffer[];
|
||||||
@@ -46,7 +54,7 @@ export function RetailersList({ retailers }: RetailersListProps) {
|
|||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<div className="flex items-center gap-2 mb-1">
|
<div className="flex items-center gap-2 mb-1">
|
||||||
<span className="text-sm font-semibold text-zinc-50">
|
<span className="text-sm font-semibold text-zinc-50">
|
||||||
{retailer.retailerName}
|
{retailer.retailer}
|
||||||
</span>
|
</span>
|
||||||
{isLowestPrice && retailer.inStock && (
|
{isLowestPrice && retailer.inStock && (
|
||||||
<span className="text-[0.65rem] font-semibold uppercase tracking-wide px-1.5 py-0.5 rounded bg-amber-400/20 text-amber-300 border border-amber-400/30">
|
<span className="text-[0.65rem] font-semibold uppercase tracking-wide px-1.5 py-0.5 rounded bg-amber-400/20 text-amber-300 border border-amber-400/30">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { sendEmailAction, type ApiResponse, type EmailRequest } from "/app/actions/sendEmail";
|
import { sendEmailAction, type ApiResponse, type EmailRequest } from "@/app/actions/sendEmail";
|
||||||
import { Button, Field, Input, Textarea } from "@/components/ui/form";
|
import { Button, Field, Input, Textarea } from "@/components/ui/form";
|
||||||
|
|
||||||
export default function SendEmailForm(): JSX.Element {
|
export default function SendEmailForm(): JSX.Element {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { sendEmailAction, type ApiResponse, type EmailRequest } from "/app/actions/sendEmail";
|
import { sendEmailAction, type ApiResponse, type EmailRequest } from "@/app/actions/sendEmail";
|
||||||
import { Button, Field, Input } from "@/components/ui/form";
|
import { Button, Field, Input } from "@/components/ui/form";
|
||||||
import RichTextEditor from "@/components/ui/RichTextEditor";
|
import RichTextEditor from "@/components/ui/RichTextEditor";
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import QuillImageResize from "quill-image-resize-module";
|
|
||||||
Quill.register("modules/imageResize", QuillImageResize);
|
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
import type React from "react";
|
import type React from "react";
|
||||||
|
|
||||||
import "react-quill/dist/quill.snow.css";
|
import "react-quill/dist/quill.snow.css";
|
||||||
|
|
||||||
|
// Import Quill modules after React Quill is loaded
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
const Quill = require('quill');
|
||||||
|
const QuillImageResize = require('quill-image-resize-module').default;
|
||||||
|
Quill.register("modules/imageResize", QuillImageResize);
|
||||||
|
}
|
||||||
|
|
||||||
const ReactQuill = dynamic(() => import("react-quill"), { ssr: false });
|
const ReactQuill = dynamic(() => import("react-quill"), { ssr: false });
|
||||||
|
|
||||||
type RichTextEditorProps = {
|
type RichTextEditorProps = {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { sendEmailAction, type ApiResponse, type EmailRequest } from "/app/actions/sendEmail";
|
import { sendEmailAction, type ApiResponse, type EmailRequest } from "@/app/actions/sendEmail";
|
||||||
import { Button, Field, Input } from "@/components/ui/form";
|
import { Button, Field, Input } from "@/components/ui/form";
|
||||||
import RichTextEditor from "@/components/ui/RichTextEditor";
|
import RichTextEditor from "@/components/ui/RichTextEditor";
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
// /lib/buildOverlaps.ts
|
// /lib/buildOverlaps.ts
|
||||||
import type { CategoryId } from "@/types/builderSlots";
|
import type { BuilderSlotKey } from "@/types/builderSlots";
|
||||||
|
|
||||||
|
type CategoryId = BuilderSlotKey;
|
||||||
|
|
||||||
export type OverlapChipModel = {
|
export type OverlapChipModel = {
|
||||||
key: string;
|
key: string;
|
||||||
@@ -25,10 +27,10 @@ export const UPPER_OVERLAP_CATEGORIES = new Set<CategoryId>([
|
|||||||
|
|
||||||
export const LOWER_OVERLAP_CATEGORIES = new Set<CategoryId>([
|
export const LOWER_OVERLAP_CATEGORIES = new Set<CategoryId>([
|
||||||
"lower-receiver",
|
"lower-receiver",
|
||||||
"lower-parts",
|
"lower-parts-kit",
|
||||||
"trigger",
|
"trigger",
|
||||||
"grip",
|
"grip",
|
||||||
"safety",
|
"safety-selector",
|
||||||
"buffer",
|
"buffer",
|
||||||
"stock",
|
"stock",
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export const CATEGORY_TO_PART_ROLES: Partial<Record<BuilderSlotKey, string[]>> =
|
|||||||
"lower-parts-kit": ["lower-parts-kit", "lower-parts"],
|
"lower-parts-kit": ["lower-parts-kit", "lower-parts"],
|
||||||
trigger: ["trigger", "trigger-kit"],
|
trigger: ["trigger", "trigger-kit"],
|
||||||
grip: ["pistol-grip", "grip"],
|
grip: ["pistol-grip", "grip"],
|
||||||
safety: ["safety", "safety-selector"],
|
"safety-selector": ["safety", "safety-selector"],
|
||||||
buffer: ["buffer-kit", "buffer"],
|
buffer: ["buffer-kit", "buffer"],
|
||||||
stock: ["stock"],
|
stock: ["stock"],
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -2,15 +2,15 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
REGISTRY="gitea.gofwd.group"
|
REGISTRY="gitea.gofwd.group"
|
||||||
OWNER="sean/shadow-gunbuilder-ai-proto"
|
OWNER="forward_group/ballistic-builder-spring"
|
||||||
IMAGE="battlbuilder"
|
IMAGE="spring-api"
|
||||||
|
|
||||||
TAG=$(git rev-parse --short HEAD)
|
TAG=$(git rev-parse --short HEAD)
|
||||||
|
|
||||||
FULL_IMAGE="$REGISTRY/$OWNER/$IMAGE"
|
FULL_IMAGE="$REGISTRY/$OWNER/$IMAGE"
|
||||||
|
|
||||||
echo "Building $FULL_IMAGE:$TAG"
|
echo "Building $FULL_IMAGE:$TAG"
|
||||||
docker build -f frontend/Dockerfile -t $FULL_IMAGE:$TAG .
|
docker build -f docker/backend/Dockerfile -t $FULL_IMAGE:$TAG .
|
||||||
|
|
||||||
echo "Tagging latest"
|
echo "Tagging latest"
|
||||||
docker tag $FULL_IMAGE:$TAG $FULL_IMAGE:latest
|
docker tag $FULL_IMAGE:$TAG $FULL_IMAGE:latest
|
||||||
|
|||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
declare module 'quill-image-resize-module' {
|
||||||
|
const QuillImageResize: any;
|
||||||
|
export default QuillImageResize;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user