Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e9c027d
fix: reset password page wrong callback + params usage
neue-dev Jun 6, 2026
0daa980
fix: add csp
jayylmao Jun 6, 2026
f75ba59
fix: add csp (#478)
jayylmao Jun 6, 2026
f55bc12
fix: allow pdfs through csp
jayylmao Jun 6, 2026
3cb0dc7
fix: allow pdfs through csp (#479)
jayylmao Jun 6, 2026
304615f
chore: update jspdf
jayylmao Jun 6, 2026
6f7ef6b
chore: update jspdf (#480)
jayylmao Jun 6, 2026
6143dd7
feat: https strict transport security
jayylmao Jun 6, 2026
a00cfd4
feat: add security headers
jayylmao Jun 6, 2026
6a56391
fix: incorrect permissions-policy header
jayylmao Jun 6, 2026
0faf9a6
fix: clear query client on logout for hire and student
jayylmao Jun 6, 2026
08f3082
chore: update postcss
jayylmao Jun 6, 2026
9cd663f
fix: additional security patches (#481)
jayylmao Jun 6, 2026
3c4bea3
fix: remove unnecessary unsafe csp exceptions
jayylmao Jun 7, 2026
abc75cf
fix: remove unnecessary unsafe csp exceptions (#482)
jayylmao Jun 7, 2026
a1e5bcd
fix: blank page on deploy due to strict csp
jayylmao Jun 7, 2026
1ec5677
fix: blank page on deploy due to strict csp (#483)
jayylmao Jun 7, 2026
90be3e9
fix: add cloudflare to script csp exceptions
jayylmao Jun 7, 2026
a81cff1
fix: add cloudflare to script csp exceptions (#484)
jayylmao Jun 7, 2026
55798d0
fix: add google storage to connect csp exceptions
jayylmao Jun 7, 2026
54c07ca
fix: add google storage to connect csp exceptions (#485)
jayylmao Jun 7, 2026
16ef0d4
chore: use PDF viewer from package now
anaj00 Jun 8, 2026
d740ba7
chore: use PDF viewer from package (#486)
anaj00 Jun 8, 2026
70caa70
feat: use signed url to access bucket documents
neue-dev Jun 8, 2026
a3ca8c6
chore: fixed autofill spilling into the form filler, and inconsistent…
anaj00 Jun 9, 2026
0b4edcb
refactor: remove initiatorFieldNames memoization and adjust filtering…
anaj00 Jun 9, 2026
a8d3046
chore: add our bucket to image origin
anaj00 Jun 9, 2026
3213971
chore: update signature field prompt and disable name input
anaj00 Jun 11, 2026
7d0592f
Merge branch 'main' into develop
neue-dev Jun 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions app/hire/authctx.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,7 @@ export const AuthContextProvider = ({

const logout = async () => {
await EmployerAuthService.logout();

await queryClient.invalidateQueries({ queryKey: ["my-employer-profile"] });
await queryClient.invalidateQueries({
queryKey: ["my-employer-conversations"],
});

queryClient.clear();
router.push("/login");
setUser(null);
setGod(false);
Expand Down
8 changes: 4 additions & 4 deletions app/student/forms/components/FormActionButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useFormRendererContext } from "@/components/features/student/forms/form
import { Button } from "@/components/ui/button";
import useModalRegistry from "@/components/modals/modal-registry";
import { cn } from "@/lib/utils";
import { resolveSignedUrl } from "@/lib/signed-url";

export const FormActionButtons = ({
handleSignViaBetterInternship,
Expand All @@ -30,11 +31,10 @@ export const FormActionButtons = ({
size="lg"
className="w-full text-lg sm:w-auto"
variant="outline"
onClick={() => {
onClick={async () => {
if (form.document.url) {
modalRegistry.previewFormPdf.open({
documentUrl: form.document.url,
});
const resolved = await resolveSignedUrl(form.document.url);
modalRegistry.previewFormPdf.open({ documentUrl: resolved });
} else {
alert("No document url provided for preview.");
}
Expand Down
70 changes: 62 additions & 8 deletions app/student/forms/components/FormSigningLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"use client";

import { ArrowLeft, LucideClipboardCheck, MailWarningIcon } from "lucide-react";
import { FormPreviewPdfDisplay } from "@/components/features/student/forms/previewer";
import { FormFillPdfViewer } from "@betterinternship/core/pdf-viewer";
import { useSignedUrl } from "@/lib/signed-url";
import { FormFillerRenderer } from "@/components/features/student/forms/FormFillerRenderer";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
Expand Down Expand Up @@ -29,6 +30,7 @@ import { getRecipientEmailErrors } from "./recipient-email-validation";
import { useSignContext } from "@/components/providers/sign.ctx";
import { withSubmittedSignatureImages } from "@/lib/signature-image-submit";
import { useProfileData } from "@/lib/api/student.data.api";
import { useDbRefs } from "@/lib/db/use-refs";

interface FlowTestSigningLayoutProps {
formLabel?: string;
Expand Down Expand Up @@ -114,8 +116,10 @@ export function FormSigningLayout({
noEsign,
onBack,
}: FlowTestSigningLayoutProps) {
const { url: resolvedDocumentUrl } = useSignedUrl(documentUrl ?? "");
const form = useFormRendererContext();
const profile = useProfileData();
const refs = useDbRefs();
const modalRegistry = useModalRegistry();
const formFiller = useFormFiller();
const autofillValues = useMyAutofill();
Expand Down Expand Up @@ -326,10 +330,57 @@ export function FormSigningLayout({
() => withDerivedFormValues(form.formMetadata, previewValues),
[form.formMetadata, previewValues],
);
const previewValuesResolved = useMemo(() => {
const resolved = { ...previewValuesWithDerived };
for (const [key, value] of Object.entries(previewValuesWithDerived)) {
if (!value) continue;
const trimmed = String(value).trim();
const keyLower = key.toLowerCase();
if (keyLower.includes("university") && refs.to_university_name) {
resolved[key] = refs.to_university_name(trimmed, trimmed) ?? trimmed;
} else if (keyLower.includes("college") && refs.to_college_name) {
resolved[key] = refs.to_college_name(trimmed, trimmed) ?? trimmed;
} else if (keyLower.includes("department") && refs.to_department_name) {
resolved[key] = refs.to_department_name(trimmed, trimmed) ?? trimmed;
}
}
return resolved;
}, [previewValuesWithDerived, refs]);
const previewValuesForViewer = useMemo(() => {
if (noEsign) return previewValuesResolved;
const filtered: Record<string, string> = {};
for (const key of Object.keys(previewValuesResolved)) {
const normalized = key.replace(/:default$/i, "").replace(/:auto$/i, "");
const owner =
fieldOwnerByName.get(normalized) ?? fieldOwnerByName.get(key);
if (owner !== undefined && owner !== "initiator") continue;
filtered[key] = previewValuesResolved[key];
}
return filtered;
}, [previewValuesResolved, fieldOwnerByName, noEsign]);
const wetSignatureHiddenFieldNames = useMemo(
() => (noEsign ? getSignatureDerivedFieldNames(form.formMetadata) : []),
[form.formMetadata, noEsign],
);
const previewBlocksForViewer = useMemo(() => {
const hiddenSet = new Set(
wetSignatureHiddenFieldNames.map(normalizeFieldName),
);
const raw = noEsign
? previewKeyedFields.filter(
(field) =>
field.type !== "signature" &&
!hiddenSet.has(normalizeFieldName(field.field)),
)
: previewKeyedFields;
return raw.map((field) => ({
...field,
id:
field.id ||
field._id ||
`${field.field}:${field.page}:${field.x}:${field.y}`,
}));
}, [previewKeyedFields, noEsign, wetSignatureHiddenFieldNames]);

const computeRequiredFieldsComplete = useCallback(
(nextValues: FormValues) =>
Expand Down Expand Up @@ -838,23 +889,26 @@ export function FormSigningLayout({
</div>
</div>
)}
{documentUrl ? (
{resolvedDocumentUrl ? (
<>
<FormPreviewPdfDisplay
<FormFillPdfViewer
key={isMobileLayout ? "mobile-preview" : "desktop-preview"}
documentUrl={documentUrl}
blocks={previewKeyedFields}
values={previewValuesWithDerived}
documentUrl={resolvedDocumentUrl}
blocks={previewBlocksForViewer}
values={previewValuesForViewer}
fieldErrors={formFiller.errors}
selectionTick={selectionTick}
autoScrollToSelectedField={
!isMobileLayout && selectedFieldSource === "form"
}
signingParties={recipients}
wetSignatureMode={!!noEsign}
hiddenFieldNames={wetSignatureHiddenFieldNames}
onFieldClick={handlePdfFieldSelect}
selectedFieldId={form.selectedPreviewId ?? undefined}
scale={isMobile ? 0.5 : 0.9}
prefillUser={profile.data as Record<string, unknown> | null}
showOwnership={!noEsign}
fieldVisibility="all"
currentSigningPartyId={!noEsign ? "initiator" : undefined}
/>
</>
) : (
Expand Down
22 changes: 14 additions & 8 deletions components/features/student/forms/SignatureFieldRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -330,15 +330,21 @@ export const SignatureFieldRenderer = <T extends any[]>({
<div className="space-y-4 rounded-[0.33em] border border-gray-300 p-4 px-5">
<div className="space-y-1.5">
<p className="text-xs text-slate-500">
Enter your full legal name, then choose one signature method.
Full name auto-filled from your profile.
</p>
<FormInput
value={typedName ?? ""}
setter={handleTypedNameChange}
className="w-full"
placeholder="Enter full legal name"
onBlur={() => onBlur?.(value)}
/>
<div
title="Edit your name in your Profile settings"
className="relative"
>
<FormInput
value={typedName ?? ""}
setter={handleTypedNameChange}
className="w-full cursor-not-allowed opacity-80"
placeholder="Enter full legal name"
onBlur={() => onBlur?.(value)}
disabled
/>
</div>
</div>
<div className="space-y-2">
<LabelWithTooltip label="Signature method" />
Expand Down
12 changes: 0 additions & 12 deletions components/features/student/forms/form-previewer.ctx.tsx

This file was deleted.

Loading