@@ -12,14 +12,23 @@
|
|||||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
// PERFORMANCE OF THIS SOFTWARE.
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
import { formatError } from "@probo/helpers";
|
|
||||||
import { usePageTitle } from "@probo/hooks";
|
|
||||||
import { useTranslate } from "@probo/i18n";
|
|
||||||
import { Button, useToast } from "@probo/ui";
|
|
||||||
import { useCallback, useState } from "react";
|
import { useCallback, useState } from "react";
|
||||||
import { type PreloadedQuery, useMutation, usePreloadedQuery } from "react-relay";
|
import { type PreloadedQuery, useMutation, usePreloadedQuery } from "react-relay";
|
||||||
import { graphql } from "relay-runtime";
|
import { graphql } from "relay-runtime";
|
||||||
|
|
||||||
|
import { formatError } from "@probo/helpers";
|
||||||
|
import { usePageTitle } from "@probo/hooks";
|
||||||
|
import { useTranslate } from "@probo/i18n";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
IconArrowsClockwise,
|
||||||
|
IconEnvelope,
|
||||||
|
IconLockOpen,
|
||||||
|
IconUser,
|
||||||
|
IconUserCircle,
|
||||||
|
useToast,
|
||||||
|
} from "@probo/ui";
|
||||||
|
|
||||||
import type { ConsentPageMutation } from "#/__generated__/iam/ConsentPageMutation.graphql";
|
import type { ConsentPageMutation } from "#/__generated__/iam/ConsentPageMutation.graphql";
|
||||||
import type { ConsentPageQuery } from "#/__generated__/iam/ConsentPageQuery.graphql";
|
import type { ConsentPageQuery } from "#/__generated__/iam/ConsentPageQuery.graphql";
|
||||||
|
|
||||||
@@ -53,80 +62,12 @@ const scopeLabels: Record<string, string> = {
|
|||||||
offline_access: "Stay signed in and access your data while you're away",
|
offline_access: "Stay signed in and access your data while you're away",
|
||||||
};
|
};
|
||||||
|
|
||||||
function ScopeIcon({ scope }: { scope: string }) {
|
const scopeIcons: Record<string, React.ReactNode> = {
|
||||||
switch (scope) {
|
openid: <IconUser size={18} className="shrink-0 text-txt-tertiary" />,
|
||||||
case "openid":
|
email: <IconEnvelope size={18} className="shrink-0 text-txt-tertiary" />,
|
||||||
return (
|
profile: <IconUserCircle size={18} className="shrink-0 text-txt-tertiary" />,
|
||||||
<svg
|
offline_access: <IconArrowsClockwise size={18} className="shrink-0 text-txt-tertiary" />,
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
};
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
strokeWidth="1.5"
|
|
||||||
stroke="currentColor"
|
|
||||||
className="w-[18px] h-[18px] shrink-0 text-txt-tertiary"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
case "email":
|
|
||||||
return (
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
strokeWidth="1.5"
|
|
||||||
stroke="currentColor"
|
|
||||||
className="w-[18px] h-[18px] shrink-0 text-txt-tertiary"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
d="M21.75 6.75v10.5a2.25 2.25 0 0 1-2.25 2.25h-15a2.25 2.25 0 0 1-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0 0 19.5 4.5h-15a2.25 2.25 0 0 0-2.25 2.25m19.5 0v.243a2.25 2.25 0 0 1-1.07 1.916l-7.5 4.615a2.25 2.25 0 0 1-2.36 0L3.32 8.91a2.25 2.25 0 0 1-1.07-1.916V6.75"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
case "profile":
|
|
||||||
return (
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
strokeWidth="1.5"
|
|
||||||
stroke="currentColor"
|
|
||||||
className="w-[18px] h-[18px] shrink-0 text-txt-tertiary"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
case "offline_access":
|
|
||||||
return (
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
strokeWidth="1.5"
|
|
||||||
stroke="currentColor"
|
|
||||||
className="w-[18px] h-[18px] shrink-0 text-txt-tertiary"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182M21.015 4.356v4.992"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ConsentPage(props: {
|
export default function ConsentPage(props: {
|
||||||
queryRef: PreloadedQuery<ConsentPageQuery>;
|
queryRef: PreloadedQuery<ConsentPageQuery>;
|
||||||
@@ -236,20 +177,7 @@ export default function ConsentPage(props: {
|
|||||||
<div className="space-y-2 text-center">
|
<div className="space-y-2 text-center">
|
||||||
<div className="flex justify-center mb-4">
|
<div className="flex justify-center mb-4">
|
||||||
<div className="w-12 h-12 rounded-full flex items-center justify-center bg-level-1">
|
<div className="w-12 h-12 rounded-full flex items-center justify-center bg-level-1">
|
||||||
<svg
|
<IconLockOpen size={24} />
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
strokeWidth="1.5"
|
|
||||||
stroke="currentColor"
|
|
||||||
className="w-6 h-6"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
d="M13.5 10.5V6.75a4.5 4.5 0 1 1 9 0v3.75M3.75 21.75h10.5a2.25 2.25 0 0 0 2.25-2.25v-6.75a2.25 2.25 0 0 0-2.25-2.25H3.75a2.25 2.25 0 0 0-2.25 2.25v6.75a2.25 2.25 0 0 0 2.25 2.25Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-2xl font-bold">
|
<h1 className="text-2xl font-bold">
|
||||||
@@ -273,7 +201,7 @@ export default function ConsentPage(props: {
|
|||||||
key={scope}
|
key={scope}
|
||||||
className="flex items-center gap-2.5 px-3 py-2.5 text-sm text-txt-secondary border border-border-mid rounded-lg"
|
className="flex items-center gap-2.5 px-3 py-2.5 text-sm text-txt-secondary border border-border-mid rounded-lg"
|
||||||
>
|
>
|
||||||
<ScopeIcon scope={scope} />
|
{scopeIcons[scope]}
|
||||||
{__(label)}
|
{__(label)}
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -22,11 +22,10 @@ import type { ConsentPageQuery } from "#/__generated__/iam/ConsentPageQuery.grap
|
|||||||
import ConsentPage, { consentPageQuery } from "./ConsentPage";
|
import ConsentPage, { consentPageQuery } from "./ConsentPage";
|
||||||
|
|
||||||
function ConsentPageQueryLoader() {
|
function ConsentPageQueryLoader() {
|
||||||
const [searchParams] = useSearchParams();
|
|
||||||
const consentId = searchParams.get("consent_id") ?? "";
|
|
||||||
|
|
||||||
const [queryRef, loadQuery]
|
const [queryRef, loadQuery]
|
||||||
= useQueryLoader<ConsentPageQuery>(consentPageQuery);
|
= useQueryLoader<ConsentPageQuery>(consentPageQuery);
|
||||||
|
const [searchParams] = useSearchParams();
|
||||||
|
const consentId = searchParams.get("consent_id") ?? "";
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadQuery({ consentId });
|
loadQuery({ consentId });
|
||||||
@@ -69,8 +68,11 @@ function ConsentErrorFallback() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function ConsentPageLoader() {
|
export default function ConsentPageLoader() {
|
||||||
|
const [searchParams] = useSearchParams();
|
||||||
|
const consentId = searchParams.get("consent_id") ?? "";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConsentErrorBoundary fallback={<ConsentErrorFallback />}>
|
<ConsentErrorBoundary key={consentId} fallback={<ConsentErrorFallback />}>
|
||||||
<ConsentPageQueryLoader />
|
<ConsentPageQueryLoader />
|
||||||
</ConsentErrorBoundary>
|
</ConsentErrorBoundary>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -44,6 +44,25 @@ type TestEnv struct {
|
|||||||
cmd *exec.Cmd
|
cmd *exec.Cmd
|
||||||
done chan error
|
done chan error
|
||||||
outputBuf *bytes.Buffer
|
outputBuf *bytes.Buffer
|
||||||
|
outputWriter *switchableWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
type switchableWriter struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
w io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *switchableWriter) Write(p []byte) (int, error) {
|
||||||
|
s.mu.Lock()
|
||||||
|
w := s.w
|
||||||
|
s.mu.Unlock()
|
||||||
|
return w.Write(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *switchableWriter) switchTo(w io.Writer) {
|
||||||
|
s.mu.Lock()
|
||||||
|
s.w = w
|
||||||
|
s.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func Setup() {
|
func Setup() {
|
||||||
@@ -93,8 +112,10 @@ func Setup() {
|
|||||||
} else {
|
} else {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
testEnv.outputBuf = &buf
|
testEnv.outputBuf = &buf
|
||||||
cmd.Stdout = &buf
|
sw := &switchableWriter{w: &buf}
|
||||||
cmd.Stderr = &buf
|
testEnv.outputWriter = sw
|
||||||
|
cmd.Stdout = sw
|
||||||
|
cmd.Stderr = sw
|
||||||
}
|
}
|
||||||
|
|
||||||
testEnv.cmd = cmd
|
testEnv.cmd = cmd
|
||||||
@@ -126,8 +147,7 @@ func Setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !verbose {
|
if !verbose {
|
||||||
cmd.Stdout = io.Discard
|
testEnv.outputWriter.switchTo(io.Discard)
|
||||||
cmd.Stderr = io.Discard
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,5 +104,12 @@ export { IconBrandFacebook } from "./IconBrandFacebook";
|
|||||||
export { IconBrandLinkedin } from "./IconBrandLinkedin";
|
export { IconBrandLinkedin } from "./IconBrandLinkedin";
|
||||||
export { IconBrandX } from "./IconBrandX";
|
export { IconBrandX } from "./IconBrandX";
|
||||||
export { IconGlobe } from "./IconGlobe";
|
export { IconGlobe } from "./IconGlobe";
|
||||||
|
export {
|
||||||
|
ArrowsClockwise as IconArrowsClockwise,
|
||||||
|
Envelope as IconEnvelope,
|
||||||
|
LockOpen as IconLockOpen,
|
||||||
|
User as IconUser,
|
||||||
|
UserCircle as IconUserCircle,
|
||||||
|
} from "@phosphor-icons/react";
|
||||||
export { SocialIcon } from "./SocialIcon";
|
export { SocialIcon } from "./SocialIcon";
|
||||||
export type { SocialIconProps } from "./SocialIcon";
|
export type { SocialIconProps } from "./SocialIcon";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
extend type Mutation {
|
extend type Mutation {
|
||||||
authorizeDevice(
|
authorizeDevice(
|
||||||
input: AuthorizeDeviceInput!
|
input: AuthorizeDeviceInput!
|
||||||
): AuthorizeDevicePayload @session(required: PRESENT)
|
): AuthorizeDevicePayload @session(required: PRESENT)
|
||||||
|
|
||||||
approveConsent(
|
approveConsent(
|
||||||
input: ApproveConsentInput!
|
input: ApproveConsentInput!
|
||||||
|
|||||||
Reference in New Issue
Block a user