{"version":3,"sources":["../../../src/lib/user-sessions.tsx"],"sourcesContent":["\"use client\";\n\nimport { Box, Card, Flex, Text } from \"@radix-ui/themes\";\nimport { Badge, Button, Skeleton } from \"./elements.js\";\nimport {\n  getComparativeReadableDate,\n  getDomProps,\n  getUserLocation,\n  parseUserAgent,\n  type WidgetRootDomProps,\n  type WidgetRootState,\n} from \"./utils.js\";\nimport { LogoutDialog } from \"./logout-dialog.js\";\nimport { LogoutAllSessionsDialog } from \"./logout-all-sessions-dialog.js\";\nimport { ActiveSession } from \"../api/endpoint.js\";\nimport * as CardList from \"./card-list.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport { useState } from \"react\";\nimport { GenericError } from \"./generic-error.js\";\nimport { LaptopIcon, MobileIcon } from \"@radix-ui/react-icons\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useLocale } from \"./i18n/use-locale.js\";\n\ninterface UserSessionsProps extends WidgetRootDomProps {\n  sessionsData: ActiveSession[];\n  currentSessionId: string;\n}\n\nconst UserSessions = ({\n  sessionsData: sessions,\n  currentSessionId,\n  ...domProps\n}: UserSessionsProps) => {\n  const currentSession = sessions.find(\n    (session) => session.id === currentSessionId,\n  );\n  const otherSessions = sessions.filter(\n    (session) => session.id !== currentSessionId,\n  );\n  const [openLogoutDialog, setOpenLogoutDialog] = useState(false);\n  const [sessionToSignOut, setSessionToSignOut] =\n    useState<ActiveSession | null>(null);\n  const [openLogoutAllSessionsDialog, setOpenLogoutAllSessionsDialog] =\n    useState(false);\n\n  return (\n    <Flex\n      direction=\"column\"\n      gap=\"4\"\n      {...getWidgetRootDomProps(\"resolved\", domProps)}\n    >\n      <CardList.Root>\n        {currentSession && (\n          <CardList.Item>\n            <UserSession session={currentSession} isCurrentSession />\n          </CardList.Item>\n        )}\n\n        {otherSessions.map((session) => (\n          <CardList.Item key={session.id}>\n            <UserSession\n              session={session}\n              onSignOut={() => {\n                setSessionToSignOut(session);\n                setOpenLogoutDialog(true);\n              }}\n            />\n          </CardList.Item>\n        ))}\n      </CardList.Root>\n\n      {sessions.length > 1 && (\n        <Card size=\"2\">\n          <Flex gap=\"2\" justify=\"between\" align=\"center\">\n            <Box>\n              <Text size=\"2\" highContrast weight=\"bold\" as=\"p\">\n                <Translation\n                  defaultMessage=\"Sign out of all other devices\"\n                  id=\"sfkEFa\"\n                  description=\"Heading for sign out all other devices action\"\n                />\n              </Text>\n              <Text size=\"2\" color=\"gray\" as=\"p\">\n                <Translation\n                  defaultMessage=\"Remove access from all devices except this one\"\n                  id=\"LsD5BK\"\n                  description=\"Description for sign out all other devices action\"\n                />\n              </Text>\n            </Box>\n            <Button\n              variant=\"secondary\"\n              onClick={() => {\n                setOpenLogoutAllSessionsDialog(true);\n              }}\n            >\n              <Translation\n                defaultMessage=\"Sign out\"\n                id=\"oKQ0rm\"\n                description=\"Button text to sign out of all other devices\"\n              />\n            </Button>\n          </Flex>\n        </Card>\n      )}\n\n      {sessionToSignOut && (\n        <LogoutDialog\n          session={sessionToSignOut}\n          open={openLogoutDialog}\n          onOpenChange={setOpenLogoutDialog}\n        />\n      )}\n\n      <LogoutAllSessionsDialog\n        currentSessionId={currentSessionId}\n        open={openLogoutAllSessionsDialog}\n        onOpenChange={setOpenLogoutAllSessionsDialog}\n      />\n    </Flex>\n  );\n};\n\ninterface UserSessionsLoadingProps extends WidgetRootDomProps {}\n\nconst UserSessionsLoading: React.FC<UserSessionsLoadingProps> = (props) => {\n  return (\n    <Card size=\"2\" {...getWidgetRootDomProps(\"loading\", props)}>\n      <Flex gap=\"4\" align=\"center\">\n        <Skeleton>\n          <IconPanel />\n        </Skeleton>\n\n        <Flex direction=\"column\">\n          <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n            <Skeleton>\n              <Translation\n                defaultMessage=\"The location\"\n                id=\"+7UnNu\"\n                description=\"Loading placeholder text for session location\"\n              />\n            </Skeleton>\n          </Text>\n\n          <Text size=\"2\" color=\"gray\" as=\"p\">\n            <Skeleton>\n              <Translation\n                defaultMessage=\"The location\"\n                id=\"+7UnNu\"\n                description=\"Loading placeholder text for session location\"\n              />\n            </Skeleton>\n          </Text>\n        </Flex>\n      </Flex>\n    </Card>\n  );\n};\n\ninterface UserSessionsErrorProps extends WidgetRootDomProps {\n  error: unknown;\n}\n\nconst UserSessionsError: React.FC<UserSessionsErrorProps> = ({\n  error,\n  ...domProps\n}) => {\n  return (\n    <Card size=\"2\" {...getWidgetRootDomProps(\"error\", domProps)}>\n      <GenericError error={error} />\n    </Card>\n  );\n};\n\ninterface UserSessionProps {\n  session: ActiveSession;\n  isCurrentSession?: boolean;\n  onSignOut?: (session: ActiveSession) => void;\n}\n\nconst UserSession = ({\n  session,\n  isCurrentSession = false,\n  onSignOut,\n}: UserSessionProps) => {\n  const userAgent = parseUserAgent(session.userAgent);\n  const userLocation = getUserLocation(\n    session.currentLocation,\n    session.ipAddress,\n  );\n  const locale = useLocale();\n\n  return (\n    <Flex gap=\"4\" align=\"center\">\n      <IconPanel>\n        {userAgent.isMobile ? <MobileIcon /> : <LaptopIcon />}\n      </IconPanel>\n\n      <Flex direction=\"column\">\n        <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n          {userAgent.pretty}\n        </Text>\n\n        <Flex gap=\"1\" align=\"center\">\n          <Text size=\"2\" color=\"gray\" as=\"p\">\n            {userLocation}\n          </Text>\n\n          {isCurrentSession && (\n            <Badge ml=\"2\">\n              <Translation\n                defaultMessage=\"This device\"\n                id=\"Wz8T8u\"\n                description=\"Badge label indicating the current device session\"\n              />\n            </Badge>\n          )}\n\n          {!isCurrentSession && session.lastActivityAt && (\n            <>\n              {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n              <Text size=\"2\" color=\"gray\">\n                ∙\n              </Text>\n              <Text size=\"2\" color=\"gray\">\n                <Translation\n                  defaultMessage=\"Last seen {timeAgo}\"\n                  id=\"gF+kUw\"\n                  description=\"Text showing when the session was last active\"\n                  values={{\n                    timeAgo: getComparativeReadableDate(\n                      new Date(),\n                      new Date(session.lastActivityAt),\n                      { locale },\n                    ),\n                  }}\n                />\n              </Text>\n            </>\n          )}\n        </Flex>\n      </Flex>\n\n      {!isCurrentSession && (\n        <Flex ml=\"auto\">\n          <Button variant=\"secondary\" onClick={() => onSignOut?.(session)}>\n            <Translation\n              defaultMessage=\"Sign out\"\n              id=\"sT1L78\"\n              description=\"Button text to sign out of a session\"\n            />\n          </Button>\n        </Flex>\n      )}\n    </Flex>\n  );\n};\n\nfunction getWidgetRootDomProps(\n  state: WidgetRootState,\n  domProps: WidgetRootDomProps,\n) {\n  return getDomProps({\n    ...domProps,\n    isWidgetRoot: true,\n    widgetId: \"user-sessions\",\n    widgetState: state,\n  });\n}\n\nexport type { UserSessionsLoadingProps, UserSessionsErrorProps };\nexport { UserSessions, UserSessionsLoading, UserSessionsError };\n"],"mappings":"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","names":[]}