@mindbill/react 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +120 -1
- package/dist/index.js +735 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.tsx
|
|
4
4
|
import "@mindbill/embed";
|
|
5
|
-
import { createElement, useEffect as
|
|
5
|
+
import { createElement, useEffect as useEffect4, useRef as useRef3 } from "react";
|
|
6
6
|
|
|
7
7
|
// src/native-bill-review.tsx
|
|
8
8
|
import { useEffect, useId, useMemo, useState } from "react";
|
|
@@ -676,11 +676,740 @@ function ConnectedBillStatus({
|
|
|
676
676
|
);
|
|
677
677
|
}
|
|
678
678
|
|
|
679
|
+
// src/connected-bill-lifecycle.tsx
|
|
680
|
+
import {
|
|
681
|
+
useCallback as useCallback2,
|
|
682
|
+
useEffect as useEffect3,
|
|
683
|
+
useMemo as useMemo3,
|
|
684
|
+
useRef as useRef2,
|
|
685
|
+
useState as useState3
|
|
686
|
+
} from "react";
|
|
687
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
688
|
+
var DEFAULT_API_BASE_URL2 = "https://app.mindbill.org";
|
|
689
|
+
var DEFAULT_SESSION_ENDPOINT2 = "/api/mindbill/bill-session";
|
|
690
|
+
var DEFAULT_REFRESH_INTERVAL2 = 6e4;
|
|
691
|
+
async function responseError2(response, fallback) {
|
|
692
|
+
const body = await response.json().catch(() => null);
|
|
693
|
+
const detail = body && typeof body === "object" ? body.detail ?? body.message ?? body.error : null;
|
|
694
|
+
return new Error(typeof detail === "string" ? detail : fallback);
|
|
695
|
+
}
|
|
696
|
+
function isSessionFresh2(session) {
|
|
697
|
+
if (!session) return false;
|
|
698
|
+
if (!session.expiresAt) return true;
|
|
699
|
+
const expiresAt = new Date(session.expiresAt).getTime();
|
|
700
|
+
return Number.isFinite(expiresAt) && expiresAt > Date.now() + 3e4;
|
|
701
|
+
}
|
|
702
|
+
function normalizeSession2(value) {
|
|
703
|
+
if (!value || typeof value !== "object") {
|
|
704
|
+
throw new Error("The MindBill session endpoint returned an invalid response.");
|
|
705
|
+
}
|
|
706
|
+
const candidate = value;
|
|
707
|
+
const nested = candidate.session ?? candidate.data;
|
|
708
|
+
const session = nested && typeof nested === "object" ? nested : candidate;
|
|
709
|
+
if (typeof session.token !== "string" || session.token.length < 8) {
|
|
710
|
+
throw new Error(
|
|
711
|
+
"The MindBill session endpoint did not return a browser session token."
|
|
712
|
+
);
|
|
713
|
+
}
|
|
714
|
+
return {
|
|
715
|
+
token: session.token,
|
|
716
|
+
...typeof session.expiresAt === "string" ? { expiresAt: session.expiresAt } : {},
|
|
717
|
+
...typeof session.apiBaseUrl === "string" ? { apiBaseUrl: session.apiBaseUrl } : {}
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
function normalizeLifecycle(value) {
|
|
721
|
+
if (!value || typeof value !== "object") {
|
|
722
|
+
throw new Error("MindBill returned an invalid bill lifecycle.");
|
|
723
|
+
}
|
|
724
|
+
const data = value;
|
|
725
|
+
if (!data.bill || !data.patient || !data.injury || !data.lifecycle || !Array.isArray(data.lifecycle.actions) || !Array.isArray(data.eors)) {
|
|
726
|
+
throw new Error("MindBill returned an invalid bill lifecycle.");
|
|
727
|
+
}
|
|
728
|
+
return data;
|
|
729
|
+
}
|
|
730
|
+
function idempotencyKey() {
|
|
731
|
+
if (typeof globalThis.crypto?.randomUUID === "function") {
|
|
732
|
+
return globalThis.crypto.randomUUID();
|
|
733
|
+
}
|
|
734
|
+
return `mb-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
735
|
+
}
|
|
736
|
+
function createBillLifecycleClient({
|
|
737
|
+
billId,
|
|
738
|
+
sessionEndpoint = DEFAULT_SESSION_ENDPOINT2,
|
|
739
|
+
getSession,
|
|
740
|
+
apiBaseUrl = DEFAULT_API_BASE_URL2,
|
|
741
|
+
fetch: fetchOverride
|
|
742
|
+
}) {
|
|
743
|
+
const fetcher = fetchOverride ?? globalThis.fetch;
|
|
744
|
+
if (typeof fetcher !== "function") {
|
|
745
|
+
throw new Error("A Fetch API implementation is required.");
|
|
746
|
+
}
|
|
747
|
+
let session = null;
|
|
748
|
+
let sessionRequest = null;
|
|
749
|
+
const mintSession = async (signal, force = false) => {
|
|
750
|
+
if (!force && isSessionFresh2(session)) return session;
|
|
751
|
+
if (!force && sessionRequest) return sessionRequest;
|
|
752
|
+
const pending = getSession ? getSession({ billId, component: "bill-review", signal }) : fetcher(sessionEndpoint, {
|
|
753
|
+
method: "POST",
|
|
754
|
+
credentials: "same-origin",
|
|
755
|
+
headers: { "content-type": "application/json" },
|
|
756
|
+
body: JSON.stringify({ billId, component: "bill-review" }),
|
|
757
|
+
signal
|
|
758
|
+
}).then(async (response) => {
|
|
759
|
+
if (!response.ok) {
|
|
760
|
+
throw await responseError2(
|
|
761
|
+
response,
|
|
762
|
+
"MindBill browser session could not be created."
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
return response.json();
|
|
766
|
+
});
|
|
767
|
+
const request2 = Promise.resolve(pending).then(normalizeSession2).then((nextSession) => {
|
|
768
|
+
session = nextSession;
|
|
769
|
+
return nextSession;
|
|
770
|
+
}).finally(() => {
|
|
771
|
+
if (sessionRequest === request2) sessionRequest = null;
|
|
772
|
+
});
|
|
773
|
+
sessionRequest = request2;
|
|
774
|
+
return request2;
|
|
775
|
+
};
|
|
776
|
+
const request = async (path, init = {}, providedSignal) => {
|
|
777
|
+
const controller = providedSignal ? null : new AbortController();
|
|
778
|
+
const signal = providedSignal ?? controller?.signal;
|
|
779
|
+
if (!signal) throw new Error("An AbortSignal could not be created.");
|
|
780
|
+
let browserSession = await mintSession(signal);
|
|
781
|
+
const perform = (current) => {
|
|
782
|
+
const base = (current.apiBaseUrl ?? apiBaseUrl).replace(/\/$/, "");
|
|
783
|
+
const headers = new Headers(init.headers);
|
|
784
|
+
headers.set("authorization", `Bearer ${current.token}`);
|
|
785
|
+
return fetcher(`${base}${path}`, { ...init, headers, signal });
|
|
786
|
+
};
|
|
787
|
+
let response = await perform(browserSession);
|
|
788
|
+
if (response.status === 401) {
|
|
789
|
+
session = null;
|
|
790
|
+
browserSession = await mintSession(signal, true);
|
|
791
|
+
response = await perform(browserSession);
|
|
792
|
+
}
|
|
793
|
+
return response;
|
|
794
|
+
};
|
|
795
|
+
const loadLifecycle = async (signal) => {
|
|
796
|
+
const response = await request("/embed/api/bill-lifecycle", {}, signal);
|
|
797
|
+
if (!response.ok) {
|
|
798
|
+
throw await responseError2(response, "Bill lifecycle could not be loaded.");
|
|
799
|
+
}
|
|
800
|
+
const body = await response.json();
|
|
801
|
+
return normalizeLifecycle(body.data);
|
|
802
|
+
};
|
|
803
|
+
const mutation = async (path, init, fallback) => {
|
|
804
|
+
const headers = new Headers(init.headers);
|
|
805
|
+
headers.set("idempotency-key", idempotencyKey());
|
|
806
|
+
const response = await request(path, { ...init, headers });
|
|
807
|
+
if (!response.ok) throw await responseError2(response, fallback);
|
|
808
|
+
return response;
|
|
809
|
+
};
|
|
810
|
+
const action = async (input, fallback) => {
|
|
811
|
+
const response = await mutation(
|
|
812
|
+
"/embed/api/bill-lifecycle/actions",
|
|
813
|
+
{
|
|
814
|
+
method: "POST",
|
|
815
|
+
headers: { "content-type": "application/json" },
|
|
816
|
+
body: JSON.stringify(input)
|
|
817
|
+
},
|
|
818
|
+
fallback
|
|
819
|
+
);
|
|
820
|
+
const body = await response.json();
|
|
821
|
+
return normalizeLifecycle(body.data);
|
|
822
|
+
};
|
|
823
|
+
const saveReview = async (input) => {
|
|
824
|
+
await mutation(
|
|
825
|
+
"/embed/api/bill-review",
|
|
826
|
+
{
|
|
827
|
+
method: "PATCH",
|
|
828
|
+
headers: { "content-type": "application/json" },
|
|
829
|
+
body: JSON.stringify(input)
|
|
830
|
+
},
|
|
831
|
+
"Bill changes could not be saved."
|
|
832
|
+
);
|
|
833
|
+
return loadLifecycle();
|
|
834
|
+
};
|
|
835
|
+
return {
|
|
836
|
+
clearSession() {
|
|
837
|
+
session = null;
|
|
838
|
+
sessionRequest = null;
|
|
839
|
+
},
|
|
840
|
+
getLifecycle: loadLifecycle,
|
|
841
|
+
saveReview,
|
|
842
|
+
async submitBill(input, route) {
|
|
843
|
+
await saveReview(input);
|
|
844
|
+
await mutation(
|
|
845
|
+
"/embed/api/bill-review/submit",
|
|
846
|
+
{
|
|
847
|
+
method: "POST",
|
|
848
|
+
headers: { "content-type": "application/json" },
|
|
849
|
+
body: JSON.stringify({ route })
|
|
850
|
+
},
|
|
851
|
+
"Bill could not be submitted."
|
|
852
|
+
);
|
|
853
|
+
return loadLifecycle();
|
|
854
|
+
},
|
|
855
|
+
async addAttachment(file, documentType, description) {
|
|
856
|
+
const body = new FormData();
|
|
857
|
+
body.set("file", file);
|
|
858
|
+
body.set("documentType", documentType);
|
|
859
|
+
if (description) body.set("description", description);
|
|
860
|
+
await mutation(
|
|
861
|
+
"/embed/api/bill-review/attachments",
|
|
862
|
+
{ method: "POST", body },
|
|
863
|
+
"Document could not be attached."
|
|
864
|
+
);
|
|
865
|
+
return loadLifecycle();
|
|
866
|
+
},
|
|
867
|
+
async removeAttachment(attachmentId) {
|
|
868
|
+
await mutation(
|
|
869
|
+
`/embed/api/bill-review/attachments/${encodeURIComponent(attachmentId)}`,
|
|
870
|
+
{ method: "DELETE" },
|
|
871
|
+
"Document could not be removed."
|
|
872
|
+
);
|
|
873
|
+
return loadLifecycle();
|
|
874
|
+
},
|
|
875
|
+
async getAttachment(attachmentId) {
|
|
876
|
+
const response = await request(
|
|
877
|
+
`/embed/api/bill-review/attachments/${encodeURIComponent(attachmentId)}`
|
|
878
|
+
);
|
|
879
|
+
if (!response.ok) {
|
|
880
|
+
throw await responseError2(response, "Document could not be opened.");
|
|
881
|
+
}
|
|
882
|
+
return response.blob();
|
|
883
|
+
},
|
|
884
|
+
async getEor(documentId) {
|
|
885
|
+
const response = await request(
|
|
886
|
+
`/embed/api/bill-lifecycle/eor/${encodeURIComponent(documentId)}`
|
|
887
|
+
);
|
|
888
|
+
if (!response.ok) throw await responseError2(response, "EOR could not be opened.");
|
|
889
|
+
return response.blob();
|
|
890
|
+
},
|
|
891
|
+
closeBill(input) {
|
|
892
|
+
return action({ action: "close", ...input }, "Bill could not be closed.");
|
|
893
|
+
},
|
|
894
|
+
postPayment(input) {
|
|
895
|
+
return action(
|
|
896
|
+
{ action: "post_payment", ...input, checkNumber: input.checkNumber ?? "" },
|
|
897
|
+
"Payment could not be posted."
|
|
898
|
+
);
|
|
899
|
+
},
|
|
900
|
+
submitSecondReview(input) {
|
|
901
|
+
return action(
|
|
902
|
+
{ action: "second_review", ...input },
|
|
903
|
+
"Second Review could not be submitted."
|
|
904
|
+
);
|
|
905
|
+
},
|
|
906
|
+
async startCorrection() {
|
|
907
|
+
const response = await mutation(
|
|
908
|
+
"/embed/api/bill-lifecycle/actions",
|
|
909
|
+
{
|
|
910
|
+
method: "POST",
|
|
911
|
+
headers: { "content-type": "application/json" },
|
|
912
|
+
body: JSON.stringify({ action: "start_correction" })
|
|
913
|
+
},
|
|
914
|
+
"Correction draft could not be created."
|
|
915
|
+
);
|
|
916
|
+
const body = await response.json();
|
|
917
|
+
if (typeof body.replacementBillId !== "string") {
|
|
918
|
+
throw new Error("MindBill did not return the correction bill ID.");
|
|
919
|
+
}
|
|
920
|
+
return {
|
|
921
|
+
replacementBillId: body.replacementBillId,
|
|
922
|
+
data: normalizeLifecycle(body.data)
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
};
|
|
926
|
+
}
|
|
927
|
+
function openPdf(blob, filename) {
|
|
928
|
+
const url = URL.createObjectURL(blob);
|
|
929
|
+
const link = document.createElement("a");
|
|
930
|
+
link.href = url;
|
|
931
|
+
link.target = "_blank";
|
|
932
|
+
link.rel = "noopener noreferrer";
|
|
933
|
+
link.download = filename;
|
|
934
|
+
link.click();
|
|
935
|
+
window.setTimeout(() => URL.revokeObjectURL(url), 6e4);
|
|
936
|
+
}
|
|
937
|
+
function useBillLifecycle({
|
|
938
|
+
billId: providedBillId,
|
|
939
|
+
sessionEndpoint = DEFAULT_SESSION_ENDPOINT2,
|
|
940
|
+
getSession,
|
|
941
|
+
apiBaseUrl = DEFAULT_API_BASE_URL2,
|
|
942
|
+
refreshInterval = DEFAULT_REFRESH_INTERVAL2,
|
|
943
|
+
enabled = true,
|
|
944
|
+
initialData = null,
|
|
945
|
+
onBillIdChange,
|
|
946
|
+
fetch: fetchOverride
|
|
947
|
+
}) {
|
|
948
|
+
const [billId, setBillId] = useState3(providedBillId);
|
|
949
|
+
const [data, setData] = useState3(initialData);
|
|
950
|
+
const [error, setError] = useState3(null);
|
|
951
|
+
const [isLoading, setIsLoading] = useState3(enabled && !initialData);
|
|
952
|
+
const [isRefreshing, setIsRefreshing] = useState3(false);
|
|
953
|
+
const [isMutating, setIsMutating] = useState3(false);
|
|
954
|
+
const mounted = useRef2(true);
|
|
955
|
+
useEffect3(() => {
|
|
956
|
+
setBillId(providedBillId);
|
|
957
|
+
setData(initialData);
|
|
958
|
+
setError(null);
|
|
959
|
+
}, [initialData, providedBillId]);
|
|
960
|
+
const client = useMemo3(() => createBillLifecycleClient({
|
|
961
|
+
billId,
|
|
962
|
+
sessionEndpoint,
|
|
963
|
+
getSession,
|
|
964
|
+
apiBaseUrl,
|
|
965
|
+
fetch: fetchOverride
|
|
966
|
+
}), [apiBaseUrl, billId, fetchOverride, getSession, sessionEndpoint]);
|
|
967
|
+
useEffect3(() => {
|
|
968
|
+
mounted.current = true;
|
|
969
|
+
return () => {
|
|
970
|
+
mounted.current = false;
|
|
971
|
+
client.clearSession();
|
|
972
|
+
};
|
|
973
|
+
}, [client]);
|
|
974
|
+
const refresh = useCallback2(async () => {
|
|
975
|
+
if (!enabled) return;
|
|
976
|
+
setIsRefreshing(true);
|
|
977
|
+
try {
|
|
978
|
+
const next = await client.getLifecycle();
|
|
979
|
+
if (!mounted.current) return;
|
|
980
|
+
setData(next);
|
|
981
|
+
setError(null);
|
|
982
|
+
} catch (cause) {
|
|
983
|
+
if (!mounted.current) return;
|
|
984
|
+
setError(cause instanceof Error ? cause : new Error("Bill could not be loaded."));
|
|
985
|
+
} finally {
|
|
986
|
+
if (mounted.current) {
|
|
987
|
+
setIsLoading(false);
|
|
988
|
+
setIsRefreshing(false);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
}, [client, enabled]);
|
|
992
|
+
useEffect3(() => {
|
|
993
|
+
if (!enabled) return;
|
|
994
|
+
void refresh();
|
|
995
|
+
const interval = refreshInterval > 0 ? window.setInterval(() => void refresh(), refreshInterval) : null;
|
|
996
|
+
const onFocus = () => void refresh();
|
|
997
|
+
window.addEventListener("focus", onFocus);
|
|
998
|
+
return () => {
|
|
999
|
+
if (interval) window.clearInterval(interval);
|
|
1000
|
+
window.removeEventListener("focus", onFocus);
|
|
1001
|
+
};
|
|
1002
|
+
}, [enabled, refresh, refreshInterval]);
|
|
1003
|
+
const mutate = useCallback2(async (task) => {
|
|
1004
|
+
setIsMutating(true);
|
|
1005
|
+
setError(null);
|
|
1006
|
+
try {
|
|
1007
|
+
const next = await task();
|
|
1008
|
+
if (mounted.current) setData(next);
|
|
1009
|
+
return next;
|
|
1010
|
+
} catch (cause) {
|
|
1011
|
+
const nextError = cause instanceof Error ? cause : new Error("MindBill could not complete this request.");
|
|
1012
|
+
if (mounted.current) setError(nextError);
|
|
1013
|
+
throw nextError;
|
|
1014
|
+
} finally {
|
|
1015
|
+
if (mounted.current) setIsMutating(false);
|
|
1016
|
+
}
|
|
1017
|
+
}, []);
|
|
1018
|
+
const saveReview = useCallback2(
|
|
1019
|
+
(input) => mutate(() => client.saveReview(input)),
|
|
1020
|
+
[client, mutate]
|
|
1021
|
+
);
|
|
1022
|
+
const submitBill = useCallback2(
|
|
1023
|
+
(input, route) => mutate(() => client.submitBill(input, route)),
|
|
1024
|
+
[client, mutate]
|
|
1025
|
+
);
|
|
1026
|
+
const addAttachment = useCallback2(
|
|
1027
|
+
(file, type, description) => mutate(() => client.addAttachment(file, type, description)),
|
|
1028
|
+
[client, mutate]
|
|
1029
|
+
);
|
|
1030
|
+
const removeAttachment = useCallback2(
|
|
1031
|
+
(attachmentId) => mutate(() => client.removeAttachment(attachmentId)),
|
|
1032
|
+
[client, mutate]
|
|
1033
|
+
);
|
|
1034
|
+
const closeBill = useCallback2(
|
|
1035
|
+
(input) => mutate(() => client.closeBill(input)),
|
|
1036
|
+
[client, mutate]
|
|
1037
|
+
);
|
|
1038
|
+
const postPayment = useCallback2(
|
|
1039
|
+
(input) => mutate(() => client.postPayment(input)),
|
|
1040
|
+
[client, mutate]
|
|
1041
|
+
);
|
|
1042
|
+
const submitSecondReview = useCallback2(
|
|
1043
|
+
(input) => mutate(() => client.submitSecondReview(input)),
|
|
1044
|
+
[client, mutate]
|
|
1045
|
+
);
|
|
1046
|
+
const startCorrection = useCallback2(async () => {
|
|
1047
|
+
setIsMutating(true);
|
|
1048
|
+
setError(null);
|
|
1049
|
+
try {
|
|
1050
|
+
const result = await client.startCorrection();
|
|
1051
|
+
const previousBillId = billId;
|
|
1052
|
+
await onBillIdChange?.(result.replacementBillId, previousBillId);
|
|
1053
|
+
setBillId(result.replacementBillId);
|
|
1054
|
+
setData(result.data);
|
|
1055
|
+
return result.data;
|
|
1056
|
+
} catch (cause) {
|
|
1057
|
+
const nextError = cause instanceof Error ? cause : new Error("Correction draft could not be created.");
|
|
1058
|
+
setError(nextError);
|
|
1059
|
+
throw nextError;
|
|
1060
|
+
} finally {
|
|
1061
|
+
setIsMutating(false);
|
|
1062
|
+
}
|
|
1063
|
+
}, [billId, client, onBillIdChange]);
|
|
1064
|
+
const openAttachment = useCallback2(async (attachment) => {
|
|
1065
|
+
openPdf(await client.getAttachment(attachment.id), attachment.filename);
|
|
1066
|
+
}, [client]);
|
|
1067
|
+
const openEor = useCallback2(async (document2) => {
|
|
1068
|
+
openPdf(await client.getEor(document2.id), document2.filename);
|
|
1069
|
+
}, [client]);
|
|
1070
|
+
return {
|
|
1071
|
+
billId,
|
|
1072
|
+
data,
|
|
1073
|
+
error,
|
|
1074
|
+
isLoading,
|
|
1075
|
+
isRefreshing,
|
|
1076
|
+
isMutating,
|
|
1077
|
+
refresh,
|
|
1078
|
+
saveReview,
|
|
1079
|
+
submitBill,
|
|
1080
|
+
addAttachment,
|
|
1081
|
+
removeAttachment,
|
|
1082
|
+
openAttachment,
|
|
1083
|
+
openEor,
|
|
1084
|
+
closeBill,
|
|
1085
|
+
postPayment,
|
|
1086
|
+
submitSecondReview,
|
|
1087
|
+
startCorrection
|
|
1088
|
+
};
|
|
1089
|
+
}
|
|
1090
|
+
function dateInputValue() {
|
|
1091
|
+
const now = /* @__PURE__ */ new Date();
|
|
1092
|
+
const offset = now.getTimezoneOffset() * 6e4;
|
|
1093
|
+
return new Date(now.getTime() - offset).toISOString().slice(0, 10);
|
|
1094
|
+
}
|
|
1095
|
+
function appearanceStyle2(appearance, style) {
|
|
1096
|
+
return {
|
|
1097
|
+
...appearance?.accentColor ? { "--mb-accent": appearance.accentColor } : {},
|
|
1098
|
+
...appearance?.textColor ? { "--mb-text": appearance.textColor } : {},
|
|
1099
|
+
...appearance?.mutedColor ? { "--mb-muted": appearance.mutedColor } : {},
|
|
1100
|
+
...appearance?.borderColor ? { "--mb-border": appearance.borderColor } : {},
|
|
1101
|
+
...appearance?.backgroundColor ? { "--mb-soft": appearance.backgroundColor } : {},
|
|
1102
|
+
...appearance?.surfaceColor ? { "--mb-surface": appearance.surfaceColor } : {},
|
|
1103
|
+
...appearance?.fontFamily ? { "--mb-font": appearance.fontFamily } : {},
|
|
1104
|
+
...style
|
|
1105
|
+
};
|
|
1106
|
+
}
|
|
1107
|
+
function SupportingDocumentControl({
|
|
1108
|
+
disabled,
|
|
1109
|
+
onAdd
|
|
1110
|
+
}) {
|
|
1111
|
+
const [file, setFile] = useState3(null);
|
|
1112
|
+
const [type, setType] = useState3("appeal");
|
|
1113
|
+
const [busy, setBusy] = useState3(false);
|
|
1114
|
+
return /* @__PURE__ */ jsxs3("div", { className: "mb-lifecycle-upload", children: [
|
|
1115
|
+
/* @__PURE__ */ jsxs3("select", { "aria-label": "Supporting document type", value: type, disabled: disabled || busy, onChange: (event) => setType(event.target.value), children: [
|
|
1116
|
+
/* @__PURE__ */ jsx3("option", { value: "appeal", children: "Second Review support" }),
|
|
1117
|
+
/* @__PURE__ */ jsx3("option", { value: "final_report", children: "Final report" }),
|
|
1118
|
+
/* @__PURE__ */ jsx3("option", { value: "proof_of_service", children: "Proof of service" }),
|
|
1119
|
+
/* @__PURE__ */ jsx3("option", { value: "letter_of_attestation", children: "Letter of attestation" }),
|
|
1120
|
+
/* @__PURE__ */ jsx3("option", { value: "form_122", children: "DWC Form 122" }),
|
|
1121
|
+
/* @__PURE__ */ jsx3("option", { value: "w9", children: "W-9" }),
|
|
1122
|
+
/* @__PURE__ */ jsx3("option", { value: "other", children: "Other supporting document" })
|
|
1123
|
+
] }),
|
|
1124
|
+
/* @__PURE__ */ jsx3("input", { "aria-label": "Choose supporting PDF", type: "file", accept: "application/pdf,.pdf", disabled: disabled || busy, onChange: (event) => setFile(event.target.files?.[0] ?? null) }),
|
|
1125
|
+
/* @__PURE__ */ jsx3("button", { type: "button", className: "mb-lifecycle-button secondary", disabled: disabled || busy || !file, onClick: () => {
|
|
1126
|
+
if (!file) return;
|
|
1127
|
+
setBusy(true);
|
|
1128
|
+
void onAdd(file, type).then(() => setFile(null)).catch(() => void 0).finally(() => setBusy(false));
|
|
1129
|
+
}, children: busy ? "Attaching\u2026" : "Attach PDF" })
|
|
1130
|
+
] });
|
|
1131
|
+
}
|
|
1132
|
+
function ConnectedBillLifecycle({
|
|
1133
|
+
appearance,
|
|
1134
|
+
className,
|
|
1135
|
+
style,
|
|
1136
|
+
loadingFallback,
|
|
1137
|
+
errorFallback,
|
|
1138
|
+
onChanged,
|
|
1139
|
+
...options
|
|
1140
|
+
}) {
|
|
1141
|
+
const lifecycle = useBillLifecycle(options);
|
|
1142
|
+
const { data } = lifecycle;
|
|
1143
|
+
const [panel, setPanel] = useState3("");
|
|
1144
|
+
const [notice, setNotice] = useState3("");
|
|
1145
|
+
const [closeReason, setCloseReason] = useState3("");
|
|
1146
|
+
const [payment, setPayment] = useState3({
|
|
1147
|
+
amount: 0,
|
|
1148
|
+
method: "check",
|
|
1149
|
+
checkNumber: "",
|
|
1150
|
+
depositDate: dateInputValue(),
|
|
1151
|
+
note: ""
|
|
1152
|
+
});
|
|
1153
|
+
const [review, setReview] = useState3({
|
|
1154
|
+
reason: "",
|
|
1155
|
+
payerClaimControlNumber: "",
|
|
1156
|
+
disputedAmount: void 0,
|
|
1157
|
+
attachmentIds: [],
|
|
1158
|
+
route: "ebill"
|
|
1159
|
+
});
|
|
1160
|
+
const lastData = useRef2(null);
|
|
1161
|
+
useEffect3(() => {
|
|
1162
|
+
if (!data || data === lastData.current) return;
|
|
1163
|
+
lastData.current = data;
|
|
1164
|
+
onChanged?.(data);
|
|
1165
|
+
setPayment((current) => ({
|
|
1166
|
+
...current,
|
|
1167
|
+
amount: current.amount > 0 ? current.amount : data.bill.balanceDue
|
|
1168
|
+
}));
|
|
1169
|
+
setReview((current) => ({
|
|
1170
|
+
...current,
|
|
1171
|
+
disputedAmount: current.disputedAmount ?? data.bill.balanceDue,
|
|
1172
|
+
attachmentIds: current.attachmentIds.length ? current.attachmentIds.filter((id) => data.bill.attachments.some((doc) => doc.id === id)) : data.bill.attachments.map((doc) => doc.id)
|
|
1173
|
+
}));
|
|
1174
|
+
}, [data, onChanged]);
|
|
1175
|
+
if (lifecycle.isLoading && !data) {
|
|
1176
|
+
return /* @__PURE__ */ jsx3(Fragment2, { children: loadingFallback ?? /* @__PURE__ */ jsx3("div", { className: "mb-lifecycle-loading", children: "Loading billing\u2026" }) });
|
|
1177
|
+
}
|
|
1178
|
+
if (!data) {
|
|
1179
|
+
const error = lifecycle.error ?? new Error("Bill could not be loaded.");
|
|
1180
|
+
return /* @__PURE__ */ jsx3(Fragment2, { children: errorFallback?.(error, lifecycle.refresh) ?? /* @__PURE__ */ jsxs3("div", { className: "mb-lifecycle-error", role: "alert", children: [
|
|
1181
|
+
/* @__PURE__ */ jsx3("strong", { children: "Billing is unavailable." }),
|
|
1182
|
+
/* @__PURE__ */ jsx3("span", { children: error.message }),
|
|
1183
|
+
/* @__PURE__ */ jsx3("button", { type: "button", onClick: () => void lifecycle.refresh(), children: "Try again" })
|
|
1184
|
+
] }) });
|
|
1185
|
+
}
|
|
1186
|
+
const actionMap = new Map(data.lifecycle.actions.map((action) => [action.id, action]));
|
|
1187
|
+
const has = (id) => actionMap.get(id);
|
|
1188
|
+
const selectPanel = (next) => {
|
|
1189
|
+
setNotice("");
|
|
1190
|
+
setPanel((current) => current === next ? "" : next);
|
|
1191
|
+
};
|
|
1192
|
+
const complete = async (message, task) => {
|
|
1193
|
+
setNotice("");
|
|
1194
|
+
try {
|
|
1195
|
+
await task();
|
|
1196
|
+
setPanel("");
|
|
1197
|
+
setNotice(message);
|
|
1198
|
+
} catch {
|
|
1199
|
+
}
|
|
1200
|
+
};
|
|
1201
|
+
const actionButtons = data.lifecycle.actions.filter((action) => action.id !== "edit_and_submit" && action.id !== "view_eor" && action.id !== "independent_bill_review").map((action) => ({
|
|
1202
|
+
...action,
|
|
1203
|
+
onClick: () => {
|
|
1204
|
+
if (!action.enabled) return;
|
|
1205
|
+
if (action.id === "correct_and_resubmit") selectPanel("correction");
|
|
1206
|
+
if (action.id === "second_review") selectPanel("second_review");
|
|
1207
|
+
if (action.id === "post_payment") selectPanel("payment");
|
|
1208
|
+
if (action.id === "close") selectPanel("close");
|
|
1209
|
+
},
|
|
1210
|
+
disabled: !action.enabled || lifecycle.isMutating
|
|
1211
|
+
}));
|
|
1212
|
+
const canEditAndSubmit = Boolean(has("edit_and_submit"));
|
|
1213
|
+
return /* @__PURE__ */ jsxs3("section", { className: ["mb-connected-lifecycle", className].filter(Boolean).join(" "), style: appearanceStyle2(appearance, style), children: [
|
|
1214
|
+
/* @__PURE__ */ jsx3("style", { children: CONNECTED_LIFECYCLE_STYLES }),
|
|
1215
|
+
canEditAndSubmit ? /* @__PURE__ */ jsx3(
|
|
1216
|
+
BillReviewForm,
|
|
1217
|
+
{
|
|
1218
|
+
data,
|
|
1219
|
+
...appearance ? { appearance } : {},
|
|
1220
|
+
disabled: lifecycle.isMutating,
|
|
1221
|
+
onSave: lifecycle.saveReview,
|
|
1222
|
+
onSubmit: async (input, route) => {
|
|
1223
|
+
await complete("Bill submitted.", () => lifecycle.submitBill(input, route));
|
|
1224
|
+
},
|
|
1225
|
+
onAddAttachment: async (file, type, description) => {
|
|
1226
|
+
await lifecycle.addAttachment(file, type, description);
|
|
1227
|
+
},
|
|
1228
|
+
onRemoveAttachment: async (attachmentId) => {
|
|
1229
|
+
await lifecycle.removeAttachment(attachmentId);
|
|
1230
|
+
},
|
|
1231
|
+
onOpenAttachment: (attachment) => void lifecycle.openAttachment(attachment).catch(() => void 0)
|
|
1232
|
+
}
|
|
1233
|
+
) : /* @__PURE__ */ jsx3(
|
|
1234
|
+
BillStatusSummary,
|
|
1235
|
+
{
|
|
1236
|
+
status: data.lifecycle.state,
|
|
1237
|
+
totalCharge: data.bill.totalCharge,
|
|
1238
|
+
totalPaid: data.bill.totalPaid,
|
|
1239
|
+
balanceDue: data.bill.balanceDue,
|
|
1240
|
+
actions: actionButtons,
|
|
1241
|
+
...appearance ? { appearance } : {}
|
|
1242
|
+
}
|
|
1243
|
+
),
|
|
1244
|
+
/* @__PURE__ */ jsxs3("div", { className: "mb-lifecycle-toolbar", children: [
|
|
1245
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
1246
|
+
/* @__PURE__ */ jsxs3("strong", { children: [
|
|
1247
|
+
"Bill #",
|
|
1248
|
+
data.bill.billNumber
|
|
1249
|
+
] }),
|
|
1250
|
+
/* @__PURE__ */ jsx3("span", { children: lifecycle.isRefreshing ? "Refreshing\u2026" : "MindBill manages this lifecycle." })
|
|
1251
|
+
] }),
|
|
1252
|
+
/* @__PURE__ */ jsxs3("div", { className: "mb-lifecycle-toolbar-actions", children: [
|
|
1253
|
+
has("view_eor") ? /* @__PURE__ */ jsx3("button", { type: "button", className: "mb-lifecycle-button secondary", onClick: () => document.getElementById(`mb-eors-${data.bill.id}`)?.scrollIntoView({ behavior: "smooth", block: "center" }), children: "View EOR" }) : null,
|
|
1254
|
+
canEditAndSubmit && has("close") ? /* @__PURE__ */ jsx3("button", { type: "button", className: "mb-lifecycle-button quiet", onClick: () => selectPanel("close"), children: "Close bill" }) : null
|
|
1255
|
+
] })
|
|
1256
|
+
] }),
|
|
1257
|
+
data.eors.length ? /* @__PURE__ */ jsxs3("section", { className: "mb-lifecycle-card", id: `mb-eors-${data.bill.id}`, children: [
|
|
1258
|
+
/* @__PURE__ */ jsxs3("header", { children: [
|
|
1259
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
1260
|
+
/* @__PURE__ */ jsx3("h3", { children: "Explanation of Review" }),
|
|
1261
|
+
/* @__PURE__ */ jsx3("p", { children: "Review the payer response and original PDF before posting payment." })
|
|
1262
|
+
] }),
|
|
1263
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
1264
|
+
data.eors.length,
|
|
1265
|
+
" PDF",
|
|
1266
|
+
data.eors.length === 1 ? "" : "s"
|
|
1267
|
+
] })
|
|
1268
|
+
] }),
|
|
1269
|
+
/* @__PURE__ */ jsx3("ul", { className: "mb-lifecycle-documents", children: data.eors.map((eor) => /* @__PURE__ */ jsxs3("li", { children: [
|
|
1270
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
1271
|
+
/* @__PURE__ */ jsx3("strong", { children: eor.filename }),
|
|
1272
|
+
/* @__PURE__ */ jsx3("span", { children: eor.description || `Added ${new Date(eor.addedAt).toLocaleDateString()}` })
|
|
1273
|
+
] }),
|
|
1274
|
+
/* @__PURE__ */ jsx3("button", { type: "button", className: "mb-lifecycle-button secondary", onClick: () => void lifecycle.openEor(eor).catch(() => void 0), children: "View PDF" })
|
|
1275
|
+
] }, eor.id)) })
|
|
1276
|
+
] }) : null,
|
|
1277
|
+
has("independent_bill_review") ? /* @__PURE__ */ jsxs3("div", { className: "mb-lifecycle-info", children: [
|
|
1278
|
+
/* @__PURE__ */ jsx3("strong", { children: has("independent_bill_review")?.label }),
|
|
1279
|
+
/* @__PURE__ */ jsx3("span", { children: has("independent_bill_review")?.reason })
|
|
1280
|
+
] }) : null,
|
|
1281
|
+
panel === "correction" ? /* @__PURE__ */ jsxs3("section", { className: "mb-lifecycle-panel", children: [
|
|
1282
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
1283
|
+
/* @__PURE__ */ jsx3("h3", { children: "Correct and resubmit" }),
|
|
1284
|
+
/* @__PURE__ */ jsx3("p", { children: "MindBill will create a new correction draft and preserve this rejected bill in history. Review the copied values before submitting." })
|
|
1285
|
+
] }),
|
|
1286
|
+
/* @__PURE__ */ jsxs3("div", { className: "mb-lifecycle-panel-actions", children: [
|
|
1287
|
+
/* @__PURE__ */ jsx3("button", { type: "button", className: "mb-lifecycle-button secondary", onClick: () => setPanel(""), children: "Cancel" }),
|
|
1288
|
+
/* @__PURE__ */ jsx3("button", { type: "button", className: "mb-lifecycle-button primary", disabled: lifecycle.isMutating, onClick: () => void complete("Correction draft created.", lifecycle.startCorrection), children: lifecycle.isMutating ? "Creating\u2026" : "Create correction draft" })
|
|
1289
|
+
] })
|
|
1290
|
+
] }) : null,
|
|
1291
|
+
panel === "second_review" ? /* @__PURE__ */ jsxs3("section", { className: "mb-lifecycle-panel wide", children: [
|
|
1292
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
1293
|
+
/* @__PURE__ */ jsx3("h3", { children: "Submit Second Review" }),
|
|
1294
|
+
/* @__PURE__ */ jsx3("p", { children: "State why payment is disputed, confirm the payer control number, and choose the supporting documents MindBill should send." })
|
|
1295
|
+
] }),
|
|
1296
|
+
/* @__PURE__ */ jsxs3("div", { className: "mb-lifecycle-fields two", children: [
|
|
1297
|
+
/* @__PURE__ */ jsxs3("label", { children: [
|
|
1298
|
+
/* @__PURE__ */ jsx3("span", { children: "Reason for Second Review" }),
|
|
1299
|
+
/* @__PURE__ */ jsx3("textarea", { required: true, value: review.reason, onChange: (event) => setReview((current) => ({ ...current, reason: event.target.value })) })
|
|
1300
|
+
] }),
|
|
1301
|
+
/* @__PURE__ */ jsxs3("div", { className: "mb-lifecycle-fields", children: [
|
|
1302
|
+
/* @__PURE__ */ jsxs3("label", { children: [
|
|
1303
|
+
/* @__PURE__ */ jsx3("span", { children: "Payer claim control number" }),
|
|
1304
|
+
/* @__PURE__ */ jsx3("input", { required: true, value: review.payerClaimControlNumber, onChange: (event) => setReview((current) => ({ ...current, payerClaimControlNumber: event.target.value })) })
|
|
1305
|
+
] }),
|
|
1306
|
+
/* @__PURE__ */ jsxs3("label", { children: [
|
|
1307
|
+
/* @__PURE__ */ jsx3("span", { children: "Disputed amount" }),
|
|
1308
|
+
/* @__PURE__ */ jsx3("input", { type: "number", min: "0.01", step: "0.01", value: review.disputedAmount ?? "", onChange: (event) => setReview((current) => ({ ...current, disputedAmount: event.target.value ? Number(event.target.value) : void 0 })) })
|
|
1309
|
+
] }),
|
|
1310
|
+
/* @__PURE__ */ jsxs3("label", { children: [
|
|
1311
|
+
/* @__PURE__ */ jsx3("span", { children: "Send via" }),
|
|
1312
|
+
/* @__PURE__ */ jsxs3("select", { value: review.route, onChange: (event) => setReview((current) => ({ ...current, route: event.target.value })), children: [
|
|
1313
|
+
/* @__PURE__ */ jsx3("option", { value: "ebill", children: "E-bill" }),
|
|
1314
|
+
/* @__PURE__ */ jsx3("option", { value: "fax", children: "Fax" }),
|
|
1315
|
+
/* @__PURE__ */ jsx3("option", { value: "mail", children: "Mail" }),
|
|
1316
|
+
/* @__PURE__ */ jsx3("option", { value: "email", children: "Email" })
|
|
1317
|
+
] })
|
|
1318
|
+
] })
|
|
1319
|
+
] })
|
|
1320
|
+
] }),
|
|
1321
|
+
/* @__PURE__ */ jsxs3("fieldset", { className: "mb-lifecycle-packet", children: [
|
|
1322
|
+
/* @__PURE__ */ jsx3("legend", { children: "Supporting packet" }),
|
|
1323
|
+
data.bill.attachments.map((attachment) => /* @__PURE__ */ jsxs3("label", { children: [
|
|
1324
|
+
/* @__PURE__ */ jsx3("input", { type: "checkbox", checked: review.attachmentIds.includes(attachment.id), onChange: (event) => setReview((current) => ({ ...current, attachmentIds: event.target.checked ? [...current.attachmentIds, attachment.id] : current.attachmentIds.filter((id) => id !== attachment.id) })) }),
|
|
1325
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
1326
|
+
/* @__PURE__ */ jsx3("strong", { children: attachment.filename }),
|
|
1327
|
+
/* @__PURE__ */ jsx3("small", { children: attachment.description || attachment.documentType })
|
|
1328
|
+
] }),
|
|
1329
|
+
/* @__PURE__ */ jsx3("button", { type: "button", onClick: () => void lifecycle.openAttachment(attachment).catch(() => void 0), children: "View" }),
|
|
1330
|
+
/* @__PURE__ */ jsx3("button", { type: "button", "aria-label": `Remove ${attachment.filename}`, onClick: () => void lifecycle.removeAttachment(attachment.id).catch(() => void 0), children: "\xD7" })
|
|
1331
|
+
] }, attachment.id))
|
|
1332
|
+
] }),
|
|
1333
|
+
/* @__PURE__ */ jsx3(SupportingDocumentControl, { disabled: lifecycle.isMutating, onAdd: async (file, type, description) => {
|
|
1334
|
+
const next = await lifecycle.addAttachment(file, type, description);
|
|
1335
|
+
setReview((current) => ({
|
|
1336
|
+
...current,
|
|
1337
|
+
attachmentIds: Array.from(/* @__PURE__ */ new Set([
|
|
1338
|
+
...current.attachmentIds,
|
|
1339
|
+
...next.bill.attachments.map((attachment) => attachment.id)
|
|
1340
|
+
]))
|
|
1341
|
+
}));
|
|
1342
|
+
} }),
|
|
1343
|
+
/* @__PURE__ */ jsxs3("div", { className: "mb-lifecycle-panel-actions", children: [
|
|
1344
|
+
/* @__PURE__ */ jsx3("button", { type: "button", className: "mb-lifecycle-button secondary", onClick: () => setPanel(""), children: "Cancel" }),
|
|
1345
|
+
/* @__PURE__ */ jsx3("button", { type: "button", className: "mb-lifecycle-button primary", disabled: lifecycle.isMutating || !review.reason.trim() || !review.payerClaimControlNumber.trim(), onClick: () => void complete("Second Review submitted.", () => lifecycle.submitSecondReview(review)), children: lifecycle.isMutating ? "Submitting\u2026" : "Submit Second Review" })
|
|
1346
|
+
] })
|
|
1347
|
+
] }) : null,
|
|
1348
|
+
panel === "payment" ? /* @__PURE__ */ jsxs3("section", { className: "mb-lifecycle-panel", children: [
|
|
1349
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
1350
|
+
/* @__PURE__ */ jsx3("h3", { children: "Post payment" }),
|
|
1351
|
+
/* @__PURE__ */ jsx3("p", { children: "Record funds shown on the EOR. MindBill updates the balance and closes the bill automatically when configured." })
|
|
1352
|
+
] }),
|
|
1353
|
+
/* @__PURE__ */ jsxs3("div", { className: "mb-lifecycle-fields two", children: [
|
|
1354
|
+
/* @__PURE__ */ jsxs3("label", { children: [
|
|
1355
|
+
/* @__PURE__ */ jsx3("span", { children: "Amount" }),
|
|
1356
|
+
/* @__PURE__ */ jsx3("input", { type: "number", min: "0.01", max: data.bill.balanceDue, step: "0.01", required: true, value: payment.amount || "", onChange: (event) => setPayment((current) => ({ ...current, amount: Number(event.target.value) })) })
|
|
1357
|
+
] }),
|
|
1358
|
+
/* @__PURE__ */ jsxs3("label", { children: [
|
|
1359
|
+
/* @__PURE__ */ jsx3("span", { children: "Method" }),
|
|
1360
|
+
/* @__PURE__ */ jsxs3("select", { value: payment.method, onChange: (event) => setPayment((current) => ({ ...current, method: event.target.value })), children: [
|
|
1361
|
+
/* @__PURE__ */ jsx3("option", { value: "check", children: "Check" }),
|
|
1362
|
+
/* @__PURE__ */ jsx3("option", { value: "eft", children: "EFT" })
|
|
1363
|
+
] })
|
|
1364
|
+
] }),
|
|
1365
|
+
/* @__PURE__ */ jsxs3("label", { children: [
|
|
1366
|
+
/* @__PURE__ */ jsx3("span", { children: payment.method === "check" ? "Check number" : "EFT reference" }),
|
|
1367
|
+
/* @__PURE__ */ jsx3("input", { value: payment.checkNumber, onChange: (event) => setPayment((current) => ({ ...current, checkNumber: event.target.value })) })
|
|
1368
|
+
] }),
|
|
1369
|
+
/* @__PURE__ */ jsxs3("label", { children: [
|
|
1370
|
+
/* @__PURE__ */ jsx3("span", { children: "Deposit date" }),
|
|
1371
|
+
/* @__PURE__ */ jsx3("input", { type: "date", required: true, value: payment.depositDate, onChange: (event) => setPayment((current) => ({ ...current, depositDate: event.target.value })) })
|
|
1372
|
+
] }),
|
|
1373
|
+
/* @__PURE__ */ jsxs3("label", { className: "full", children: [
|
|
1374
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
1375
|
+
"Note ",
|
|
1376
|
+
/* @__PURE__ */ jsx3("small", { children: "Optional" })
|
|
1377
|
+
] }),
|
|
1378
|
+
/* @__PURE__ */ jsx3("input", { value: payment.note, onChange: (event) => setPayment((current) => ({ ...current, note: event.target.value })) })
|
|
1379
|
+
] })
|
|
1380
|
+
] }),
|
|
1381
|
+
/* @__PURE__ */ jsxs3("div", { className: "mb-lifecycle-panel-actions", children: [
|
|
1382
|
+
/* @__PURE__ */ jsx3("button", { type: "button", className: "mb-lifecycle-button secondary", onClick: () => setPanel(""), children: "Cancel" }),
|
|
1383
|
+
/* @__PURE__ */ jsx3("button", { type: "button", className: "mb-lifecycle-button primary", disabled: lifecycle.isMutating || payment.amount <= 0 || payment.amount > data.bill.balanceDue || !payment.depositDate, onClick: () => void complete("Payment posted.", () => lifecycle.postPayment(payment)), children: lifecycle.isMutating ? "Posting\u2026" : "Post payment" })
|
|
1384
|
+
] })
|
|
1385
|
+
] }) : null,
|
|
1386
|
+
panel === "close" ? /* @__PURE__ */ jsxs3("section", { className: "mb-lifecycle-panel danger", children: [
|
|
1387
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
1388
|
+
/* @__PURE__ */ jsx3("h3", { children: "Close bill" }),
|
|
1389
|
+
/* @__PURE__ */ jsx3("p", { children: "Closing removes this bill from active A/R. Any remaining balance will be written off and the original lifecycle is preserved." })
|
|
1390
|
+
] }),
|
|
1391
|
+
/* @__PURE__ */ jsxs3("label", { children: [
|
|
1392
|
+
/* @__PURE__ */ jsx3("span", { children: "Reason for closing" }),
|
|
1393
|
+
/* @__PURE__ */ jsx3("textarea", { required: true, value: closeReason, onChange: (event) => setCloseReason(event.target.value) })
|
|
1394
|
+
] }),
|
|
1395
|
+
/* @__PURE__ */ jsxs3("div", { className: "mb-lifecycle-panel-actions", children: [
|
|
1396
|
+
/* @__PURE__ */ jsx3("button", { type: "button", className: "mb-lifecycle-button secondary", onClick: () => setPanel(""), children: "Cancel" }),
|
|
1397
|
+
/* @__PURE__ */ jsx3("button", { type: "button", className: "mb-lifecycle-button danger", disabled: lifecycle.isMutating || !closeReason.trim(), onClick: () => void complete("Bill closed.", () => lifecycle.closeBill({ reason: closeReason })), children: lifecycle.isMutating ? "Closing\u2026" : "Close bill" })
|
|
1398
|
+
] })
|
|
1399
|
+
] }) : null,
|
|
1400
|
+
notice ? /* @__PURE__ */ jsx3("div", { className: "mb-lifecycle-message success", role: "status", children: notice }) : null,
|
|
1401
|
+
lifecycle.error ? /* @__PURE__ */ jsx3("div", { className: "mb-lifecycle-message error", role: "alert", children: lifecycle.error.message }) : null
|
|
1402
|
+
] });
|
|
1403
|
+
}
|
|
1404
|
+
var CONNECTED_LIFECYCLE_STYLES = `
|
|
1405
|
+
.mb-connected-lifecycle{--mb-accent:#238dbd;--mb-text:#203743;--mb-muted:#657982;--mb-border:#dbe6ea;--mb-soft:#f3f8fa;--mb-surface:#fff;display:grid;gap:14px;color:var(--mb-text);font:14px/1.45 var(--mb-font,Inter,ui-sans-serif,system-ui,sans-serif)}.mb-connected-lifecycle *{box-sizing:border-box}.mb-lifecycle-toolbar{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:12px 14px;border:1px solid var(--mb-border);border-radius:10px;background:var(--mb-surface)}.mb-lifecycle-toolbar>div:first-child{display:grid;gap:2px}.mb-lifecycle-toolbar span,.mb-lifecycle-card p,.mb-lifecycle-panel p,.mb-lifecycle-info span{color:var(--mb-muted)}.mb-lifecycle-toolbar-actions,.mb-lifecycle-panel-actions{display:flex;justify-content:flex-end;gap:8px}.mb-lifecycle-button{min-height:38px;border:1px solid var(--mb-border);border-radius:8px;background:#fff;color:var(--mb-text);cursor:pointer;font:inherit;font-weight:750;padding:8px 13px}.mb-lifecycle-button.primary{border-color:var(--mb-accent);background:var(--mb-accent);color:#fff}.mb-lifecycle-button.quiet{border-color:transparent;background:transparent;color:var(--mb-muted)}.mb-lifecycle-button.danger{border-color:#b63d35;background:#b63d35;color:#fff}.mb-lifecycle-button:disabled{cursor:not-allowed;opacity:.5}.mb-lifecycle-card,.mb-lifecycle-panel{padding:18px;border:1px solid var(--mb-border);border-radius:12px;background:var(--mb-surface)}.mb-lifecycle-card header{display:flex;align-items:start;justify-content:space-between;gap:16px}.mb-lifecycle-card h3,.mb-lifecycle-panel h3{margin:0;font-size:18px}.mb-lifecycle-card p,.mb-lifecycle-panel p{margin:3px 0 0}.mb-lifecycle-card header>span{padding:5px 8px;border-radius:999px;background:var(--mb-soft);color:var(--mb-muted);font-size:11px;font-weight:800;text-transform:uppercase}.mb-lifecycle-documents{list-style:none;margin:12px 0 0;padding:0}.mb-lifecycle-documents li{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:11px 0;border-top:1px solid var(--mb-border)}.mb-lifecycle-documents li>div{display:grid}.mb-lifecycle-documents span{color:var(--mb-muted);font-size:12px}.mb-lifecycle-info{display:grid;gap:3px;padding:13px 15px;border:1px solid #cddfe5;border-radius:10px;background:var(--mb-soft)}.mb-lifecycle-panel{display:grid;gap:16px;box-shadow:0 14px 38px rgba(30,56,68,.08)}.mb-lifecycle-panel.danger{border-color:#ecc5c2}.mb-lifecycle-panel label{display:grid;gap:6px;font-size:12px;font-weight:750}.mb-lifecycle-panel label small{color:var(--mb-muted);font-size:inherit;font-weight:500}.mb-lifecycle-panel input,.mb-lifecycle-panel select,.mb-lifecycle-panel textarea,.mb-lifecycle-upload input,.mb-lifecycle-upload select{width:100%;min-height:42px;border:1px solid var(--mb-border);border-radius:8px;background:#fff;color:var(--mb-text);font:inherit;padding:9px 11px}.mb-lifecycle-panel textarea{min-height:100px;resize:vertical}.mb-lifecycle-fields{display:grid;gap:12px}.mb-lifecycle-fields.two{grid-template-columns:repeat(2,minmax(0,1fr))}.mb-lifecycle-fields .full{grid-column:1/-1}.mb-lifecycle-packet{display:grid;gap:0;margin:0;padding:0;border:0}.mb-lifecycle-packet legend{margin-bottom:7px;font-size:12px;font-weight:800}.mb-lifecycle-packet>label{display:grid;grid-template-columns:auto 1fr auto auto;align-items:center;gap:10px;padding:10px 2px;border-top:1px solid var(--mb-border)}.mb-lifecycle-packet>label>input{width:16px;min-height:16px}.mb-lifecycle-packet>label>span{display:grid}.mb-lifecycle-packet button{border:0;background:transparent;color:var(--mb-accent);cursor:pointer;font:inherit}.mb-lifecycle-upload{display:grid;grid-template-columns:220px 1fr auto;align-items:end;gap:10px;padding:12px;border-radius:9px;background:var(--mb-soft)}.mb-lifecycle-message,.mb-lifecycle-error,.mb-lifecycle-loading{padding:12px 14px;border-radius:9px}.mb-lifecycle-message.success{background:#edf9f2;color:#217449}.mb-lifecycle-message.error,.mb-lifecycle-error{background:#fff0ef;color:#9d3029}.mb-lifecycle-error{display:flex;align-items:center;gap:12px}.mb-lifecycle-error span{flex:1}.mb-lifecycle-error button{border:1px solid currentColor;border-radius:7px;background:transparent;color:inherit;padding:7px 10px}@media(max-width:760px){.mb-lifecycle-toolbar,.mb-lifecycle-card header{align-items:stretch;flex-direction:column}.mb-lifecycle-toolbar-actions,.mb-lifecycle-panel-actions{justify-content:start}.mb-lifecycle-fields.two,.mb-lifecycle-upload{grid-template-columns:1fr}.mb-lifecycle-documents li{align-items:start}.mb-lifecycle-packet>label{grid-template-columns:auto 1fr auto}}
|
|
1406
|
+
`;
|
|
1407
|
+
|
|
679
1408
|
// src/index.tsx
|
|
680
1409
|
function widget(tagName, props) {
|
|
681
|
-
const ref =
|
|
1410
|
+
const ref = useRef3(null);
|
|
682
1411
|
const { onMindBill, onMindBillError } = props;
|
|
683
|
-
|
|
1412
|
+
useEffect4(() => {
|
|
684
1413
|
const element = ref.current;
|
|
685
1414
|
if (!element) return;
|
|
686
1415
|
const handleEvent = (event) => onMindBill?.(event);
|
|
@@ -733,6 +1462,7 @@ var HostedOnboarding = MindBillOnboarding;
|
|
|
733
1462
|
export {
|
|
734
1463
|
BillReviewForm,
|
|
735
1464
|
BillStatusSummary,
|
|
1465
|
+
ConnectedBillLifecycle,
|
|
736
1466
|
ConnectedBillStatus,
|
|
737
1467
|
HostedBillFromReport,
|
|
738
1468
|
HostedBillReview,
|
|
@@ -745,7 +1475,9 @@ export {
|
|
|
745
1475
|
MindBillCollections,
|
|
746
1476
|
MindBillOnboarding,
|
|
747
1477
|
buildBillReviewSaveInput,
|
|
1478
|
+
createBillLifecycleClient,
|
|
748
1479
|
createBillStatusClient,
|
|
1480
|
+
useBillLifecycle,
|
|
749
1481
|
useBillStatus
|
|
750
1482
|
};
|
|
751
1483
|
//# sourceMappingURL=index.js.map
|