six-degrees 0.3.0 → 0.4.0-beta.1
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/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +1 -0
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +34 -6
- package/.next/standalone/.next/routes-manifest.json +6 -0
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +10 -10
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +9 -9
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/admin-delete/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/admin-update/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/bridges/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/bulk-import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/company-scores/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/connections/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/export/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/restart/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/reveal/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/delete-cluster/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/ingest/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/outreach/route.js +3 -3
- package/.next/standalone/.next/server/app/api/outreach/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/queue/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/scraper/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/setup-profile/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/unlock/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/update-images/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/users/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/avatars/[file]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/import/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/import/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/import.html +1 -1
- package/.next/standalone/.next/server/app/import.rsc +12 -12
- package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/import.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/import.segments/import/__PAGE__.segment.rsc +11 -11
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +12 -12
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +11 -11
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/launch/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/launch/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/launch.html +2 -2
- package/.next/standalone/.next/server/app/launch.rsc +12 -12
- package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/launch.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/launch.segments/launch/__PAGE__.segment.rsc +11 -11
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/paths/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/paths/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/paths.html +1 -1
- package/.next/standalone/.next/server/app/paths.rsc +12 -12
- package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/paths.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/paths.segments/paths/__PAGE__.segment.rsc +11 -11
- package/.next/standalone/.next/server/app/profile/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/profile/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/profile.html +1 -1
- package/.next/standalone/.next/server/app/profile.rsc +12 -12
- package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/profile.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/profile.segments/profile/__PAGE__.segment.rsc +11 -11
- package/.next/standalone/.next/server/app/queue/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/queue/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/queue.html +1 -1
- package/.next/standalone/.next/server/app/queue.rsc +12 -12
- package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/queue.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/queue.segments/queue/__PAGE__.segment.rsc +11 -11
- package/.next/standalone/.next/server/app/scores/page/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/scores/page/build-manifest.json +20 -0
- package/.next/standalone/.next/server/app/scores/page/next-font-manifest.json +11 -0
- package/.next/standalone/.next/server/app/scores/page/react-loadable-manifest.json +1 -0
- package/.next/standalone/.next/server/app/scores/page/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/scores/page.js +13 -0
- package/.next/standalone/.next/server/app/scores/page.js.map +5 -0
- package/.next/standalone/.next/server/app/scores/page.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/scores/page_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/scores.html +1 -0
- package/.next/standalone/.next/server/app/scores.meta +26 -0
- package/.next/standalone/.next/server/app/scores.rsc +24 -0
- package/.next/standalone/.next/server/app/scores.segments/_full.segment.rsc +24 -0
- package/.next/standalone/.next/server/app/scores.segments/_tree.segment.rsc +4 -0
- package/.next/standalone/.next/server/app/scores.segments/scores/__PAGE__.segment.rsc +28 -0
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings.html +1 -1
- package/.next/standalone/.next/server/app/settings.rsc +12 -12
- package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +11 -11
- package/.next/standalone/.next/server/app/setup/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/setup.html +1 -1
- package/.next/standalone/.next/server/app/setup.rsc +12 -12
- package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +11 -11
- package/.next/standalone/.next/server/app-paths-manifest.json +1 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rc27za._.js +8 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1kbl21f._.js +1 -1
- package/.next/standalone/.next/server/chunks/_02twlca._.js +10 -0
- package/.next/standalone/.next/server/chunks/_072jl0y._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0lw8_i0._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1_fynia._.js +7 -6
- package/.next/standalone/.next/server/chunks/_1itd1o_._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1iwkh8t._.js +1 -1
- package/.next/standalone/.next/server/chunks/lib_db-client_15le7cw.js +3 -2
- package/.next/standalone/.next/server/chunks/lib_rpc_0c9d9ti.js +5 -5
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0an6blh._.js → [root-of-the-server]__0zzcbqg._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1194jps._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1z1j3ek._.js → [root-of-the-server]__19ip1qq._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_01f38ty._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0223v9s._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0bcf13g._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0cu6-an._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0wxbq78._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0z88zcl._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_17gui6a._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1cyxocj._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1gpbbw9._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_scores_page_actions_0x-w58n.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_launch_page_19t0dyd.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +4 -4
- package/.next/standalone/.next/server/chunks/ssr/app_paths_page_1ol90m7.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/app_profile_page_0u3-l5y.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_queue_page_0c6znd6.js +5 -5
- package/.next/standalone/.next/server/chunks/ssr/app_scores_page_09wepvv.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_settings_page_1f8mjj_.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/lib_1bn38gs._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_0x3i8za._.js +131 -0
- package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_1bunoni._.js → node_modules_next_dist_1v8aef8._.js} +2 -2
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/middleware-manifest.json +5 -5
- package/.next/standalone/.next/server/next-font-manifest.js +1 -1
- package/.next/standalone/.next/server/next-font-manifest.json +4 -0
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/prefetch-hints.json +14 -0
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/0_yurn4q91vq8.js +16 -0
- package/.next/standalone/.next/static/chunks/0d_mh-06srh2k.js +1 -0
- package/.next/standalone/.next/static/chunks/0x3oadfikvb1c.js +1 -0
- package/.next/standalone/.next/static/chunks/1d5hl1io798n2.js +1 -0
- package/.next/standalone/.next/static/chunks/1qt67cvj9sjwi.js +1 -0
- package/.next/{static/chunks/1chp3nx45meg5.js → standalone/.next/static/chunks/1roznk7hkjes1.js} +1 -1
- package/.next/standalone/.next/static/chunks/2_bf2n4gstad9.js +33 -0
- package/.next/standalone/.next/static/chunks/36gbwek52x_w-.js +2 -0
- package/.next/standalone/.next/static/chunks/3a55suosthntc.js +1 -0
- package/.next/standalone/.next/static/chunks/3fq1zq-6cfwbc.js +1 -0
- package/.next/standalone/.next/static/chunks/3nbnio971zlji.js +2 -0
- package/.next/standalone/.next/static/chunks/3s6awp3qq9s7w.js +1 -0
- package/.next/standalone/CHANGELOG.md +134 -0
- package/.next/standalone/README.md +30 -15
- package/.next/standalone/app/api/company-scores/legacy/route.js +1 -1
- package/.next/standalone/app/api/company-scores/route.js +1 -1
- package/.next/standalone/app/api/ingest/route.js +17 -1
- package/.next/standalone/app/api/outreach/route.js +107 -44
- package/.next/standalone/app/api/scraper/route.js +69 -8
- package/.next/standalone/app/api/settings/sector-preview/route.js +3 -2
- package/.next/standalone/app/api/settings/sector-suggestions/route.js +1 -1
- package/.next/standalone/app/components/CompanyScores.js +16 -10
- package/.next/standalone/app/components/LegacyScoresCard.js +1 -1
- package/.next/standalone/app/components/OrbitGraph.js +30 -0
- package/.next/standalone/app/components/PathsAnalyzer.js +1 -1
- package/.next/standalone/app/components/SeparationView.js +96 -14
- package/.next/standalone/app/components/Sidebar.js +258 -239
- package/.next/standalone/app/components/TheirCircle.js +293 -0
- package/.next/standalone/app/components/settings/SectorSection.js +5 -5
- package/.next/standalone/app/components/settings/TierSection.js +104 -0
- package/.next/standalone/app/components/useRequests.js +12 -0
- package/.next/standalone/app/components/useScanner.js +13 -0
- package/.next/standalone/app/components/views.js +1 -3
- package/.next/standalone/app/launch/page.js +4 -1
- package/.next/standalone/app/page.js +55 -51
- package/.next/standalone/app/paths/page.js +17 -12
- package/.next/standalone/app/profile/page.js +3 -3
- package/.next/standalone/app/queue/page.js +38 -50
- package/.next/standalone/app/scores/page.js +72 -0
- package/.next/standalone/app/settings/page.js +15 -3
- package/.next/standalone/db/schema.js +1 -0
- package/.next/standalone/lib/circle.js +169 -0
- package/.next/standalone/lib/companies.js +1 -1
- package/.next/standalone/lib/csv.js +17 -4
- package/.next/standalone/lib/db-client.js +1 -0
- package/.next/standalone/lib/ingest.js +12 -0
- package/.next/standalone/lib/legacy-offer.js +7 -6
- package/.next/standalone/lib/legacy-scores.js +2 -2
- package/.next/standalone/lib/rarity.js +80 -0
- package/.next/standalone/lib/requests-client.js +113 -0
- package/.next/standalone/lib/rpc.js +26 -15
- package/.next/standalone/lib/score-guess.js +60 -0
- package/.next/standalone/lib/scoring.js +1002 -61
- package/.next/standalone/lib/scraper-client.js +208 -17
- package/.next/standalone/lib/sector-directory.js +1 -1
- package/.next/standalone/lib/sector-focus.js +4 -3
- package/.next/standalone/lib/settings-effects.js +19 -1
- package/.next/standalone/lib/settings.js +4 -1
- package/.next/standalone/package-lock.json +2 -2
- package/.next/standalone/package.json +2 -2
- package/.next/standalone/public/demo-data.json +1 -1
- package/.next/standalone/scripts/gen-synthetic.mjs +1 -1
- package/.next/standalone/scripts/scrape.py +62 -0
- package/.next/static/chunks/0_yurn4q91vq8.js +16 -0
- package/.next/static/chunks/0d_mh-06srh2k.js +1 -0
- package/.next/static/chunks/0x3oadfikvb1c.js +1 -0
- package/.next/static/chunks/1d5hl1io798n2.js +1 -0
- package/.next/static/chunks/1qt67cvj9sjwi.js +1 -0
- package/.next/{standalone/.next/static/chunks/1chp3nx45meg5.js → static/chunks/1roznk7hkjes1.js} +1 -1
- package/.next/static/chunks/2_bf2n4gstad9.js +33 -0
- package/.next/static/chunks/36gbwek52x_w-.js +2 -0
- package/.next/static/chunks/3a55suosthntc.js +1 -0
- package/.next/static/chunks/3fq1zq-6cfwbc.js +1 -0
- package/.next/static/chunks/3nbnio971zlji.js +2 -0
- package/.next/static/chunks/3s6awp3qq9s7w.js +1 -0
- package/CHANGELOG.md +134 -0
- package/README.md +30 -15
- package/db/schema.js +1 -0
- package/lib/circle.js +169 -0
- package/lib/companies.js +1 -1
- package/lib/csv.js +17 -4
- package/lib/db-client.js +1 -0
- package/lib/ingest.js +12 -0
- package/lib/legacy-offer.js +7 -6
- package/lib/legacy-scores.js +2 -2
- package/lib/rarity.js +80 -0
- package/lib/requests-client.js +113 -0
- package/lib/rpc.js +26 -15
- package/lib/score-guess.js +60 -0
- package/lib/scoring.js +1002 -61
- package/lib/scraper-client.js +208 -17
- package/lib/sector-directory.js +1 -1
- package/lib/sector-focus.js +4 -3
- package/lib/settings-effects.js +19 -1
- package/lib/settings.js +4 -1
- package/package.json +2 -2
- package/public/demo-data.json +1 -1
- package/scripts/scrape.py +62 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1t3rugi._.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0jzisgh.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_07u8byv._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_08r_mlf._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0942v8n._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0hl_t7r._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0tb83dw._.js +0 -132
- package/.next/standalone/.next/server/chunks/ssr/lib_0i8v-s3._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/node_modules_16vay6l._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/node_modules_1kciwn4._.js +0 -3
- package/.next/standalone/.next/static/chunks/06x3jiiz96m5t.js +0 -1
- package/.next/standalone/.next/static/chunks/08k1crid-05dt.js +0 -1
- package/.next/standalone/.next/static/chunks/0ngx9s6-zgshe.js +0 -33
- package/.next/standalone/.next/static/chunks/0q-_khndfxubv.js +0 -2
- package/.next/standalone/.next/static/chunks/1c79veqedvubt.js +0 -1
- package/.next/standalone/.next/static/chunks/1irqj0lf-fu3d.js +0 -1
- package/.next/standalone/.next/static/chunks/1uadqylrod5_v.js +0 -1
- package/.next/standalone/.next/static/chunks/23u0zclgwpc4d.js +0 -1
- package/.next/standalone/.next/static/chunks/289ktj97di6zg.js +0 -1
- package/.next/standalone/.next/static/chunks/2b3lmf8e6uj8m.js +0 -16
- package/.next/standalone/.next/static/chunks/3npq5yd7c4dmn.js +0 -2
- package/.next/standalone/app/components/BridgeRing.js +0 -753
- package/.next/static/chunks/06x3jiiz96m5t.js +0 -1
- package/.next/static/chunks/08k1crid-05dt.js +0 -1
- package/.next/static/chunks/0ngx9s6-zgshe.js +0 -33
- package/.next/static/chunks/0q-_khndfxubv.js +0 -2
- package/.next/static/chunks/1c79veqedvubt.js +0 -1
- package/.next/static/chunks/1irqj0lf-fu3d.js +0 -1
- package/.next/static/chunks/1uadqylrod5_v.js +0 -1
- package/.next/static/chunks/23u0zclgwpc4d.js +0 -1
- package/.next/static/chunks/289ktj97di6zg.js +0 -1
- package/.next/static/chunks/2b3lmf8e6uj8m.js +0 -16
- package/.next/static/chunks/3npq5yd7c4dmn.js +0 -2
- /package/.next/standalone/.next/static/{qqqcxvzBUizkECrT4swyK → NnWlxbDF24KhrU1eHiEnv}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{qqqcxvzBUizkECrT4swyK → NnWlxbDF24KhrU1eHiEnv}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{qqqcxvzBUizkECrT4swyK → NnWlxbDF24KhrU1eHiEnv}/_ssgManifest.js +0 -0
- /package/.next/static/{qqqcxvzBUizkECrT4swyK → NnWlxbDF24KhrU1eHiEnv}/_buildManifest.js +0 -0
- /package/.next/static/{qqqcxvzBUizkECrT4swyK → NnWlxbDF24KhrU1eHiEnv}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{qqqcxvzBUizkECrT4swyK → NnWlxbDF24KhrU1eHiEnv}/_ssgManifest.js +0 -0
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useEffect, useState, useRef, useMemo, useCallback } from 'react';
|
|
4
|
-
import { scraperStatus,
|
|
4
|
+
import { scraperStatus, beginScrape, notReadyMessage, busyReason } from '../lib/scraper-client';
|
|
5
|
+
import useScanner from './components/useScanner';
|
|
6
|
+
import useRequests from './components/useRequests';
|
|
7
|
+
import { requestCount } from '../lib/requests-client';
|
|
5
8
|
import { loadNetwork } from '../lib/network';
|
|
6
9
|
import { resolveView } from './components/views';
|
|
7
10
|
import Sidebar from './components/Sidebar';
|
|
@@ -59,9 +62,10 @@ function HomeInner() {
|
|
|
59
62
|
const [visualMode, setVisualMode] = useState('galaxy');
|
|
60
63
|
const [notifications, setNotifications] = useState([]);
|
|
61
64
|
const [showNotifs, setShowNotifs] = useState(false);
|
|
62
|
-
const [pending, setPending] = useState([]);
|
|
63
65
|
const [csvMode, setCsvMode] = useState(false);
|
|
64
66
|
const [csvSource, setCsvSource] = useState('csv');
|
|
67
|
+
// Everyone with a request out, shared with every view (lib/requests-client.js).
|
|
68
|
+
const pendingCount = requestCount(useRequests());
|
|
65
69
|
|
|
66
70
|
useEffect(() => {
|
|
67
71
|
if (!userId) return;
|
|
@@ -93,8 +97,6 @@ function HomeInner() {
|
|
|
93
97
|
if (!IS_DEMO && !hasCsvNetwork()) {
|
|
94
98
|
// Fetch notifications
|
|
95
99
|
fetch(`/api/notifications?userId=${userId}`).then(r => r.json()).then(d => setNotifications(d.notifications || [])).catch(() => {});
|
|
96
|
-
// Fetch pending outreach
|
|
97
|
-
fetch(`/api/outreach?userId=${userId}`).then(r => r.json()).then(d => setPending(d.pending || [])).catch(() => {});
|
|
98
100
|
}
|
|
99
101
|
}, [userId]);
|
|
100
102
|
|
|
@@ -215,6 +217,16 @@ function HomeInner() {
|
|
|
215
217
|
>
|
|
216
218
|
Paths
|
|
217
219
|
</Link>}
|
|
220
|
+
{!IS_DEMO && !csvMode && <Link
|
|
221
|
+
href="/scores"
|
|
222
|
+
style={{
|
|
223
|
+
padding: isMobile ? '6px 10px' : '8px 16px', borderRadius: 6, border: 'none', fontSize: isMobile ? 11 : 13, fontWeight: 600,
|
|
224
|
+
background: 'rgba(255,255,255,0.06)', color: '#FFD700', textDecoration: 'none',
|
|
225
|
+
display: 'flex', alignItems: 'center', gap: 4,
|
|
226
|
+
}}
|
|
227
|
+
>
|
|
228
|
+
Scores
|
|
229
|
+
</Link>}
|
|
218
230
|
{!IS_DEMO && !csvMode && <Link
|
|
219
231
|
href="/queue"
|
|
220
232
|
style={{
|
|
@@ -316,28 +328,7 @@ function HomeInner() {
|
|
|
316
328
|
)}
|
|
317
329
|
</div>}
|
|
318
330
|
{/* Refresh button — checks connections + notifies */}
|
|
319
|
-
{!IS_DEMO && !csvMode && <
|
|
320
|
-
onClick={async () => {
|
|
321
|
-
try {
|
|
322
|
-
const status = await scraperStatus();
|
|
323
|
-
const blocked = notReadyMessage(status);
|
|
324
|
-
if (blocked) { alert(blocked); return; }
|
|
325
|
-
if (status.running) { alert('The scanner is already busy.'); return; }
|
|
326
|
-
await startScrape('refresh');
|
|
327
|
-
alert('Checking for new connections — watch it on the Scan page.');
|
|
328
|
-
} catch (e) {
|
|
329
|
-
alert(e.message);
|
|
330
|
-
}
|
|
331
|
-
}}
|
|
332
|
-
title="Refresh connections + bridges"
|
|
333
|
-
style={{
|
|
334
|
-
width: isMobile ? 28 : 32, height: isMobile ? 28 : 32, borderRadius: '50%', border: 'none', cursor: 'pointer',
|
|
335
|
-
background: 'rgba(255,255,255,0.06)', color: '#888', fontSize: isMobile ? 12 : 14,
|
|
336
|
-
display: isMobile ? 'none' : 'flex', alignItems: 'center', justifyContent: 'center', marginLeft: 8,
|
|
337
|
-
}}
|
|
338
|
-
>
|
|
339
|
-
↻
|
|
340
|
-
</button>}
|
|
331
|
+
{!IS_DEMO && !csvMode && <RefreshButton isMobile={isMobile} />}
|
|
341
332
|
{/* Profile icon — top right */}
|
|
342
333
|
<a href={IS_DEMO ? '/launch' : csvMode ? '/import' : '/profile'} style={{
|
|
343
334
|
width: isMobile ? 30 : 36, height: isMobile ? 30 : 36, borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
@@ -356,8 +347,8 @@ function HomeInner() {
|
|
|
356
347
|
</a>
|
|
357
348
|
</div>
|
|
358
349
|
|
|
359
|
-
{/* Pending count badge — in header */}
|
|
360
|
-
{isDegreesMode &&
|
|
350
|
+
{/* Pending count badge — in header: everyone with a request out, once each (lib/requests-client.js) */}
|
|
351
|
+
{isDegreesMode && !csvMode && pendingCount > 0 && (
|
|
361
352
|
<Link href="/queue" style={{
|
|
362
353
|
padding: '5px 12px', borderRadius: 16, fontSize: 12, fontWeight: 600, textDecoration: 'none',
|
|
363
354
|
background: 'rgba(255,107,53,0.12)', color: '#FF6B35',
|
|
@@ -365,7 +356,7 @@ function HomeInner() {
|
|
|
365
356
|
display: 'inline-flex', alignItems: 'center', gap: 5,
|
|
366
357
|
}}>
|
|
367
358
|
<span style={{ fontSize: 10 }}>⏳</span>
|
|
368
|
-
{
|
|
359
|
+
{pendingCount} Pending
|
|
369
360
|
</Link>
|
|
370
361
|
)}
|
|
371
362
|
</header>
|
|
@@ -428,6 +419,10 @@ function HomeInner() {
|
|
|
428
419
|
selectedId: selected?.id ?? null,
|
|
429
420
|
tierColors: TIER_COLORS,
|
|
430
421
|
focusNodeRef,
|
|
422
|
+
// Every row, whatever the filters: rarity counts the ways in across
|
|
423
|
+
// all your scanned circles, and "already connected" needs everyone.
|
|
424
|
+
fullDegree1: degree1,
|
|
425
|
+
fullDegree2: degree2,
|
|
431
426
|
};
|
|
432
427
|
return <View {...viewProps} />;
|
|
433
428
|
})()}
|
|
@@ -440,32 +435,10 @@ function HomeInner() {
|
|
|
440
435
|
mode={mode}
|
|
441
436
|
collapsed={sidebarCollapsed}
|
|
442
437
|
filter={filter}
|
|
443
|
-
pending={pending}
|
|
444
438
|
onToggle={() => setSidebarCollapsed(!sidebarCollapsed)}
|
|
445
439
|
onSelect={(node) => { setSelected(node || null); }}
|
|
446
440
|
onSwitchMode={(newMode) => { setMode(newMode); setFilter('all'); }}
|
|
447
441
|
onFocusNode={(nodeId) => { if (focusNodeRef.current) focusNodeRef.current(nodeId); }}
|
|
448
|
-
onMarkSent={async (person) => {
|
|
449
|
-
if (IS_DEMO) return;
|
|
450
|
-
const id = person.id;
|
|
451
|
-
const url = person.profile_url;
|
|
452
|
-
await fetch('/api/outreach', {
|
|
453
|
-
method: 'POST',
|
|
454
|
-
headers: { 'Content-Type': 'application/json' },
|
|
455
|
-
body: JSON.stringify({ action: 'mark-sent', connectionId: id, profileUrl: url }),
|
|
456
|
-
});
|
|
457
|
-
setPending(prev => [...prev, person]);
|
|
458
|
-
}}
|
|
459
|
-
onUndoPending={async (person) => {
|
|
460
|
-
if (IS_DEMO) return;
|
|
461
|
-
const id = person.id;
|
|
462
|
-
await fetch('/api/outreach', {
|
|
463
|
-
method: 'POST',
|
|
464
|
-
headers: { 'Content-Type': 'application/json' },
|
|
465
|
-
body: JSON.stringify({ action: 'undo', connectionId: id }),
|
|
466
|
-
});
|
|
467
|
-
setPending(prev => prev.filter(p => p.id !== id));
|
|
468
|
-
}}
|
|
469
442
|
/>
|
|
470
443
|
|
|
471
444
|
{/* Galaxy experimental toggle — bottom right, Degrees mode only.
|
|
@@ -501,3 +474,34 @@ function HomeInner() {
|
|
|
501
474
|
</div>
|
|
502
475
|
);
|
|
503
476
|
}
|
|
477
|
+
|
|
478
|
+
// Its own component so the scanner's answer, which changes every second or two
|
|
479
|
+
// while a scan runs, re-renders this button and not the whole map.
|
|
480
|
+
function RefreshButton({ isMobile }) {
|
|
481
|
+
const scan = useScanner();
|
|
482
|
+
const busy = busyReason(scan);
|
|
483
|
+
return (
|
|
484
|
+
<button
|
|
485
|
+
onClick={async () => {
|
|
486
|
+
try {
|
|
487
|
+
const blocked = notReadyMessage(await scraperStatus());
|
|
488
|
+
if (blocked) { alert(blocked); return; }
|
|
489
|
+
await beginScrape('refresh');
|
|
490
|
+
alert('Checking for new connections — watch it on the Scan page.');
|
|
491
|
+
} catch (e) {
|
|
492
|
+
alert(e.message);
|
|
493
|
+
}
|
|
494
|
+
}}
|
|
495
|
+
disabled={Boolean(busy)}
|
|
496
|
+
title={busy ? `${busy}. One scan at a time.` : 'Refresh connections + bridges'}
|
|
497
|
+
style={{
|
|
498
|
+
width: isMobile ? 28 : 32, height: isMobile ? 28 : 32, borderRadius: '50%', border: 'none',
|
|
499
|
+
cursor: busy ? 'not-allowed' : 'pointer', opacity: busy ? 0.4 : 1,
|
|
500
|
+
background: 'rgba(255,255,255,0.06)', color: '#888', fontSize: isMobile ? 12 : 14,
|
|
501
|
+
display: isMobile ? 'none' : 'flex', alignItems: 'center', justifyContent: 'center', marginLeft: 8,
|
|
502
|
+
}}
|
|
503
|
+
>
|
|
504
|
+
↻
|
|
505
|
+
</button>
|
|
506
|
+
);
|
|
507
|
+
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { Suspense, useEffect, useState } from 'react';
|
|
4
|
-
import { useSearchParams } from 'next/navigation';
|
|
5
|
-
import { runScrape, scraperStatus, notReadyMessage } from '../../lib/scraper-client';
|
|
4
|
+
import { useRouter, useSearchParams } from 'next/navigation';
|
|
5
|
+
import { runScrape, scraperStatus, notReadyMessage, busyReason } from '../../lib/scraper-client';
|
|
6
6
|
import { loadNetwork } from '../../lib/network';
|
|
7
7
|
import { IS_DEMO } from '../../lib/demo';
|
|
8
8
|
import { hasCsvNetwork, loadCsvNetwork } from '../../lib/csv';
|
|
9
9
|
import OnboardingGate from '../components/OnboardingGate';
|
|
10
10
|
import PathsAnalyzer from '../components/PathsAnalyzer';
|
|
11
|
-
import CompanyScores from '../components/CompanyScores';
|
|
12
11
|
import { useUser } from '../components/UserProvider';
|
|
12
|
+
import useScanner from '../components/useScanner';
|
|
13
13
|
import Link from 'next/link';
|
|
14
14
|
import { companyOf, getSeniority } from '../../lib/companies';
|
|
15
15
|
|
|
16
16
|
const TIER_COLORS = { S: '#FFD700', A: '#9B59B6', B: '#3498DB', C: '#95A5A6', D: '#BDC3C7' };
|
|
17
|
-
const TABS = [['map', 'Map'], ['industries', 'Industries'], ['companies', 'Companies']
|
|
17
|
+
const TABS = [['map', 'Map'], ['industries', 'Industries'], ['companies', 'Companies']];
|
|
18
18
|
|
|
19
19
|
export default function PathsPage() {
|
|
20
20
|
// Suspense because PathsInner reads the address's ?tab= (useSearchParams),
|
|
@@ -32,11 +32,14 @@ function PathsInner() {
|
|
|
32
32
|
const [d2Data, setD2Data] = useState([]);
|
|
33
33
|
const [d3Data, setD3Data] = useState([]);
|
|
34
34
|
// Map and Industries are the analyzer; Companies is the list it grew from.
|
|
35
|
-
// A link can open a tab (/paths?tab=scores
|
|
35
|
+
// A link can open a tab (/paths?tab=companies). Company scores have a tab of
|
|
36
|
+
// their own now (app/scores): an old link to /paths?tab=scores goes there.
|
|
36
37
|
// The router's search params rather than window.location: on a click from
|
|
37
38
|
// another page the address bar only changes after this page has rendered.
|
|
38
39
|
const asked = useSearchParams().get('tab');
|
|
39
40
|
const [tab, setTab] = useState(() => (TABS.some(([k]) => k === asked) ? asked : 'map'));
|
|
41
|
+
const router = useRouter();
|
|
42
|
+
useEffect(() => { if (asked === 'scores') router.replace('/scores#companies'); }, [asked, router]);
|
|
40
43
|
// Bumped when company scores change, so the network reloads with new tiers.
|
|
41
44
|
const [reloadKey, setReloadKey] = useState(0);
|
|
42
45
|
|
|
@@ -92,6 +95,9 @@ function PathsInner() {
|
|
|
92
95
|
|
|
93
96
|
const [scanning, setScanning] = useState(false);
|
|
94
97
|
const [scanLog, setScanLog] = useState([]);
|
|
98
|
+
// Anything else the scanner runs (a profile card's scan, say) greys this out too.
|
|
99
|
+
const scan = useScanner();
|
|
100
|
+
const busy = !scanning && scan.running ? busyReason(scan) : null;
|
|
95
101
|
|
|
96
102
|
function enrichPeople(people) {
|
|
97
103
|
const d1Urls = new Set(d1Data.map(c => c.profile_url));
|
|
@@ -255,13 +261,14 @@ function PathsInner() {
|
|
|
255
261
|
<span style={{ fontSize: 11, color: '#888' }}>
|
|
256
262
|
{connectedCount}/{companyPeople.length} connected
|
|
257
263
|
</span>
|
|
258
|
-
<button onClick={scanFullCompany} disabled={scanning}
|
|
264
|
+
<button onClick={scanFullCompany} disabled={scanning || Boolean(busy)}
|
|
265
|
+
title={busy ? `${busy}. One scan at a time.` : undefined}
|
|
259
266
|
style={{
|
|
260
|
-
marginLeft: 'auto', padding: '5px 12px', borderRadius: 6, border: 'none', cursor: scanning ? 'not-allowed' : 'pointer',
|
|
261
|
-
background: scanning ? '#333' : 'rgba(0,255,136,0.15)', color: scanning ? '#555' : '#00ff88',
|
|
267
|
+
marginLeft: 'auto', padding: '5px 12px', borderRadius: 6, border: 'none', cursor: scanning || busy ? 'not-allowed' : 'pointer',
|
|
268
|
+
background: scanning || busy ? '#333' : 'rgba(0,255,136,0.15)', color: scanning || busy ? '#555' : '#00ff88',
|
|
262
269
|
fontSize: 11, fontWeight: 600,
|
|
263
270
|
}}>
|
|
264
|
-
{scanning ? 'Scanning...' : '+ Scan Full Company'}
|
|
271
|
+
{scanning ? 'Scanning...' : busy ? 'Scanner busy' : '+ Scan Full Company'}
|
|
265
272
|
</button>
|
|
266
273
|
<span
|
|
267
274
|
title="Not yet tested against live LinkedIn. Results may be incomplete."
|
|
@@ -275,9 +282,7 @@ function PathsInner() {
|
|
|
275
282
|
</div>
|
|
276
283
|
</header>
|
|
277
284
|
|
|
278
|
-
{!selectedCompany && tab
|
|
279
|
-
<CompanyScores onRescored={() => setReloadKey((k) => k + 1)} />
|
|
280
|
-
) : !selectedCompany && tab !== 'companies' ? (
|
|
285
|
+
{!selectedCompany && tab !== 'companies' ? (
|
|
281
286
|
<PathsAnalyzer d1={d1Data} d2={d2Data} d3={d3Data} tab={tab}
|
|
282
287
|
onOpenCompany={(co) => selectCompany({ ...co, sCount: co.S, aCount: co.A })} />
|
|
283
288
|
) : (
|
|
@@ -33,7 +33,7 @@ function ProfileInner() {
|
|
|
33
33
|
const [notifications, setNotifications] = useState([]);
|
|
34
34
|
const [queueStats, setQueueStats] = useState({ total: 0, sent: 0, accepted: 0 });
|
|
35
35
|
const [mapping, setMapping] = useState({ degree1: [], degree2: [], skips: [] });
|
|
36
|
-
// "Your Sectors" is what you picked in
|
|
36
|
+
// "Your Sectors" is what you picked in Scores → Your sector. (users.sectors,
|
|
37
37
|
// which this card used to show, is never written by anything; the Sidebar
|
|
38
38
|
// and Outlink still read it as free text.) null while it loads; a load that
|
|
39
39
|
// fails says so rather than showing "none picked" (TRAPS §7).
|
|
@@ -376,8 +376,8 @@ function ProfileInner() {
|
|
|
376
376
|
}}>
|
|
377
377
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
|
|
378
378
|
<h3 style={{ fontSize: 14, fontWeight: 700, margin: 0 }}>Your Sectors</h3>
|
|
379
|
-
<Link href="/
|
|
380
|
-
{sectorFocus?.sectors?.length ? 'Change' : sectorFocus && !sectorFocus.failed ? 'Pick
|
|
379
|
+
<Link href="/scores#sector" style={{ fontSize: 11, color: '#3498DB', textDecoration: 'none', fontWeight: 600 }}>
|
|
380
|
+
{sectorFocus?.sectors?.length ? 'Change' : sectorFocus && !sectorFocus.failed ? 'Pick on Scores' : 'Scores'} →
|
|
381
381
|
</Link>
|
|
382
382
|
</div>
|
|
383
383
|
{!sectorFocus ? (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useEffect, useState } from 'react';
|
|
3
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
4
4
|
import { loadNetwork } from '../../lib/network';
|
|
5
5
|
import { IS_DEMO } from '../../lib/demo';
|
|
6
6
|
import OutlinkQuest from '../components/OutlinkQuest';
|
|
@@ -8,6 +8,9 @@ import OnboardingGate from '../components/OnboardingGate';
|
|
|
8
8
|
import { useUser } from '../components/UserProvider';
|
|
9
9
|
import { rowCompanyScore, TOP_COMPANY } from '../../lib/scoring';
|
|
10
10
|
import Link from 'next/link';
|
|
11
|
+
import useRequests from '../components/useRequests';
|
|
12
|
+
import { hasRequest, markRequested, undoRequest } from '../../lib/requests-client';
|
|
13
|
+
import { keyFor } from '../../lib/separation';
|
|
11
14
|
|
|
12
15
|
const TIER_COLORS = { S: '#FFD700', A: '#9B59B6', B: '#3498DB', C: '#95A5A6', D: '#BDC3C7' };
|
|
13
16
|
|
|
@@ -38,8 +41,12 @@ function QueueInner() {
|
|
|
38
41
|
const [loading, setLoading] = useState(true);
|
|
39
42
|
const [filter, setFilter] = useState('all');
|
|
40
43
|
const [selected, setSelected] = useState(new Set());
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
// Requests out come from the one list every view shares (lib/requests-client.js),
|
|
45
|
+
// per person, so a request sent on the map shows here and one sent here shows
|
|
46
|
+
// there. What this page loads is only the rows to draw them with.
|
|
47
|
+
const requests = useRequests();
|
|
48
|
+
const [serverPending, setServerPending] = useState([]);
|
|
49
|
+
const [bridgeById, setBridgeById] = useState({});
|
|
43
50
|
// Circles is the game (lib/quest.js); the list and Pending are still here.
|
|
44
51
|
const [view, setView] = useState('quest'); // quest | recs | pending
|
|
45
52
|
const [added, setAdded] = useState([]);
|
|
@@ -80,13 +87,8 @@ function QueueInner() {
|
|
|
80
87
|
const bridgeById = {};
|
|
81
88
|
d1.forEach(c => { bridgeById[c.id] = c; });
|
|
82
89
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
setSentIds(sentSet);
|
|
86
|
-
setPendingList((pendingRes.pending || []).map(p => ({
|
|
87
|
-
...p,
|
|
88
|
-
bridge: bridgeById[p.source_connection_id] || null,
|
|
89
|
-
})));
|
|
90
|
+
setServerPending(pendingRes.pending || []);
|
|
91
|
+
setBridgeById(bridgeById);
|
|
90
92
|
|
|
91
93
|
const recommendations = d2
|
|
92
94
|
.filter(c => (c.tier === 'S' || c.tier === 'A' || c.tier === 'B') && !d1Urls.has(c.profile_url))
|
|
@@ -104,6 +106,24 @@ function QueueInner() {
|
|
|
104
106
|
load();
|
|
105
107
|
}, [userId]);
|
|
106
108
|
|
|
109
|
+
// Every row of anyone with a request out (a person's copies all count), and
|
|
110
|
+
// the people themselves, once each, for the Pending tab.
|
|
111
|
+
const sentIds = useMemo(
|
|
112
|
+
() => new Set([...serverPending, ...recs].filter((r) => hasRequest(r, requests)).map((r) => r.id)),
|
|
113
|
+
[serverPending, recs, requests],
|
|
114
|
+
);
|
|
115
|
+
const pendingList = useMemo(() => {
|
|
116
|
+
const seen = new Set();
|
|
117
|
+
const out = [];
|
|
118
|
+
for (const r of [...serverPending, ...recs]) {
|
|
119
|
+
const key = keyFor(r);
|
|
120
|
+
if (seen.has(key) || !hasRequest(r, requests)) continue;
|
|
121
|
+
seen.add(key);
|
|
122
|
+
out.push({ ...r, bridge: bridgeById[r.source_connection_id] || r.bridge || null });
|
|
123
|
+
}
|
|
124
|
+
return out;
|
|
125
|
+
}, [serverPending, recs, requests, bridgeById]);
|
|
126
|
+
|
|
107
127
|
// Demo builds: this page is excluded from the public demo
|
|
108
128
|
if (IS_DEMO) {
|
|
109
129
|
return (
|
|
@@ -303,22 +323,8 @@ function QueueInner() {
|
|
|
303
323
|
sentIds={sentIds}
|
|
304
324
|
added={added}
|
|
305
325
|
mappedIds={mappedIds}
|
|
306
|
-
onSend={
|
|
307
|
-
|
|
308
|
-
await fetch('/api/outreach', { method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
309
|
-
body: JSON.stringify({ action: 'mark-sent', connectionId: r.id, profileUrl: r.profile_url, userId }) });
|
|
310
|
-
setSentIds(prev => new Set([...prev, r.id]));
|
|
311
|
-
setPendingList(prev => (prev.some(x => x.id === r.id) ? prev : [...prev, r]));
|
|
312
|
-
} catch {}
|
|
313
|
-
}}
|
|
314
|
-
onUndo={async (r) => {
|
|
315
|
-
try {
|
|
316
|
-
await fetch('/api/outreach', { method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
317
|
-
body: JSON.stringify({ action: 'undo', connectionId: r.id, userId }) });
|
|
318
|
-
setSentIds(prev => { const next = new Set(prev); next.delete(r.id); return next; });
|
|
319
|
-
setPendingList(prev => prev.filter(x => x.id !== r.id));
|
|
320
|
-
} catch {}
|
|
321
|
-
}}
|
|
326
|
+
onSend={(r) => markRequested(r, { bridgeId: r.source_connection_id }).catch(() => {})}
|
|
327
|
+
onUndo={(r) => undoRequest(r).catch(() => {})}
|
|
322
328
|
/>
|
|
323
329
|
</div>
|
|
324
330
|
)}
|
|
@@ -391,14 +397,7 @@ function QueueInner() {
|
|
|
391
397
|
style={{ padding: '4px 8px', borderRadius: 4, fontSize: 9, fontWeight: 700, background: '#0077B5', color: '#fff', textDecoration: 'none' }}>
|
|
392
398
|
View
|
|
393
399
|
</a>
|
|
394
|
-
<button onClick={
|
|
395
|
-
await fetch('/api/outreach', {
|
|
396
|
-
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
397
|
-
body: JSON.stringify({ action: 'undo', connectionId: p.id }),
|
|
398
|
-
});
|
|
399
|
-
setPendingList(prev => prev.filter(x => x.id !== p.id));
|
|
400
|
-
setSentIds(prev => { const next = new Set(prev); next.delete(p.id); return next; });
|
|
401
|
-
}} style={{
|
|
400
|
+
<button onClick={() => { undoRequest(p).catch(() => {}); }} style={{
|
|
402
401
|
padding: '4px 8px', borderRadius: 4, fontSize: 9, fontWeight: 600,
|
|
403
402
|
background: 'rgba(255,255,255,0.06)', color: '#666', border: 'none', cursor: 'pointer',
|
|
404
403
|
}}>Undo</button>
|
|
@@ -585,13 +584,9 @@ function QueueInner() {
|
|
|
585
584
|
<span style={{ padding: '3px 6px', borderRadius: 3, fontSize: 8, fontWeight: 700, background: 'rgba(255,107,53,0.15)', color: '#FF6B35', flexShrink: 0 }}>Sent</span>
|
|
586
585
|
) : (
|
|
587
586
|
<a href={r.profile_url} target="_blank" rel="noopener noreferrer"
|
|
588
|
-
onClick={
|
|
587
|
+
onClick={(e) => {
|
|
589
588
|
e.stopPropagation();
|
|
590
|
-
|
|
591
|
-
await fetch('/api/outreach', { method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
592
|
-
body: JSON.stringify({ action: 'mark-sent', connectionId: r.id, profileUrl: r.profile_url }) });
|
|
593
|
-
setSentIds(prev => new Set([...prev, r.id]));
|
|
594
|
-
} catch {}
|
|
589
|
+
markRequested(r, { bridgeId: r.source_connection_id }).catch(() => {});
|
|
595
590
|
}}
|
|
596
591
|
style={{ padding: '3px 6px', borderRadius: 3, fontSize: 8, fontWeight: 700, background: '#0077B5', color: '#fff', textDecoration: 'none', flexShrink: 0 }}>Add</a>
|
|
597
592
|
)}
|
|
@@ -659,17 +654,10 @@ function QueueInner() {
|
|
|
659
654
|
}}>⏳ Sent</span>
|
|
660
655
|
) : (
|
|
661
656
|
<a href={r.profile_url} target="_blank" rel="noopener noreferrer"
|
|
662
|
-
onClick={
|
|
657
|
+
onClick={(e) => {
|
|
663
658
|
e.stopPropagation();
|
|
664
|
-
//
|
|
665
|
-
|
|
666
|
-
await fetch('/api/outreach', {
|
|
667
|
-
method: 'POST',
|
|
668
|
-
headers: { 'Content-Type': 'application/json' },
|
|
669
|
-
body: JSON.stringify({ action: 'mark-sent', connectionId: r.id, profileUrl: r.profile_url }),
|
|
670
|
-
});
|
|
671
|
-
setSentIds(prev => new Set([...prev, r.id]));
|
|
672
|
-
} catch {}
|
|
659
|
+
// Opens LinkedIn, and marks the request sent everywhere.
|
|
660
|
+
markRequested(r, { bridgeId: r.source_connection_id }).catch(() => {});
|
|
673
661
|
}}
|
|
674
662
|
style={{
|
|
675
663
|
padding: '4px 8px', borderRadius: 4, fontSize: 9, fontWeight: 700,
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
// Scores: how a power score is worked out, and everything you can change about
|
|
4
|
+
// it, in one place (Blake, 2026-09-28: "maybe this should be its own tab").
|
|
5
|
+
// Your field (the sector focus), how tiers are graded, and every company's
|
|
6
|
+
// score. The first two used to live in Settings and the company scores in
|
|
7
|
+
// Paths → Scores; the old links forward here (app/settings/page.js,
|
|
8
|
+
// app/paths/page.js).
|
|
9
|
+
|
|
10
|
+
import { useState } from 'react';
|
|
11
|
+
import Link from 'next/link';
|
|
12
|
+
import OnboardingGate from '../components/OnboardingGate';
|
|
13
|
+
import SectorSection from '../components/settings/SectorSection';
|
|
14
|
+
import TierSection from '../components/settings/TierSection';
|
|
15
|
+
import CompanyScores from '../components/CompanyScores';
|
|
16
|
+
import { Body, LINE, FONT } from '../components/ui';
|
|
17
|
+
import { IS_DEMO } from '../../lib/demo';
|
|
18
|
+
|
|
19
|
+
export default function ScoresPage() {
|
|
20
|
+
return <OnboardingGate><ScoresInner /></OnboardingGate>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const jump = { color: '#3498DB', textDecoration: 'none', fontWeight: 600 };
|
|
24
|
+
|
|
25
|
+
function ScoresInner() {
|
|
26
|
+
// Saving your sector or tiers rescores everyone; the company list below reads
|
|
27
|
+
// its scores again when this changes.
|
|
28
|
+
const [saves, setSaves] = useState(0);
|
|
29
|
+
const saved = () => setSaves((n) => n + 1);
|
|
30
|
+
if (IS_DEMO) {
|
|
31
|
+
return (
|
|
32
|
+
<div style={{
|
|
33
|
+
minHeight: '100vh', background: '#0a0a1a', color: 'rgba(255,255,255,0.7)',
|
|
34
|
+
display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
|
|
35
|
+
gap: 12, textAlign: 'center', padding: 24, fontFamily: FONT,
|
|
36
|
+
}}>
|
|
37
|
+
<h2 style={{ margin: 0, fontSize: 20, fontWeight: 700, color: '#fff' }}>Not part of the demo</h2>
|
|
38
|
+
<p style={{ margin: 0, fontSize: 13 }}>The public demo includes the Network Circle and Degrees views only.</p>
|
|
39
|
+
<Link href="/" style={{ fontSize: 12, color: 'rgba(255,255,255,0.5)', textDecoration: 'none' }}>← Back to the network</Link>
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div style={{ minHeight: '100vh', background: '#0a0a1a', color: '#fff', fontFamily: FONT }}>
|
|
46
|
+
<header style={{ padding: '16px 24px', borderBottom: LINE, display: 'flex', alignItems: 'center', gap: 16 }}>
|
|
47
|
+
<Link href="/" style={{
|
|
48
|
+
display: 'flex', alignItems: 'center', gap: 6, color: '#888', textDecoration: 'none',
|
|
49
|
+
fontSize: 13, fontWeight: 600, padding: '6px 14px', borderRadius: 6,
|
|
50
|
+
background: 'rgba(255,255,255,0.06)', border: LINE,
|
|
51
|
+
}}>← Back to Map</Link>
|
|
52
|
+
<h1 style={{
|
|
53
|
+
fontSize: 22, fontWeight: 700, margin: 0,
|
|
54
|
+
background: 'linear-gradient(135deg, #FFD700, #9B59B6, #3498DB)',
|
|
55
|
+
WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent',
|
|
56
|
+
}}>Scores</h1>
|
|
57
|
+
</header>
|
|
58
|
+
<main style={{ maxWidth: 980, margin: '0 auto', padding: '8px 24px 64px' }}>
|
|
59
|
+
<Body style={{ marginTop: 16 }}>
|
|
60
|
+
How someone’s power score is worked out, and the three things you can change about it:{' '}
|
|
61
|
+
<a href="#sector" style={jump}>your field</a>, <a href="#tiers" style={jump}>how tiers are graded</a> and{' '}
|
|
62
|
+
<a href="#companies" style={jump}>any company’s score</a>. A change here rescores everyone.
|
|
63
|
+
</Body>
|
|
64
|
+
<SectorSection onSaved={saved} />
|
|
65
|
+
<TierSection onSaved={saved} />
|
|
66
|
+
<div id="companies" style={{ marginTop: 28 }}>
|
|
67
|
+
<CompanyScores version={saves} />
|
|
68
|
+
</div>
|
|
69
|
+
</main>
|
|
70
|
+
</div>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import { useEffect, useState } from 'react';
|
|
4
4
|
import Link from 'next/link';
|
|
5
|
+
import { useRouter } from 'next/navigation';
|
|
5
6
|
import OnboardingGate from '../components/OnboardingGate';
|
|
6
7
|
import UpdatePanel from '../components/UpdatePanel';
|
|
7
|
-
import SectorSection from '../components/settings/SectorSection';
|
|
8
8
|
import DataSection from '../components/settings/DataSection';
|
|
9
9
|
import { Section, Body, Mono, LINE, FONT } from '../components/ui';
|
|
10
10
|
import { IS_DEMO } from '../../lib/demo';
|
|
@@ -28,6 +28,13 @@ const KIND_LABEL = {
|
|
|
28
28
|
function SettingsInner() {
|
|
29
29
|
const [info, setInfo] = useState(null);
|
|
30
30
|
const [error, setError] = useState(null);
|
|
31
|
+
const router = useRouter();
|
|
32
|
+
// Your field and tiers moved to the Scores tab (app/scores): old links to
|
|
33
|
+
// /settings#sector and /settings#tiers go there.
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
const at = window.location.hash;
|
|
36
|
+
if (at === '#sector' || at === '#tiers') router.replace(`/scores${at}`);
|
|
37
|
+
}, [router]);
|
|
31
38
|
|
|
32
39
|
useEffect(() => {
|
|
33
40
|
fetch('/api/settings')
|
|
@@ -71,8 +78,13 @@ function SettingsInner() {
|
|
|
71
78
|
{error && <Body style={{ color: '#ff7676', marginTop: 16 }}>{error}</Body>}
|
|
72
79
|
|
|
73
80
|
<UpdatePanel />
|
|
74
|
-
<
|
|
75
|
-
|
|
81
|
+
<Section id="scoring" title="Your field and tiers">
|
|
82
|
+
<Body>
|
|
83
|
+
They’re on the <Link href="/scores" style={{ color: '#3498DB' }}>Scores</Link> tab now, beside every
|
|
84
|
+
company’s score: <Link href="/scores#sector" style={{ color: '#3498DB' }}>your field</Link> and{' '}
|
|
85
|
+
<Link href="/scores#tiers" style={{ color: '#3498DB' }}>how tiers are graded</Link>.
|
|
86
|
+
</Body>
|
|
87
|
+
</Section>
|
|
76
88
|
<DataSection />
|
|
77
89
|
|
|
78
90
|
<Section id="about" title="About this copy">
|
|
@@ -60,6 +60,7 @@ CREATE TABLE IF NOT EXISTS linkedin_connections (
|
|
|
60
60
|
unlocked_from_bridge_id TEXT,
|
|
61
61
|
unlocked_from_name TEXT,
|
|
62
62
|
outreach_status TEXT,
|
|
63
|
+
mutual_count INTEGER, -- LinkedIn's count of mutual connections (2nd degree), when a scan read one
|
|
63
64
|
scanned_company TEXT,
|
|
64
65
|
score_why TEXT,
|
|
65
66
|
user_id TEXT,
|