six-degrees 0.4.9 → 0.4.11
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 +4 -4
- package/.next/standalone/.next/routes-manifest.json +6 -0
- 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 +13 -13
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +13 -13
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- 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.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/social/crm/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/social/crm/route/build-manifest.json +12 -0
- package/.next/standalone/.next/server/app/api/social/crm/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/social/crm/route.js +10 -0
- package/.next/standalone/.next/server/app/api/social/crm/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/social/crm/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/social/crm/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/social/messages/route.js +4 -3
- package/.next/standalone/.next/server/app/api/social/messages/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/social/route.js +4 -3
- package/.next/standalone/.next/server/app/api/social/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 +15 -15
- package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/import.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/import.segments/import/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- 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 +15 -15
- package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/launch.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/launch.segments/launch/__PAGE__.segment.rsc +14 -14
- 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 +15 -15
- package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/paths.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/paths.segments/paths/__PAGE__.segment.rsc +14 -14
- 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 +15 -15
- package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/profile.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/profile.segments/profile/__PAGE__.segment.rsc +14 -14
- 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 +15 -15
- package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/queue.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/queue.segments/queue/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/scores/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/scores/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/scores.html +1 -1
- package/.next/standalone/.next/server/app/scores.rsc +15 -15
- package/.next/standalone/.next/server/app/scores.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/scores.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/scores.segments/scores/__PAGE__.segment.rsc +14 -14
- 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 +15 -15
- package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +14 -14
- 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 +15 -15
- package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/social/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/social/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/social.html +1 -1
- package/.next/standalone/.next/server/app/social.rsc +15 -15
- package/.next/standalone/.next/server/app/social.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/social.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/social.segments/social/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app-paths-manifest.json +1 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__06mi9k2._.js → [root-of-the-server]__05_3-22._.js} +7 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t3v1a1._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tir0vc._.js +8 -0
- package/.next/standalone/.next/server/chunks/_0ea9qwy._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1_fynia._.js +4 -4
- package/.next/standalone/.next/server/chunks/_1itd1o_._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1oqfuh8._.js +3 -0
- package/.next/standalone/.next/server/chunks/_1xh07bp._.js +1 -1
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_social_crm_route_actions_0d1aflv.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_db-client_15le7cw.js +7 -7
- package/.next/standalone/.next/server/chunks/lib_linkedin-export_12imqxg.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_05gt5ya.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0-85h6g._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_08cfj2b._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0c_y09g._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_paths_page_1ol90m7.js +1 -1
- 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 +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_scores_page_09wepvv.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_settings_page_1f8mjj_.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_setup_page_1-282zx.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_social_page_0h7zxda.js +2 -1
- package/.next/standalone/.next/server/chunks/ssr/lib_galaxy-lab_108_lu-.js +3 -0
- 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/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- 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/0a5iadnmt9u9k.js +1 -0
- package/.next/standalone/.next/static/chunks/15sjx07xhpn6p.js +1 -0
- package/.next/standalone/.next/static/chunks/{054zdthcnyd2h.js → 160wjb73ddwqd.js} +1 -1
- package/.next/standalone/.next/static/chunks/1a74dky22dxd6.js +1 -0
- package/.next/standalone/.next/static/chunks/{04bbi55urkrd6.js → 1c_n0973t07l0.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0bo1dxn5gwzpk.css → 1x_ysly42-teq.css} +1 -1
- package/.next/standalone/.next/static/chunks/{1_mohm2643nxp.js → 236f0jtp68j_h.js} +1 -1
- package/.next/standalone/.next/static/chunks/297e1z34yi--z.js +1 -0
- package/.next/standalone/.next/static/chunks/2_ak6qjxb6oa5.js +1 -0
- package/.next/standalone/.next/static/chunks/{38wwtni5e1ec1.js → 39hr8d-b2ibtw.js} +1 -1
- package/.next/standalone/.next/static/chunks/3ui4d-uqkqj5d.js +2 -0
- package/.next/{static/chunks/1z_rt4jteewqp.js → standalone/.next/static/chunks/3zw8bv7-mc4n6.js} +1 -1
- package/.next/standalone/CHANGELOG.md +57 -0
- package/.next/standalone/app/api/data/export/route.js +2 -1
- package/.next/standalone/app/api/scraper/route.js +5 -1
- package/.next/standalone/app/api/social/crm/route.js +37 -0
- package/.next/standalone/app/api/social/messages/route.js +44 -8
- package/.next/standalone/app/api/social/route.js +80 -22
- package/.next/standalone/app/components/GalaxyLab.js +4 -1
- package/.next/standalone/app/components/ScanStatusBar.js +97 -71
- package/.next/standalone/app/components/settings/DataSection.js +12 -3
- package/.next/standalone/app/globals.css +15 -0
- package/.next/standalone/app/paths/page.js +0 -2
- package/.next/standalone/app/profile/page.js +0 -2
- package/.next/standalone/app/queue/page.js +0 -2
- package/.next/standalone/app/scores/page.js +0 -2
- package/.next/standalone/app/settings/page.js +0 -2
- package/.next/standalone/app/setup/page.js +0 -2
- package/.next/standalone/app/social/Crm.js +683 -0
- package/.next/standalone/app/social/Thread.js +90 -0
- package/.next/standalone/app/social/page.js +71 -62
- package/.next/standalone/lib/data-export.js +10 -4
- package/.next/standalone/lib/data-folder.js +9 -0
- package/.next/standalone/lib/data-import.js +13 -3
- package/.next/standalone/lib/island.js +36 -0
- package/.next/standalone/lib/linkedin-export.js +267 -46
- package/.next/standalone/lib/social-crm.js +415 -0
- package/.next/standalone/lib/social-store.js +13 -6
- package/.next/standalone/package-lock.json +2 -2
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/scripts/scrape.py +126 -22
- package/.next/static/chunks/0a5iadnmt9u9k.js +1 -0
- package/.next/static/chunks/15sjx07xhpn6p.js +1 -0
- package/.next/static/chunks/{054zdthcnyd2h.js → 160wjb73ddwqd.js} +1 -1
- package/.next/static/chunks/1a74dky22dxd6.js +1 -0
- package/.next/static/chunks/{04bbi55urkrd6.js → 1c_n0973t07l0.js} +1 -1
- package/.next/static/chunks/{0bo1dxn5gwzpk.css → 1x_ysly42-teq.css} +1 -1
- package/.next/static/chunks/{1_mohm2643nxp.js → 236f0jtp68j_h.js} +1 -1
- package/.next/static/chunks/297e1z34yi--z.js +1 -0
- package/.next/static/chunks/2_ak6qjxb6oa5.js +1 -0
- package/.next/static/chunks/{38wwtni5e1ec1.js → 39hr8d-b2ibtw.js} +1 -1
- package/.next/static/chunks/3ui4d-uqkqj5d.js +2 -0
- package/.next/{standalone/.next/static/chunks/1z_rt4jteewqp.js → static/chunks/3zw8bv7-mc4n6.js} +1 -1
- package/CHANGELOG.md +57 -0
- package/lib/data-export.js +10 -4
- package/lib/data-folder.js +9 -0
- package/lib/data-import.js +13 -3
- package/lib/island.js +36 -0
- package/lib/linkedin-export.js +267 -46
- package/lib/social-crm.js +415 -0
- package/lib/social-store.js +13 -6
- package/package.json +1 -1
- package/scripts/scrape.py +126 -22
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__08f5awg._.js +0 -8
- package/.next/standalone/.next/server/chunks/lib_18cr1gi._.js +0 -8
- package/.next/standalone/.next/server/chunks/ssr/_0ezj4e0._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1errbuf._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/app_components_ui_0pdmz2z.js +0 -3
- package/.next/standalone/.next/static/chunks/2bftn9gubwf0w.js +0 -1
- package/.next/standalone/.next/static/chunks/2pw6_osz1n_te.js +0 -1
- package/.next/standalone/.next/static/chunks/39csdcx7yv227.js +0 -1
- package/.next/standalone/.next/static/chunks/3yzlf70j5t0-o.js +0 -1
- package/.next/standalone/.next/static/chunks/3z-swu5pet507.js +0 -1
- package/.next/standalone/app/social/Conversations.js +0 -246
- package/.next/static/chunks/2bftn9gubwf0w.js +0 -1
- package/.next/static/chunks/2pw6_osz1n_te.js +0 -1
- package/.next/static/chunks/39csdcx7yv227.js +0 -1
- package/.next/static/chunks/3yzlf70j5t0-o.js +0 -1
- package/.next/static/chunks/3z-swu5pet507.js +0 -1
- /package/.next/standalone/.next/static/{yPlsfKhdS8MMtyXF7twSZ → jqE2D3zWqSGz5su948Azf}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{yPlsfKhdS8MMtyXF7twSZ → jqE2D3zWqSGz5su948Azf}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{yPlsfKhdS8MMtyXF7twSZ → jqE2D3zWqSGz5su948Azf}/_ssgManifest.js +0 -0
- /package/.next/static/{yPlsfKhdS8MMtyXF7twSZ → jqE2D3zWqSGz5su948Azf}/_buildManifest.js +0 -0
- /package/.next/static/{yPlsfKhdS8MMtyXF7twSZ → jqE2D3zWqSGz5su948Azf}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{yPlsfKhdS8MMtyXF7twSZ → jqE2D3zWqSGz5su948Azf}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,60451,e=>{"use strict";var t=e.i(43476),n=e.i(71645),o=e.i(22016),s=e.i(2776),r=e.i(15812),a=e.i(19821),i=e.i(84278),l=e.i(39160),c=e.i(7214),d=e.i(40996),p=e.i(8819),u=e.i(64745);let h=Object.freeze([{id:"new",label:"New"},{id:"contacted",label:"Contacted"},{id:"replied",label:"Replied"},{id:"meeting",label:"Meeting"},{id:"won",label:"Won/Partner"},{id:"not-now",label:"Not now"}]);h.map(e=>e.id);let g=e=>h.find(t=>t.id===e)?.label||"",f=e=>"string"==typeof e&&e.length>0&&e.length<300;function m(){return{version:1,settings:{awaitDays:7},people:{}}}function y(e=new Date){let t=e=>String(e).padStart(2,"0");return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}`}let x=/^https:\/\/(www\.)?linkedin\.com\/in\/[^/?#\s]+$/,w={S:0,A:1,B:2,C:3,D:4},b=(e,t)=>(e.degree??9)<(t.degree??9)||(e.degree??9)===(t.degree??9)&&(w[e.tier]??9)<(w[t.tier]??9),v=e=>"sponsored"===e.kind;function j(e,t,n=7){let o=[];for(let s of e){if(v(s)||!1!==s.lastFromThem||!s.last)continue;let e=Math.floor((t-s.last)/864e5);e>=n&&o.push({contact:s,waited:e})}return o.sort((e,t)=>e.waited-t.waited)}function k(e,t,n=null){let o=String(t||"").trim().toLowerCase();return!o||[e.name,e.row?.company,e.row?.role,e.row?.headline,...e.crm?.tags||[],e.crm?.notes].filter(Boolean).join("\n").toLowerCase().includes(o)||!!n&&e.conversations.some(e=>n.has(e.id))}function S(e){let t=null==e?"":String(e);return/^[=+\-@\t\r]/.test(t)&&(t=`'${t}`),/[",\r\n]/.test(t)?`"${t.replace(/"/g,'""')}"`:t}let T=e=>e?new Date(e).toISOString().slice(0,10):"",C=["Name","Company","Profile","Connection","Stage","Tags","Last contact","Who wrote last","Next follow-up","Notes"];function z({id:e,keep:o,group:s,token:r}){let[a,i]=(0,n.useState)(null),[l,c]=(0,n.useState)(null),d=(0,n.useRef)(null),u=(0,n.useRef)(null);async function h(){let t=d.current,n=await fetch(`/api/social/messages?id=${encodeURIComponent(e)}&before=${a.start}&limit=200`).then(e=>e.json()).catch(()=>null);n&&!n.error&&(u.current=t?t.scrollHeight-t.scrollTop:null,i({...a,start:n.start,messages:[...n.messages,...a.messages]}))}(0,n.useEffect)(()=>{if(!o)return;let t=!0;return fetch(`/api/social/messages?id=${encodeURIComponent(e)}&limit=100`).then(e=>e.json()).then(e=>{t&&(e.error?c(e.error):(u.current="bottom",i(e)))}).catch(()=>{t&&c("It couldn’t be read.")}),()=>{t=!1}},[e,o,r]),(0,n.useLayoutEffect)(()=>{let e=d.current;e&&u.current&&("bottom"===u.current?e.scrollTop=e.scrollHeight:e.scrollTop=e.scrollHeight-u.current,u.current=null)},[a]);let g={padding:"10px 14px 14px",fontSize:12.5,color:"#8b9a9a"};return o?l?(0,t.jsx)("div",{style:{...g,color:"#ff9b9b"},children:l}):a?a.total?(0,t.jsxs)("div",{ref:d,style:{maxHeight:440,overflowY:"auto",padding:"8px 14px 12px",background:"rgba(0,0,0,0.2)"},children:[a.start>0&&(0,t.jsx)("div",{style:{textAlign:"center",margin:"4px 0 10px"},children:(0,t.jsxs)("button",{onClick:h,style:{background:"rgba(255,255,255,0.06)",border:p.LINE,borderRadius:6,color:"#cfe6f7",cursor:"pointer",fontSize:12,padding:"4px 12px"},children:["Show earlier (",a.start.toLocaleString()," more)"]})}),a.messages.map((e,n)=>{let o;return(0,t.jsx)("div",{style:{display:"flex",justifyContent:e.fromMe?"flex-end":"flex-start",margin:"6px 0"},children:(0,t.jsxs)("div",{style:{maxWidth:"72%"},children:[(0,t.jsx)("div",{style:{padding:"7px 11px",borderRadius:12,fontSize:13,lineHeight:1.45,whiteSpace:"pre-wrap",overflowWrap:"anywhere",background:e.fromMe?"rgba(52,152,219,0.35)":"rgba(255,255,255,0.08)",color:"#eef",borderBottomRightRadius:e.fromMe?4:12,borderBottomLeftRadius:e.fromMe?12:4},children:e.text||(0,t.jsx)("i",{style:{color:"#8b9a9a"},children:"(no words: an attachment or a reaction)"})}),(0,t.jsxs)("div",{style:{fontSize:10.5,color:"#778",marginTop:2,textAlign:e.fromMe?"right":"left"},children:[e.fromMe?"You":s?"Someone in the group":"Them"," · ",(o=e.t)?new Date(o).toLocaleString(void 0,{day:"numeric",month:"short",year:"numeric",hour:"numeric",minute:"2-digit"}):""]})]})},a.start+n)})]}):(0,t.jsx)("div",{style:g,children:"No messages are kept for this conversation yet. Choose your export folder again, or sync your messages, to bring them in."}):(0,t.jsx)("div",{style:g,children:"Opening…"}):(0,t.jsxs)("div",{style:g,children:["Turn on ",(0,t.jsx)("b",{children:"Keep my messages"})," to read them here."]})}let I={S:"#FFD700",A:"#9B59B6",B:"#3498DB",C:"#95A5A6",D:"#BDC3C7"},D={new:"#8b9a9a",contacted:"#3498DB",replied:"#00d4aa",meeting:"#ff9f43",won:"#FFD700","not-now":"#667"},$=e=>e?new Date(e).toLocaleDateString(void 0,{day:"numeric",month:"short",year:"numeric"}):"",F=e=>e?new Date(`${e}T12:00:00`).toLocaleDateString(void 0,{day:"numeric",month:"short",year:"numeric"}):"",L=e=>/^https:\/\/(www\.)?linkedin\.com\//.test(String(e||""))?e:null,N=(e,t,n=`${t}s`)=>`${e.toLocaleString()} ${1===e?t:n}`,O=[["inbox","Inbox"],["awaiting","Awaiting reply"],["due","Follow-ups due"],["pipeline","Pipeline"],["sent","Sent"],["received","Received"],["all","All"]],R=(e,t="#dfe8e8")=>({fontSize:10.5,padding:"1px 6px",borderRadius:4,background:e,color:t,whiteSpace:"nowrap"}),E={background:"rgba(255,255,255,0.06)",border:p.LINE,borderRadius:6,color:"#cfe6f7",cursor:"pointer",fontSize:12,padding:"4px 10px"},M={padding:"6px 10px",borderRadius:6,border:p.LINE,background:"rgba(0,0,0,0.3)",color:"#fff",fontSize:13};function B({net:e,asOf:o,keep:s,onKeep:r,switching:a,token:l,crmToken:d}){let[u,w]=(0,n.useState)(null),[z,I]=(0,n.useState)(null),[D,L]=(0,n.useState)("inbox"),[R,U]=(0,n.useState)(""),[A,Y]=(0,n.useState)(null),[_,K]=(0,n.useState)(null),[G,V]=(0,n.useState)(100),[Q,X]=(0,n.useState)(null),Z=(0,n.useRef)(null);(0,n.useEffect)(()=>{let e=!0;return fetch("/api/social/messages").then(e=>e.json()).then(t=>{e&&w(t)}).catch(()=>{e&&w({conversations:[],invitations:[],names:{},inviteNotes:{}})}),()=>{e=!1}},[l,s]),(0,n.useEffect)(()=>{let e=!0;return fetch("/api/social/crm").then(e=>e.json()).then(t=>{e&&I(t.crm||m())}).catch(()=>{e&&I(m())}),()=>{e=!1}},[d]),(0,n.useEffect)(()=>{let e=R.trim();if(!s||e.length<2)return;let t=!0,n=setTimeout(()=>{fetch(`/api/social/messages?q=${encodeURIComponent(e)}`).then(e=>e.json()).then(n=>{t&&Y({q:e,ids:new Set(n.ids||[])})}).catch(()=>{})},250);return()=>{t=!1,clearTimeout(n)}},[R,s,l]);let ee=_?.type==="person"?_.key:null,{contacts:et,groups:en}=(0,n.useMemo)(()=>(function({conversations:e=[],invitations:t=[],network:n={},crm:o=m(),names:s={},also:r=[]}={}){let a=n.degree1||[],l=n.degree2||[],d=[...a,...l,...n.degree3||[]],p=new Map,u=new Map;for(let e of d){let t=(0,c.keyFor)(e),n=p.get(t);(!n||b(e,n))&&p.set(t,e)}for(let[e,t]of p){let n=(0,i.nameKey)(t.name);n&&u.set(n,u.has(n)&&u.get(n)!==e?null:e)}let h=new Set(a.map(c.keyFor)),g=(0,c.routeIndex)(l),y=new Map(a.map(e=>[e.id,e])),w=e=>e.startsWith("name:")&&u.get(e.slice(5))||e,v=new Map,j=e=>{var t,n,r;let a=w(e),i=v.get(a);if(i)return i;let l=p.get(a)||null;return i={key:a,name:(t=a,n=l,r=s,n?.name?n.name:r[t]?r[t]:t.startsWith("name:")?t.slice(5).replace(/\b\w/g,e=>e.toUpperCase()):String(t||"").replace(/\/+$/,"").split("/").pop()),row:l,connection:h.has(a),degree:l?.degree??null,profileUrl:x.test(a)?a:l?.profile_url&&x.test((0,c.keyFor)(l))?(0,c.keyFor)(l):null,introducers:l&&2===l.degree?[...new Set((0,c.routesFor)(l,g,y).map(e=>e.bridge?.name).filter(Boolean))]:[],conversations:[],groups:[],last:null,lastFromThem:null,unread:null,threadUrl:null,count:0,theyWrote:!1,kind:null,invitesIn:[],invitesOut:[],request:null,crm:o?.people?.[a]||null,lastContact:null},v.set(a,i),i},k=[];for(let t of e){if(!t||!Array.isArray(t.people))continue;if(t.group){k.push({...t,people:t.people.map(w)});continue}if(!t.people.length){k.push({...t,unknown:!0});continue}let e=j(t.people[0]);e.conversations.push(t),e.count+=t.count||0,(!0===t.lastFromThem||null!=t.count&&null!=t.mine&&t.count>t.mine)&&(e.theyWrote=!0),t.last&&(!e.last||t.last>=e.last)?(e.last=t.last,e.lastFromThem=t.lastFromThem,e.unread=t.unread,e.threadUrl=t.threadUrl||e.threadUrl):e.last||t.last||(e.threadUrl=t.threadUrl||e.threadUrl)}for(let e of v.values()){e.conversations.sort((e,t)=>(t.last||0)-(e.last||0));let t=new Set(e.conversations.map(e=>e.kind||null));e.kind=1===t.size?[...t][0]:null}for(let e of k)for(let t of e.people)v.get(t)?.groups.push(e.id);for(let e of t){if(!e?.key)continue;let t=j(e.key);!e.name||t.row||s[t.key]||(t.name=e.name),("in"===e.dir?t.invitesIn:t.invitesOut).push(e)}for(let e of d){if("sent"!==e.outreach_status&&"accepted"!==e.outreach_status&&"pending"!==e.unlock_status)continue;let t=j((0,c.keyFor)(e)),n=t.connection||"accepted"===e.outreach_status?"accepted":"pending";t.request&&"accepted"!==n||(t.request={status:n})}for(let e of Object.keys(o?.people||{}))j(e);for(let e of r)f(e)&&j(e);for(let e of v.values()){let t=[e.last,...e.invitesIn.map(e=>e.t),...e.invitesOut.map(e=>e.t)].filter(Boolean);e.lastContact=t.length?Math.max(...t):null}return{contacts:v,groups:k}})({conversations:u?.conversations||[],invitations:u?.invitations||[],network:e||{},crm:z||m(),names:u?.names||{},also:ee?[ee]:[]}),[u,e,z,ee]),eo=(0,n.useMemo)(()=>{let t=new Map;for(let n of[...e?.degree1||[],...e?.degree2||[]])t.has((0,c.keyFor)(n))||t.set((0,c.keyFor)(n),n);let n=u?.names||{};return e=>et.get(e)?.name||t.get(e)?.name||n[e]||null},[et,e,u]),es=z?.settings?.awaitDays||7,[er]=(0,n.useState)(()=>Date.now()),ea=o||er,ei=y(new Date(er)),el=(0,n.useMemo)(()=>[...et.values()],[et]),ec=(0,n.useMemo)(()=>{let e=(e,t)=>({type:"person",key:e.key,c:e,sub:t,t:e.lastContact||0}),t=e=>null==e.lastFromThem?"":e.lastFromThem?`They wrote ${$(e.last)}`:`You wrote ${$(e.last)}`,n=el.filter(e=>e.lastContact||e.crm||e.request).map(n=>e(n,t(n)||(n.invitesOut[0]?`You asked to connect ${$(n.invitesOut[0].t)}`:"")||(n.invitesIn[0]?`Asked to connect ${$(n.invitesIn[0].t)}`:"")||(n.request?`Tracked request \xb7 ${n.request.status}`:"")||(n.crm?.stage?g(n.crm.stage):"")));for(let e of en)n.push({type:"group",id:e.id,g:e,sub:e.last?`${e.lastFromThem?"Someone wrote":"You wrote"} ${$(e.last)}`:"",t:e.last||0});return n.sort((e,t)=>t.t-e.t),{inbox:[...el].filter(e=>!v(e)&&(!0===e.lastFromThem||e.unread>0)).sort((e,t)=>(t.unread>0)-(e.unread>0)||(t.last||0)-(e.last||0)).map(n=>e(n,n.unread>0?`${n.unread} unread \xb7 ${t(n)}`:t(n))),awaiting:j(el,ea,es).map(t=>e(t.contact,`You wrote ${$(t.contact.last)}, no reply for ${N(t.waited,"day")}`)),due:(function(e,t=y()){return[...e].filter(e=>e.crm?.followUp&&e.crm.followUp<=t).sort((e,t)=>e.crm.followUp.localeCompare(t.crm.followUp))})(el,ei).map(t=>e(t,t.crm.followUp===ei?"Follow up today":`Follow up was due ${F(t.crm.followUp)}`)),pipeline:function(e){let t=Object.fromEntries(h.map(e=>[e.id,[]]));for(let n of e)n.crm?.stage&&t[n.crm.stage].push(n);for(let e of Object.values(t))e.sort((e,t)=>(t.lastContact||0)-(e.lastContact||0));return t}(el),sent:(function(e,t,n=7){let o=[...e],s=new Map(j(o,t,n).map(e=>[e.contact.key,e.waited])),r=[];for(let e of o){let t=[];for(let n of e.invitesOut)t.push({type:"invite",id:n.id,t:n.t,status:e.connection?"accepted":"pending"});e.request&&t.push({type:"request",status:e.request.status}),s.has(e.key)&&t.push({type:"awaiting",t:e.last,waited:s.get(e.key)}),t.length&&r.push({contact:e,items:t,t:Math.max(0,...t.map(e=>e.t||0))})}return r.sort((e,t)=>t.t-e.t)})(el,ea,es).map(t=>e(t.contact,t.items.map(e=>"invite"===e.type?`Request ${$(e.t)} \xb7 ${e.status}`:"request"===e.type?`Tracked request \xb7 ${e.status}`:`No reply for ${N(e.waited,"day")}`).join(" · "))),received:(function(e){let t=[];for(let n of e)!n.connection&&n.invitesIn.length&&t.push({contact:n,t:Math.max(0,...n.invitesIn.map(e=>e.t||0))});return t.sort((e,t)=>t.t-e.t)})(el).map(t=>e(t.contact,`Asked to connect ${$(t.t)}`)),all:n}},[el,en,ea,es,ei]),ed=s&&A?.q===R.trim()?A.ids:null,ep=R.trim().toLowerCase(),eu=(0,n.useMemo)(()=>{let t="pipeline"===D?[]:ec[D];if(!ep)return t;let n=t.filter(e=>"person"===e.type?k(e.c,ep,ed):String(e.g.title||"").toLowerCase().includes(ep)||e.g.people.some(e=>String(eo(e)||"").toLowerCase().includes(ep))||ed?.has(e.g.id));if("all"===D&&ep.length>=2&&e){let t=new Set(n.map(e=>e.key)),o=new Set;for(let s of[...e.degree1||[],...e.degree2||[]]){let e=(0,c.keyFor)(s);if(!(t.has(e)||o.has(e))&&[s.name,s.company,s.role,s.headline].some(e=>String(e||"").toLowerCase().includes(ep))&&(o.add(e),n.push({type:"person",key:e,c:null,row:s,sub:"Nothing on file yet",t:0}),o.size>=50))break}}return n},[ec,D,ep,ed,e,eo]),eh=(0,n.useMemo)(()=>{if("pipeline"!==D)return null;let e={};for(let[t,n]of Object.entries(ec.pipeline))e[t]=ep?n.filter(e=>k(e,ep,ed)):n;return e},[ec,D,ep,ed]),eg={inbox:ec.inbox.length,awaiting:ec.awaiting.length,due:ec.due.length,pipeline:Object.values(ec.pipeline).reduce((e,t)=>e+t.length,0),sent:ec.sent.length,received:ec.received.length,all:ec.all.length};function ef(e){K(e),window.matchMedia?.("(max-width: 760px)").matches&&setTimeout(()=>Z.current?.scrollIntoView({behavior:"smooth",block:"start"}),50)}async function em(e,t){let n=await fetch("/api/social/crm",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:e,set:t})}),o=await n.json().catch(()=>({}));if(!n.ok)throw Error(o.error||"That couldn’t be saved.");I(t=>{let n={...t||m(),people:{...t?.people||{}}};return o.entry?n.people[e]=o.entry:delete n.people[e],n})}async function ey(e){let t=await fetch("/api/social/crm",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({settings:{awaitDays:e}})}),n=await t.json().catch(()=>({}));t.ok&&I(e=>({...e||m(),settings:n.settings}))}async function ex(){window.confirm("Delete your CRM: every stage, tag, note and follow-up date you added? This can’t be undone.")&&(await fetch("/api/social/crm",{method:"DELETE"}),I(m()),X("Your CRM notes are deleted."))}let ew=!u||!z||!e,eb={padding:"12px 14px",borderRadius:8,border:p.LINE,background:"rgba(255,255,255,0.03)",marginTop:10},ev=_?.type==="group"?en.find(e=>e.id===_.id):null,ej=ee?et.get(ee):null;return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{style:eb,children:[(0,t.jsxs)("label",{style:{display:"flex",gap:8,alignItems:"center",fontSize:13.5,color:"#fff",cursor:a?"default":"pointer"},children:[(0,t.jsx)("input",{type:"checkbox",checked:s,disabled:a,onChange:e=>r(e.target.checked)}),(0,t.jsx)("b",{children:"Keep my messages on this computer"}),(0,t.jsx)("span",{style:{fontSize:11.5,color:s?"#00ff88":"#8b9a9a"},children:s?"on":"off"})]}),(0,t.jsxs)(p.Body,{style:{margin:"6px 0 0",fontSize:12.5},children:["Off unless you turn it on. When it’s on, the messages themselves, including what other people wrote to you, and the notes sent with connection requests, are saved only in the app’s data folder on this computer. They’re never sent anywhere, and they aren’t in “Save a copy of my network”. ",(0,t.jsx)("i",{children:"Forget it"}),", or switching this off, deletes them. With it off, the CRM still shows who, when and who wrote last. Your own stages, tags, notes and follow-ups are always kept, on this computer only."]})]}),(0,t.jsxs)("div",{className:"crm-grid",style:{marginTop:10},children:[(0,t.jsxs)("div",{className:"pipeline"===D?"crm-wide":void 0,style:{...eb,marginTop:0,padding:0,minWidth:0},children:[(0,t.jsx)("div",{role:"tablist","aria-label":"CRM views",style:{display:"flex",flexWrap:"wrap",gap:4,padding:"10px 10px 6px",borderBottom:p.LINE},children:O.map(([e,n])=>(0,t.jsxs)("button",{role:"tab","aria-selected":D===e,onClick:()=>{L(e),V(100)},style:{...E,padding:"4px 9px",fontSize:12,background:D===e?"rgba(52,152,219,0.28)":"rgba(255,255,255,0.04)",color:D===e?"#fff":"#b8c4c4"},children:[n," ",(0,t.jsx)("span",{style:{color:D===e?"#cfe6f7":"#778"},children:ew?"":eg[e].toLocaleString()})]},e))}),(0,t.jsxs)("div",{style:{padding:"8px 10px",borderBottom:p.LINE,display:"flex",gap:8,alignItems:"center",flexWrap:"wrap"},children:[(0,t.jsx)("input",{type:"search",value:R,onChange:e=>{U(e.target.value),V(100)},placeholder:s?"Search names, companies, tags, notes, what was said":"Search names, companies, tags, notes","aria-label":"Search the CRM",style:{...M,flex:"1 1 180px",minWidth:0}}),(0,t.jsx)("button",{onClick:function(){var e;let t,n,o=el.filter(e=>"sponsored"!==e.kind).sort((e,t)=>(t.lastContact||0)-(e.lastContact||0)),s=`Six Degrees CRM ${y()}.csv`;e=function(e){let t=[C.map(S).join(",")];for(let n of e)t.push([n.name,n.row?.company||"",n.profileUrl||"",n.connection?"Yes":"No",g(n.crm?.stage),(n.crm?.tags||[]).join("; "),T(n.lastContact),null==n.lastFromThem?"":n.lastFromThem?"Them":"You",n.crm?.followUp||"",n.crm?.notes||""].map(S).join(","));return`\uFEFF${t.join("\r\n")}\r
|
|
2
|
+
`}(o),t=URL.createObjectURL(new Blob([e],{type:"text/csv;charset=utf-8"})),(n=document.createElement("a")).href=t,n.download=s,n.style.position="fixed",n.style.left="-9999px",document.body.appendChild(n),n.click(),n.remove(),setTimeout(()=>URL.revokeObjectURL(t),6e4),X(`Made “${s}” (${N(o.length,"person","people")}). Look for it in your Downloads folder, or wherever you chose to save it. It holds your notes: keep it private.`)},disabled:ew,style:E,title:"A spreadsheet of everyone here, with your stages, tags, follow-ups and notes",children:"Export CSV"})]}),"awaiting"===D&&(0,t.jsxs)("div",{style:{padding:"8px 12px",borderBottom:p.LINE,fontSize:12.5,color:"#b8c4c4",display:"flex",gap:6,alignItems:"center",flexWrap:"wrap"},children:["You wrote last and nothing came back for",(0,t.jsx)("input",{type:"number",min:1,max:365,value:es,"aria-label":"Days with no reply",onChange:e=>{let t=Number(e.target.value);t>=1&&t<=365&&ey(t)},style:{...M,width:64,padding:"3px 6px"}}),"days or more",o?`, as of ${$(o)}`:"","."]}),Q&&(0,t.jsx)("div",{style:{padding:"8px 12px",fontSize:12.5,color:"#00ff88",borderBottom:p.LINE},children:Q}),ew&&(0,t.jsx)("div",{style:{padding:12,fontSize:13,color:"#8b9a9a"},children:"Loading…"}),!ew&&"pipeline"===D&&(0,t.jsx)(P,{pipeline:eh,picked:ee,onPick:e=>ef({type:"person",key:e})}),!ew&&"pipeline"!==D&&0===eu.length&&(0,t.jsx)("div",{style:{padding:12,fontSize:13,color:"#8b9a9a"},children:ep?"Nothing matches that.":W[D]}),!ew&&"pipeline"!==D&&(0,t.jsxs)("div",{children:[eu.slice(0,G).map(e=>(0,t.jsx)(q,{r:e,nameOf:eo,active:"person"===e.type?ee===e.key:_?.id===e.id,onPick:()=>ef("person"===e.type?{type:"person",key:e.key}:{type:"group",id:e.id})},"person"===e.type?`p:${e.key}`:`g:${e.id}`)),eu.length>G&&(0,t.jsxs)("button",{onClick:()=>V(G+100),style:{width:"100%",padding:10,background:"none",border:"none",color:"#3498DB",cursor:"pointer",fontSize:13},children:["Show ",Math.min(100,eu.length-G).toLocaleString()," more of ",eu.length.toLocaleString()]})]})]}),(0,t.jsxs)("div",{ref:Z,className:"pipeline"===D?"crm-wide":void 0,style:{...eb,marginTop:0,minWidth:0,scrollMarginTop:80},children:[!_&&(0,t.jsx)("div",{style:{fontSize:13,color:"#8b9a9a"},children:"Pick someone to see everything with them, and to add a stage, tags, notes or a follow-up."}),ej&&(0,t.jsx)(H,{c:ej,nameOf:eo,groups:en,keep:s,token:l,inviteNotes:u?.inviteNotes||{},onChange:em,onPickGroup:e=>ef({type:"group",id:e})},ej.key),ev&&(0,t.jsx)(J,{g:ev,contacts:et,nameOf:eo,keep:s,token:l,onPick:e=>ef({type:"person",key:e})})]})]}),(0,t.jsxs)("div",{style:{fontSize:11.5,color:"#778",marginTop:6},children:["Everyone from your export and the live sync, connections or not; groups are listed and marked. Sponsored messages are marked and kept out of the Inbox. Awaiting reply and warmth are judged as of the newest thing your data knows.",Object.keys(z?.people||{}).length>0&&(0,t.jsxs)(t.Fragment,{children:[" ","Your notes are in the app’s data folder, not in “Save a copy of my network”."," ",(0,t.jsx)("button",{onClick:ex,style:{background:"none",border:"none",color:"#ff9b9b",cursor:"pointer",fontSize:11.5,padding:0},children:"Delete my CRM notes"})]})]})]})}let W={inbox:"No one is waiting on a reply.",awaiting:"Nobody you wrote to is overdue a reply.",due:"No follow-ups are due. Set one on anyone, and it shows here on the day.",sent:"Nothing sent yet: choose your export folder above (its Invitations.csv), or mark requests sent in the app.",received:"No requests waiting on you, as far as your export shows.",all:"Nobody here yet. Choose your export folder above, or sync your messages."};function U({tier:e}){return(0,t.jsx)("span",{style:{width:8,height:8,borderRadius:"50%",background:I[e]||"#556",flexShrink:0,display:"inline-block"}})}function A({c:e}){return(0,t.jsxs)(t.Fragment,{children:[e&&!e.connection&&(0,t.jsx)("span",{style:R("rgba(255,159,67,0.18)","#ffc58a"),children:2===e.degree?"2nd degree":"Not a connection"}),e?.kind==="sponsored"&&(0,t.jsx)("span",{style:R("rgba(255,255,255,0.08)"),children:"Sponsored"}),e?.kind==="inmail"&&(0,t.jsx)("span",{style:R("rgba(155,89,182,0.25)"),children:"InMail"}),e?.crm?.stage&&(0,t.jsx)("span",{style:R("rgba(255,255,255,0.06)",D[e.crm.stage]),children:g(e.crm.stage)})]})}function q({r:e,nameOf:n,active:o,onPick:s}){let r,a=null,i=null;if("person"===e.type){let n=e.c;r=n?.name||e.row?.name||e.key,a=n?.row?.tier||e.row?.tier,i=(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(A,{c:n||{connection:e.row?.degree===1,degree:e.row?.degree}}),n?.unread>0&&(0,t.jsxs)("span",{style:R("#3498DB","#fff"),children:[n.unread," unread"]})]})}else r=Y(e.g,n),i=(0,t.jsx)("span",{style:R("rgba(255,255,255,0.08)"),children:e.g.unknown?"To someone unnamed":"Group"});let l="person"===e.type?e.c?.row?.company||e.row?.company:null;return(0,t.jsxs)("div",{role:"button",tabIndex:0,"aria-pressed":o,onClick:s,onKeyDown:e=>{("Enter"===e.key||" "===e.key)&&(e.preventDefault(),s())},style:{padding:"8px 12px",borderBottom:"1px solid rgba(255,255,255,0.04)",cursor:"pointer",background:o?"rgba(52,152,219,0.14)":"none"},children:[(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:6,fontSize:13,minWidth:0,flexWrap:"wrap"},children:[(0,t.jsx)(U,{tier:a}),(0,t.jsx)("b",{style:{overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",maxWidth:"100%"},children:r}),i]}),(0,t.jsx)("div",{style:{fontSize:11.5,color:"#8b9a9a",marginTop:2,paddingLeft:14,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:[l,e.sub].filter(Boolean).join(" · ")})]})}function Y(e,t){if(e.title)return e.title;if(e.unknown)return"A conversation only you wrote in";let n=e.people.map(t).filter(Boolean);return n.length?`${n.slice(0,3).join(", ")}${e.people.length>3?` +${e.people.length-3}`:""}`:`${e.people.length} people`}function P({pipeline:e,picked:n,onPick:o}){return(0,t.jsx)("div",{className:"crm-board",children:h.map(s=>(0,t.jsxs)("div",{style:{minWidth:0},children:[(0,t.jsxs)("div",{style:{fontSize:12,fontWeight:650,color:D[s.id],margin:"0 0 6px",display:"flex",justifyContent:"space-between"},children:[(0,t.jsx)("span",{children:s.label}),(0,t.jsx)("span",{style:{color:"#778"},children:e[s.id].length.toLocaleString()})]}),0===e[s.id].length&&(0,t.jsx)("div",{style:{fontSize:11.5,color:"#667",padding:"6px 0"},children:"No one"}),e[s.id].slice(0,200).map(e=>(0,t.jsxs)("div",{role:"button",tabIndex:0,onClick:()=>o(e.key),onKeyDown:t=>{("Enter"===t.key||" "===t.key)&&(t.preventDefault(),o(e.key))},style:{padding:"7px 9px",marginBottom:6,borderRadius:6,border:p.LINE,cursor:"pointer",fontSize:12.5,background:n===e.key?"rgba(52,152,219,0.18)":"rgba(255,255,255,0.03)"},children:[(0,t.jsxs)("div",{style:{display:"flex",gap:6,alignItems:"center"},children:[(0,t.jsx)(U,{tier:e.row?.tier}),(0,t.jsx)("b",{style:{overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.name})]}),(0,t.jsx)("div",{style:{color:"#8b9a9a",fontSize:11,marginTop:2},children:[e.row?.company,e.crm.followUp?`Follow up ${F(e.crm.followUp)}`:null].filter(Boolean).join(" · ")})]},e.key)),e[s.id].length>200&&(0,t.jsxs)("div",{style:{fontSize:11,color:"#778"},children:["and ",(e[s.id].length-200).toLocaleString()," more (search to find them)"]})]},s.id))})}let _={fontSize:12,fontWeight:650,color:"#b8c4c4",margin:"16px 0 6px",textTransform:"uppercase",letterSpacing:.4};function H({c:e,nameOf:o,groups:s,keep:r,token:a,inviteNotes:i,onChange:l,onPickGroup:c}){let d=e.row,[u,h]=(0,n.useState)(e.conversations[0]?.id||null),g=L(e.profileUrl),f=L(e.threadUrl),m=e.connection?`A connection${d?.connected_date?` since ${$(Date.parse(d.connected_date))}`:""}.`:2===e.degree?"2nd degree: not a connection yet.":"Not a connection.";return(0,t.jsxs)("div",{style:{fontSize:13},children:[(0,t.jsxs)("div",{style:{display:"flex",gap:8,alignItems:"center",flexWrap:"wrap"},children:[(0,t.jsx)(U,{tier:d?.tier}),(0,t.jsx)("h3",{style:{margin:0,fontSize:17},children:e.name}),d?.tier&&(0,t.jsxs)("span",{style:R("rgba(255,255,255,0.06)",I[d.tier]),children:[d.tier," tier"]}),(0,t.jsx)(A,{c:e})]}),(d?.headline||d?.company)&&(0,t.jsx)("div",{style:{color:"#b8c4c4",marginTop:4},children:d.headline||[d.role,d.company].filter(Boolean).join(" at ")}),(0,t.jsxs)("div",{style:{color:"#8b9a9a",marginTop:4,fontSize:12.5},children:[m,e.introducers.length>0&&(0,t.jsxs)(t.Fragment,{children:[" Who can introduce you: ",(0,t.jsx)("b",{style:{color:"#dfe8e8"},children:e.introducers.slice(0,6).join(", ")}),e.introducers.length>6?` and ${e.introducers.length-6} more`:"","."]}),d?.unlocked_from_name&&e.connection&&(0,t.jsxs)(t.Fragment,{children:[" You met through ",(0,t.jsx)("b",{style:{color:"#dfe8e8"},children:d.unlocked_from_name}),"."]})]}),(0,t.jsxs)("div",{style:{display:"flex",gap:12,marginTop:6,flexWrap:"wrap",fontSize:12.5},children:[g&&(0,t.jsx)("a",{href:g,target:"_blank",rel:"noreferrer",style:{color:"#3498DB",textDecoration:"none"},children:"Profile on LinkedIn ↗"}),f&&(0,t.jsx)("a",{href:f,target:"_blank",rel:"noreferrer",style:{color:"#3498DB",textDecoration:"none"},children:"Conversation on LinkedIn ↗"})]}),(0,t.jsx)(K,{c:e,onChange:l}),(0,t.jsx)("div",{style:_,children:"Conversations"}),0===e.conversations.length&&(0,t.jsx)("div",{style:{color:"#8b9a9a",fontSize:12.5},children:"None one to one."}),e.conversations.map(e=>(0,t.jsxs)("div",{style:{border:p.LINE,borderRadius:6,marginBottom:6,overflow:"hidden"},children:[(0,t.jsxs)("div",{role:"button",tabIndex:0,"aria-expanded":u===e.id,onClick:()=>h(u===e.id?null:e.id),onKeyDown:t=>{("Enter"===t.key||" "===t.key)&&(t.preventDefault(),h(u===e.id?null:e.id))},style:{display:"flex",gap:8,alignItems:"center",flexWrap:"wrap",padding:"7px 10px",cursor:"pointer",fontSize:12.5,background:u===e.id?"rgba(255,255,255,0.04)":"none"},children:[(0,t.jsx)("span",{style:{color:"#dfe8e8"},children:$(e.last)||"No date"}),null!=e.lastFromThem&&(0,t.jsx)("span",{style:{color:e.lastFromThem?"#ff9f43":"#8b9a9a"},children:e.lastFromThem?"They wrote last":"You wrote last"}),null!=e.count&&(0,t.jsx)("span",{style:{color:"#8b9a9a"},children:N(e.count,"message")}),null!=e.mine&&null!=e.count&&e.mine===e.count&&(0,t.jsx)("span",{style:R("rgba(255,255,255,0.06)"),children:"Only you wrote"}),e.folder&&"inbox"!==e.folder&&(0,t.jsx)("span",{style:R("rgba(255,255,255,0.06)"),children:e.folder}),"inmail"===e.kind&&(0,t.jsx)("span",{style:R("rgba(155,89,182,0.25)"),children:"InMail"}),"sponsored"===e.kind&&(0,t.jsx)("span",{style:R("rgba(255,255,255,0.08)"),children:"Sponsored"}),e.unread>0&&(0,t.jsxs)("span",{style:R("#3498DB","#fff"),children:[e.unread," unread"]})]}),u===e.id&&(0,t.jsx)(z,{id:e.id,keep:r,group:!1,token:a},`${e.id}:${a}:${r}`)]},e.id)),e.groups.length>0&&(0,t.jsxs)("div",{style:{fontSize:12.5,color:"#8b9a9a",marginTop:4},children:["Also in ",N(e.groups.length,"group"),":"," ",e.groups.slice(0,8).map((e,n)=>{let r=s.find(t=>t.id===e);return(0,t.jsxs)("span",{children:[n>0?", ":"",(0,t.jsx)("button",{onClick:()=>c(e),style:{background:"none",border:"none",color:"#3498DB",cursor:"pointer",padding:0,fontSize:12.5},children:r?Y(r,o):"a group"})]},e)})]}),(0,t.jsx)("div",{style:_,children:"Requests"}),e.invitesOut.length+e.invitesIn.length===0&&!e.request&&(0,t.jsx)("div",{style:{color:"#8b9a9a",fontSize:12.5},children:"None on file."}),[...e.invitesOut,...e.invitesIn].sort((e,t)=>(t.t||0)-(e.t||0)).map(n=>(0,t.jsxs)("div",{style:{fontSize:12.5,marginBottom:6},children:[(0,t.jsx)("span",{style:{color:"#dfe8e8"},children:"out"===n.dir?"You asked to connect":"They asked to connect"}),(0,t.jsxs)("span",{style:{color:"#8b9a9a"},children:[" · ",$(n.t)||"no date"," · ",e.connection?"accepted":"out"===n.dir?"pending":"not accepted yet"]}),r&&i[n.id]&&(0,t.jsx)("div",{style:{marginTop:3,padding:"6px 9px",borderRadius:8,background:"rgba(255,255,255,0.06)",whiteSpace:"pre-wrap",overflowWrap:"anywhere"},children:i[n.id]})]},n.id)),e.request&&(0,t.jsxs)("div",{style:{fontSize:12.5},children:[(0,t.jsx)("span",{style:{color:"#dfe8e8"},children:"Request tracked in the app"}),(0,t.jsxs)("span",{style:{color:"#8b9a9a"},children:[" · ",e.request.status]})]})]})}function K({c:e,onChange:o}){let s=e.crm||{},[r,a]=(0,n.useState)(s.notes||""),[i,l]=(0,n.useState)(""),[c,d]=(0,n.useState)(null),p=(0,n.useRef)(null),u=e.theyWrote?"replied":e.conversations.length||e.invitesOut.length||e.request?"contacted":"new";async function f(t){d("Saving…");try{await o(e.key,t),d("Saved")}catch(e){d(e.message)}}(0,n.useEffect)(()=>()=>clearTimeout(p.current),[]);let m=e=>y(new Date(Date.now()+864e5*e)),x=s.tags||[];function w(){let e=i.trim();e&&(l(""),f({tags:[...x,...e.split(",")]}))}return(0,t.jsxs)("div",{style:{marginTop:12,padding:"10px 12px",borderRadius:8,background:"rgba(52,152,219,0.06)",border:"1px solid rgba(52,152,219,0.18)"},children:[(0,t.jsxs)("div",{style:{display:"flex",gap:12,flexWrap:"wrap",alignItems:"flex-end"},children:[(0,t.jsxs)("label",{style:{fontSize:11.5,color:"#8b9a9a",display:"flex",flexDirection:"column",gap:3},children:["Stage",(0,t.jsxs)("select",{value:s.stage||"",onChange:e=>f({stage:e.target.value||null}),style:{...M,padding:"5px 8px"},children:[(0,t.jsxs)("option",{value:"",children:["Not set (looks like ",g(u),")"]}),h.map(e=>(0,t.jsx)("option",{value:e.id,children:e.label},e.id))]})]}),(0,t.jsxs)("label",{style:{fontSize:11.5,color:"#8b9a9a",display:"flex",flexDirection:"column",gap:3},children:["Next follow-up",(0,t.jsx)("input",{type:"date",value:s.followUp||"",onChange:e=>f({followUp:e.target.value||null}),style:{...M,padding:"4px 8px",colorScheme:"dark"}})]}),(0,t.jsxs)("div",{style:{display:"flex",gap:4,flexWrap:"wrap"},children:[(0,t.jsx)("button",{onClick:()=>f({followUp:m(3)}),style:E,children:"In 3 days"}),(0,t.jsx)("button",{onClick:()=>f({followUp:m(7)}),style:E,children:"In a week"}),s.followUp&&(0,t.jsx)("button",{onClick:()=>f({followUp:null}),style:E,children:"Clear"})]})]}),null==s.stage&&"new"!==u&&(0,t.jsxs)("button",{onClick:()=>f({stage:u}),style:{...E,marginTop:8},children:["Set to ",g(u)]}),(0,t.jsxs)("div",{style:{marginTop:10,display:"flex",gap:6,flexWrap:"wrap",alignItems:"center"},children:[x.map(e=>(0,t.jsxs)("span",{style:{...R("rgba(255,255,255,0.08)"),fontSize:11.5,display:"inline-flex",gap:4,alignItems:"center"},children:[e,(0,t.jsx)("button",{"aria-label":`Remove ${e}`,onClick:()=>f({tags:x.filter(t=>t!==e)}),style:{background:"none",border:"none",color:"#8b9a9a",cursor:"pointer",padding:0,fontSize:12},children:"×"})]},e)),(0,t.jsx)("input",{value:i,onChange:e=>l(e.target.value),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),w())},onBlur:w,placeholder:"Add a tag","aria-label":"Add a tag",style:{...M,padding:"3px 8px",fontSize:12,width:120}})]}),(0,t.jsx)("textarea",{value:r,onChange:e=>{var t;a(t=e.target.value),clearTimeout(p.current),p.current=setTimeout(()=>f({notes:t}),800)},onBlur:function(){clearTimeout(p.current),r!==(s.notes||"")&&f({notes:r})},placeholder:"Your notes on them: kept on this computer only","aria-label":"Notes",rows:4,style:{...M,width:"100%",marginTop:10,resize:"vertical",fontFamily:"inherit",lineHeight:1.45,boxSizing:"border-box"}}),(0,t.jsx)("div",{style:{fontSize:11,color:c&&"Saved"!==c&&"Saving…"!==c?"#ff9b9b":"#778",marginTop:4,minHeight:14},children:c||""})]})}function J({g:e,contacts:n,nameOf:o,keep:s,token:r,onPick:a}){let i=L(e.threadUrl);return(0,t.jsxs)("div",{style:{fontSize:13},children:[(0,t.jsxs)("div",{style:{display:"flex",gap:8,alignItems:"center",flexWrap:"wrap"},children:[(0,t.jsx)("h3",{style:{margin:0,fontSize:17},children:Y(e,o)}),(0,t.jsx)("span",{style:R("rgba(255,255,255,0.08)"),children:e.unknown?"To someone unnamed":"Group"}),e.unread>0&&(0,t.jsxs)("span",{style:R("#3498DB","#fff"),children:[e.unread," unread"]})]}),(0,t.jsx)("div",{style:{color:"#8b9a9a",marginTop:4,fontSize:12.5},children:[e.last?`Last active ${$(e.last)}`:null,null!=e.count?N(e.count,"message"):null].filter(Boolean).join(" · ")}),i&&(0,t.jsx)("a",{href:i,target:"_blank",rel:"noreferrer",style:{color:"#3498DB",textDecoration:"none",fontSize:12.5,display:"inline-block",marginTop:6},children:"Conversation on LinkedIn ↗"}),e.people.length>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("div",{style:_,children:"Who’s in it"}),(0,t.jsx)("div",{style:{display:"flex",flexWrap:"wrap",gap:6},children:e.people.map(e=>{let s=n.get(e);return(0,t.jsxs)("button",{onClick:()=>a(e),style:{...E,display:"inline-flex",gap:6,alignItems:"center"},children:[(0,t.jsx)(U,{tier:s?.row?.tier}),o(e)||e.split("/").pop(),s&&!s.connection&&(0,t.jsx)("span",{style:{color:"#ffc58a",fontSize:10.5},children:"not a connection"})]},e)})})]}),(0,t.jsx)("div",{style:_,children:"Messages"}),(0,t.jsx)("div",{style:{border:p.LINE,borderRadius:6,overflow:"hidden"},children:(0,t.jsx)(z,{id:e.id,keep:s,group:!0,token:r},`${e.id}:${r}:${s}`)})]})}let G={warm:["Warm","#ff9f43"],cool:["Cool","#3498DB"],dormant:["Dormant","#8899aa"],never:["Never messaged","#556"]},V={"connections.csv":"first name","messages.csv":"conversation id","invitations.csv":"direction","positions.csv":"company name","shares.csv":"date"},Q=e=>e?new Date(e).toLocaleDateString(void 0,{day:"numeric",month:"short",year:"numeric"}):"";async function X(e){let t=[],n={},o=0;for(let s of e)for(let e of s.messages){let r=JSON.stringify(e).length+2;o+r>25e5&&o>0&&(t.push(n),n={},o=0),n[s.id]||(n[s.id]={title:s.title||"",messages:[]},o+=s.id.length+(s.title||"").length+40),n[s.id].messages.push(e),o+=r}t.push(n);for(let e=0;e<t.length;e++){let n=await fetch("/api/social/messages",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({part:e,parts:t.length,threads:t[e]})});if(!n.ok)throw Error((await n.json().catch(()=>({}))).error||"The messages couldn’t be saved.")}}async function Z(e){let t={};for(let n of e)n.note&&(t[n.id]=n.note);let n=await fetch("/api/social/messages",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({invites:t})});if(!n.ok)throw Error((await n.json().catch(()=>({}))).error||"The requests’ notes couldn’t be saved.")}function ee(){let{userId:e}=(0,r.useUser)(),[s,h]=(0,n.useState)(void 0),[g,f]=(0,n.useState)(null),[m,y]=(0,n.useState)(!1),[x,w]=(0,n.useState)(null),[b,v]=(0,n.useState)(!1),[j,k]=(0,n.useState)(()=>(0,d.scannerNow)()),[S,T]=(0,n.useState)(!1),[C,z]=(0,n.useState)(0),[I,D]=(0,n.useState)(0),$=(0,n.useRef)(null),F=(0,n.useRef)(null),L=s?.keepMessages===!0,N=()=>fetch("/api/social").then(e=>e.json()).then(e=>h(e.social||null)).catch(()=>h(null)).finally(()=>z(e=>e+1));async function O(e){v(!0),w(null);try{let t={};for(let n of Array.from(e||[])){let e=n.name.toLowerCase();V[e]&&!t[e]&&(t[e]=(0,i.readTable)(await n.text(),V[e]))}if(!Object.keys(t).length)throw Error("That folder doesn’t have LinkedIn’s export files in it (Connections.csv, messages.csv and so on).");let n=t["connections.csv"]||[],o=t["messages.csv"]?(0,i.messageStats)(t["messages.csv"]):{asOf:null,people:new Map},s=t["messages.csv"]?(0,i.buildConversations)(t["messages.csv"],{keepText:L}):null,r=t["invitations.csv"]?(0,i.buildInvitations)(t["invitations.csv"],{keepText:L}):null;$.current=t["messages.csv"]||null,F.current=t["invitations.csv"]||null;let a={};for(let[e,t]of o.people)a[e]={last:t.last,lastFromThem:t.lastFromThem,total:t.total,recent:t.recent};if(m)for(let e of n){let t=e["email address"];if(!t)continue;let n=(0,c.keyFor)({profile_url:e.url});a[n]={...a[n]||{},email:t}}let l=o.asOf||Date.now(),d={asOf:l,people:a,conversations:s?s.conversations.map(i.conversationSummary):[],chapters:(0,i.careerChapters)(t["positions.csv"]||[],n,l),posts:t["shares.csv"]?(0,i.postingEffect)(t["shares.csv"],n):null,invites:t["invitations.csv"]?(0,i.invitationSplit)(t["invitations.csv"]):null,invitations:(r||[]).map(({note:e,...t})=>t),names:s?s.names:{},emails:m},p=await fetch("/api/social",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(d)});if(!p.ok)throw Error((await p.json().catch(()=>({}))).error||"It couldn’t be saved.");s&&L&&await X(s.conversations),r&&L&&await Z(r);let u=s?[s.drafts?`${s.drafts.toLocaleString()} unsent ${1===s.drafts?"draft":"drafts"} left out`:"",s.skipped?`${s.skipped.toLocaleString()} ${1===s.skipped?"row":"rows"} with no conversation or date left out`:""].filter(Boolean):[];w({good:!0,text:`Read ${Object.keys(t).length} of LinkedIn’s files: ${o.people.size.toLocaleString()} people you’ve messaged one to one`+(s?`, ${s.conversations.length.toLocaleString()} conversations${L?", their messages kept on this computer":""}`:"")+(r?`, ${r.length.toLocaleString()} connection requests`:"")+`.${u.length?` (${u.join("; ")}.)`:""}`}),await N()}catch(e){w({good:!1,text:e.message})}finally{v(!1)}}async function R(e=!1){w(null);try{let t=await (0,d.runScrape)(e?"messages-full":"messages");w(t?.exitCode===0?{good:!0,text:e?"Your whole messages history is read.":"Your messages list is read."}:{good:!1,text:"The sync stopped before it finished. The Scan page has the log."}),await N()}catch(e){w({good:!1,text:e.message})}}async function E(e){await fetch("/api/social",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({autoSync:e})}),N()}async function M(e){if(e||window.confirm("Delete the messages kept on this computer? The list of conversations stays; the messages themselves are deleted.")){T(!0),w(null);try{if(e||await fetch("/api/social/messages",{method:"DELETE"}),!(await fetch("/api/social",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({keepMessages:e})})).ok)throw Error("The switch couldn’t be saved.");e&&($.current||F.current)?($.current&&await X((0,i.buildConversations)($.current,{keepText:!0}).conversations),F.current&&await Z((0,i.buildInvitations)(F.current,{keepText:!0})),w({good:!0,text:"Your messages are kept on this computer now."})):e?w({good:!0,text:"On. Choose your export folder again, or sync your messages, to bring the messages in."}):w({good:!0,text:"Off. The kept messages are deleted."})}catch(e){w({good:!1,text:e.message})}finally{T(!1),N()}}}async function W(){await fetch("/api/social",{method:"DELETE"}),$.current=null,F.current=null;let e="Forgotten. Nothing from your export or messages is kept here now, the messages themselves included.";window.confirm("Also delete your CRM: the stages, tags, notes and follow-up dates you added? This can’t be undone. Cancel keeps them.")?(await fetch("/api/social/crm",{method:"DELETE"}),D(e=>e+1),e+=" Your CRM notes are deleted too."):e+=" Your CRM notes are kept.",w({good:!0,text:e}),N()}(0,n.useEffect)(()=>{N()},[]),(0,n.useEffect)(()=>(0,d.watchScanner)(()=>k((0,d.scannerNow)())),[]),(0,n.useEffect)(()=>{if(!e)return;let t=!0;return(0,a.loadNetwork)(e).then(e=>{t&&f(e)}).catch(()=>{}),()=>{t=!1}},[e]);let{merged:U,asOf:A}=(0,n.useMemo)(()=>(0,l.mergeSocial)(s),[s]),q=(0,n.useMemo)(()=>{let e={warm:0,cool:0,dormant:0,never:0};for(let t of g?.degree1||[])e[(0,i.warmthOf)(U.get((0,c.keyFor)(t)),A)]+=1;return e},[g,U,A]);if(u.IS_DEMO)return(0,t.jsx)("div",{style:{minHeight:"100vh",background:"#0a0a1a",color:"#aaa",padding:40,fontFamily:p.FONT},children:"Not part of the demo."});let Y=j?.running,P={padding:"12px 14px",borderRadius:8,border:p.LINE,background:"rgba(255,255,255,0.03)",marginTop:10},_={fontSize:16,margin:"24px 0 6px"};return(0,t.jsxs)("div",{style:{minHeight:"100vh",background:"#0a0a1a",color:"#fff",fontFamily:p.FONT},children:[(0,t.jsxs)("header",{style:{padding:"16px 24px",borderBottom:p.LINE,display:"flex",alignItems:"center",gap:16},children:[(0,t.jsx)(o.default,{href:"/",style:{color:"#888",textDecoration:"none",fontSize:13,fontWeight:600,padding:"6px 14px",borderRadius:6,background:"rgba(255,255,255,0.06)",border:p.LINE},children:"← Back to Map"}),(0,t.jsxs)("h1",{style:{fontSize:22,fontWeight:700,margin:0,color:"#FFD700"},children:["Social ",(0,t.jsx)("span",{style:{fontSize:12,color:"#8b9a9a",fontWeight:600},children:"experimental"})]})]}),(0,t.jsxs)("main",{style:{maxWidth:1180,margin:"0 auto",padding:"8px 16px 64px"},children:[(0,t.jsxs)(p.Body,{style:{marginTop:16},children:["Everyone you’ve been in touch with on LinkedIn, connections or not: who’s waiting on you, who hasn’t answered, what you’ve sent and received, and your own notes and follow-ups on each, from your own LinkedIn data. Only dates, who wrote last, counts and names are kept on this computer, and what messages say only if you turn on ",(0,t.jsx)("i",{children:"Keep my messages"})," below."]}),(0,t.jsx)("h2",{style:_,children:"Your LinkedIn export"}),(0,t.jsxs)("div",{style:P,children:[(0,t.jsxs)(p.Body,{style:{margin:0},children:["On LinkedIn: ",(0,t.jsx)("i",{children:"Settings → Data privacy → Get a copy of your data"}),", pick the larger archive, and unzip the file it emails you. Then choose that folder here. It’s read in this window; nothing goes to LinkedIn."]}),(0,t.jsxs)("label",{style:{display:"flex",gap:8,alignItems:"flex-start",fontSize:12.5,color:"#b8c4c4",marginTop:10},children:[(0,t.jsx)("input",{type:"checkbox",checked:m,onChange:e=>y(e.target.checked),style:{marginTop:3}}),(0,t.jsx)("span",{children:"Also keep email addresses from it, on this computer only, for one-click email."})]}),(0,t.jsxs)("div",{style:{marginTop:10,display:"flex",gap:10,alignItems:"center",flexWrap:"wrap"},children:[(0,t.jsxs)("label",{style:{padding:"7px 14px",borderRadius:8,background:"rgba(52,152,219,0.18)",color:"#cfe6f7",cursor:b?"default":"pointer",fontSize:13},children:[b?"Reading…":s?"Choose a newer export":"Choose the export folder",(0,t.jsx)("input",{type:"file",webkitdirectory:"",directory:"",multiple:!0,disabled:b,style:{display:"none"},onChange:e=>O(e.target.files)})]}),s&&(0,t.jsxs)("span",{style:{fontSize:12,color:"#8b9a9a"},children:["From an export up to ",Q(s.asOf),s.liveAt?` \xb7 messages synced ${Q(Date.parse(s.liveAt))}`:""]}),s&&(0,t.jsx)("button",{onClick:W,style:{background:"none",border:"none",color:"#ff9b9b",cursor:"pointer",fontSize:12},children:"Forget it"})]})]}),(0,t.jsxs)("h2",{style:_,children:["Live messages sync ",(0,t.jsx)("span",{style:{fontSize:11,color:"#FFD700"},children:"experimental"})]}),(0,t.jsxs)("div",{style:P,children:[(0,t.jsxs)(p.Body,{style:{margin:0},children:["Reads your messages list once, in your own Chrome: who each conversation is with, connections or not, when it was last active, whether it’s unread and who wrote last. It uses no search budget and opens no conversation. The newest message’s words are kept only if ",(0,t.jsx)("i",{children:"Keep my messages"})," is on. The daily sync reads the top of the list; ",(0,t.jsx)("i",{children:"Read my whole history"})," keeps scrolling until no more conversations load (at most 60 scrolls, about 1,000 conversations), at the same slow, fixed pace, so it takes a few minutes."]}),(0,t.jsxs)("div",{style:{marginTop:10,display:"flex",gap:12,alignItems:"center",flexWrap:"wrap"},children:[(0,t.jsx)("button",{onClick:()=>R(!1),disabled:Y,style:{padding:"7px 14px",borderRadius:8,border:"none",background:Y?"#333":"rgba(0,255,136,0.15)",color:Y?"#777":"#00ff88",cursor:Y?"default":"pointer",fontSize:13},children:Y?"The scanner is busy":"Sync messages now"}),(0,t.jsx)("button",{onClick:()=>R(!0),disabled:Y,style:{padding:"7px 14px",borderRadius:8,border:p.LINE,background:"none",color:Y?"#777":"#cfe6f7",cursor:Y?"default":"pointer",fontSize:13},children:"Read my whole history"}),(0,t.jsxs)("label",{style:{display:"flex",gap:6,alignItems:"center",fontSize:12.5,color:"#b8c4c4"},children:[(0,t.jsx)("input",{type:"checkbox",checked:s?.autoSync===!0,onChange:e=>E(e.target.checked)}),"Once a day while the app is open (daytime only)"]})]})]}),x&&(0,t.jsx)("div",{style:{marginTop:10,fontSize:13,color:x.good?"#00ff88":"#ff9b9b"},children:x.text}),(0,t.jsx)("h2",{style:_,children:"People"}),(0,t.jsx)(B,{net:g,asOf:s?A:null,keep:L,onKeep:M,switching:S||b,token:C,crmToken:I}),s&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("h2",{style:_,children:"Warmth"}),(0,t.jsx)("div",{style:{display:"grid",gridTemplateColumns:"repeat(auto-fit, minmax(160px, 1fr))",gap:10},children:Object.entries(G).map(([e,[n,o]])=>(0,t.jsxs)("div",{style:{...P,marginTop:0},children:[(0,t.jsx)("div",{style:{fontSize:22,fontWeight:700,color:o},children:(q[e]||0).toLocaleString()}),(0,t.jsx)("div",{style:{fontSize:12.5,color:"#b8c4c4"},children:n})]},e))}),(0,t.jsx)("div",{style:{fontSize:11.5,color:"#778",marginTop:6},children:"Of your connections. Warm: messaged in the last 30 days, or 3+ messages in 90. Cool: within a year. Dormant: longer ago."}),s.chapters?.length>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("h2",{style:_,children:"Career chapters"}),(0,t.jsx)("div",{style:{...P,padding:0},children:s.chapters.map(e=>{let n=(e.people||[]).filter(e=>["warm","cool"].includes((0,i.warmthOf)(U.get((0,c.keyFor)({profile_url:e})),A))).length;return(0,t.jsxs)("div",{style:{display:"flex",gap:10,padding:"8px 14px",borderBottom:"1px solid rgba(255,255,255,0.04)",fontSize:13,alignItems:"baseline"},children:[(0,t.jsxs)("span",{style:{flex:1},children:[(0,t.jsx)("b",{children:e.company})," ",(0,t.jsxs)("span",{style:{color:"#8b9a9a"},children:[e.title," · ",new Date(e.from).getFullYear(),"–",e.to?new Date(e.to).getFullYear():"now"]})]}),(0,t.jsxs)("span",{style:{color:"#b8c4c4"},children:[e.made.toLocaleString()," connections made"]}),(0,t.jsx)("span",{style:{color:"#ff9f43",minWidth:90,textAlign:"right"},children:e.made?`${Math.round(100*n/e.made)}% still in touch`:""})]},`${e.company}-${e.from}`)})})]}),s.posts?.posts?.length>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("h2",{style:_,children:"Does posting work?"}),(0,t.jsxs)("div",{style:P,children:[(0,t.jsxs)("div",{style:{fontSize:13},children:["In the week after a post you made ",(0,t.jsx)("b",{children:s.posts.afterPosts.toFixed(1)})," new connections on average; a usual week, ",(0,t.jsx)("b",{children:s.posts.usualWeek.toFixed(1)}),"."]}),(0,t.jsx)("div",{style:{fontSize:11.5,color:"#778",marginTop:4},children:"What came after a post, not proof it came from it."}),[...s.posts.posts].sort((e,t)=>t.week-e.week).slice(0,3).map(e=>(0,t.jsxs)("div",{style:{fontSize:12.5,color:"#b8c4c4",marginTop:6},children:[Q(e.t),": ",e.week," new connections that week ",e.link?(0,t.jsx)("a",{href:e.link,target:"_blank",rel:"noreferrer",style:{color:"#3498DB",textDecoration:"none"},children:"Post ↗"}):null]},e.t))]})]}),s.invites?.total>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("h2",{style:_,children:"Who reaches out"}),(0,t.jsx)("div",{style:P,children:(0,t.jsxs)("span",{style:{fontSize:13},children:[s.invites.incoming.toLocaleString()," requests came to you and you sent ",s.invites.outgoing.toLocaleString()," ","(",Math.round(100*s.invites.incoming/s.invites.total),"% came to you), as far as your export shows."]})})]})]})]})]})}e.s(["default",0,function(){return(0,t.jsx)(s.default,{children:(0,t.jsx)(ee,{})})}],60451)}]);
|
package/.next/{static/chunks/1z_rt4jteewqp.js → standalone/.next/static/chunks/3zw8bv7-mc4n6.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,2776,e=>{"use strict";var t=e.i(43476),r=e.i(15812);e.s(["default",0,function({children:e}){let{userId:n,ready:i}=(0,r.useUser)();return i&&n?e:(0,t.jsx)("div",{style:{minHeight:"100vh",display:"flex",alignItems:"center",justifyContent:"center",background:"#0a0a1a",color:"#fff",padding:24,textAlign:"center",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'},children:i?(0,t.jsxs)("div",{style:{maxWidth:420},children:[(0,t.jsx)("div",{style:{fontSize:18,fontWeight:700,marginBottom:8},children:"Can’t reach Six Degrees’ local server"}),(0,t.jsx)("div",{style:{color:"#888",fontSize:14,lineHeight:1.6},children:"The page loaded but the app behind it is not answering. If you started it from a terminal, check that window for an error, then reload this page."})]}):(0,t.jsx)("div",{style:{fontSize:18,fontWeight:600},children:"Loading…"})})}])},28867,86106,e=>{"use strict";var t=e.i(71645),r=e.i(7214);let n=Object.freeze({known:!1,sent:new Set,mine:new Map,version:0}),i=new Set,o=n,l=null,s=new Map;function d(e=o.sent,t=o.known){for(let r of(o=Object.freeze({known:t,sent:e,mine:new Map(s),version:o.version+1}),[...i]))r()}function a(e){return i.add(e),l||o.known||(l=fetch("/api/outreach").then(e=>e.ok?e.json():null).then(e=>{e&&d(new Set((e.pending||[]).map(r.keyFor)),!0)}).catch(()=>{}).finally(()=>{l=null})),()=>i.delete(e)}function c(){return o}async function g(e){let t=await fetch("/api/outreach",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}),r=await t.json().catch(()=>({}));if(!t.ok)throw Error(r.error||"Could not save that.");return r}async function p(e,{bridgeId:t}={}){let n=(0,r.keyFor)(e),i=s.has(n)?s.get(n):void 0;s.set(n,!0),d();try{return await g({action:"mark-sent",connectionId:e.id,profileUrl:e.profile_url,bridgeId:t})}catch(e){throw void 0===i?s.delete(n):s.set(n,i),d(),e}}async function h(e){let t=(0,r.keyFor)(e),n=s.has(t)?s.get(t):void 0;s.set(t,!1),d();try{return await g({action:"undo",connectionId:e.id,profileUrl:e.profile_url})}catch(e){throw void 0===n?s.delete(t):s.set(t,n),d(),e}}e.s(["REQUESTS_UNKNOWN",0,n,"hasRequest",0,function(e,t=o){if(!e)return!1;let n=(0,r.keyFor)(e);return t.mine.has(n)?t.mine.get(n):t.known?t.sent.has(n):"pending"===e.unlock_status||"sent"===e.outreach_status},"markRequested",0,p,"requestCount",0,function(e=o){let t=new Set(e.known?e.sent:[]);for(let[r,n]of e.mine)n?t.add(r):t.delete(r);return t.size},"requestsNow",0,c,"undoRequest",0,h,"watchRequests",0,a],86106),e.s(["default",0,function(){return(0,t.useSyncExternalStore)(a,c,()=>n)}],28867)},77305,e=>{"use strict";var t=e.i(43476),r=e.i(71645),n=e.i(19821),i=e.i(64745),o=e.i(22016),l=e.i(48235);let s={S:25,A:15,B:10,C:5,D:2},d={S:100,A:60,B:35,C:15,D:5};var a=e.i(5258),c=e.i(36774);let g={S:"#FFD700",A:"#9B59B6",B:"#3498DB",C:"#95A5A6",D:"#BDC3C7"},p="1px solid rgba(255,255,255,0.1)";function h({person:e,size:r=36,ring:n}){let i=g[e?.tier]||"#667";return(0,t.jsxs)("div",{style:{position:"relative",width:r,height:r,flexShrink:0},children:[(0,t.jsx)("div",{style:{width:r,height:r,borderRadius:"50%",background:i,color:e?.tier==="S"?"#000":"#fff",display:"flex",alignItems:"center",justifyContent:"center",fontSize:.34*r,fontWeight:800,border:`2px solid ${n||i}`},children:(0,a.initialsFor)(e?.name||"?")}),(0,c.localPhoto)(e?.profile_image_url)&&(0,t.jsx)("img",{src:(0,c.localPhoto)(e.profile_image_url),alt:"",onError:e=>{e.currentTarget.style.display="none"},style:{position:"absolute",inset:0,width:r,height:r,borderRadius:"50%",objectFit:"cover",border:`2px solid ${n||i}`}})]})}function f({progress:e,size:r=86,color:n="#FF6B35",children:i}){let o=r/2-5,l=2*Math.PI*o;return(0,t.jsxs)("div",{style:{position:"relative",width:r,height:r},children:[(0,t.jsxs)("svg",{width:r,height:r,style:{position:"absolute",inset:0,transform:"rotate(-90deg)"},children:[(0,t.jsx)("circle",{cx:r/2,cy:r/2,r:o,fill:"none",stroke:"rgba(255,255,255,0.08)",strokeWidth:5}),(0,t.jsx)("circle",{cx:r/2,cy:r/2,r:o,fill:"none",stroke:n,strokeWidth:5,strokeLinecap:"round",strokeDasharray:`${l*Math.min(1,e)} ${l}`,style:{transition:"stroke-dasharray 0.5s ease"}})]}),(0,t.jsx)("div",{style:{position:"absolute",inset:9,display:"flex",alignItems:"center",justifyContent:"center"},children:i})]})}function u({recs:e,sentIds:n,added:i,mappedIds:a,reach:c,onSend:y,onUndo:m}){let S=(0,r.useMemo)(()=>(function({recs:e=[],sentIds:t=new Set,added:r=[],mappedIds:n=new Set,reach:i=null}){var o;let a,c,g,p=new Map,h=new Set;for(let t of[...e].sort((e,t)=>(t.priority||0)-(e.priority||0))){if(!t.bridge)continue;let e=`${t.bridge.id}|${t.profile_url||t.id}`;if(h.has(e))continue;h.add(e);let r=p.get(t.bridge.id);r||(r={bridge:t.bridge,people:[]},p.set(t.bridge.id,r)),r.people.push(t)}let f=new Map;for(let e of r){let t=e.unlocked_from_bridge_id;t&&f.set(t,[...f.get(t)||[],e])}let u=[],x=0,b=0;for(let{bridge:e,people:r}of p.values()){let n=r.filter(e=>t.has(e.id)),i=f.get(e.id)||[];b+=n.length,x+=n.reduce((e,t)=>e+(s[t.tier]||2),0),x+=i.reduce((e,t)=>e+(d[t.tier]||5),0);let o=Math.ceil(r.length/5)||1,l=0;for(;l<o-1&&r.slice(5*l,(l+1)*5).every(e=>t.has(e.id));)l++;let a=r.slice(5*l,(l+1)*5),c=a.filter(e=>t.has(e.id)).length,g=c===a.length&&l===o-1;u.push({bridge:e,people:r,stage:l+1,stages:o,targets:a,done:c,progress:a.length?c/a.length:1,complete:g,sent:n.length,added:i,value:a.filter(e=>!t.has(e.id)).reduce((e,t)=>e+(t.priority||0),0),open:{S:a.filter(e=>"S"===e.tier&&!t.has(e.id)).length,A:a.filter(e=>"A"===e.tier&&!t.has(e.id)).length}})}u.sort((e,t)=>e.complete-t.complete||(t.progress>0&&t.progress<1)-(e.progress>0&&e.progress<1)||t.progress-e.progress||t.value-e.value);let y=u.filter(e=>!e.complete).flatMap(e=>e.targets.filter(e=>!t.has(e.id)).map(t=>({person:t,cluster:e,score:(t.priority||0)*(1+.6*e.progress)}))).sort((e,t)=>t.score-e.score),m=new Set,S=[];for(let e of y){let t=e.person.profile_url||e.person.id;if(!m.has(t)&&(m.add(t),S.push(e),3===S.length))break}let k=r.filter(e=>e.unlocked_from_bridge_id).length;return{clusters:u,nextMoves:S,points:x,level:(c=((a=Math.floor(Math.sqrt(Math.max(0,o=x)/40))+1)-1)**2*40,g=a**2*40,{level:a,floor:c,next:g,progress:(o-c)/(g-c)}),sentTotal:b,addedTotal:k,newDoors:r.filter(e=>e.unlocked_from_bridge_id&&"todo"===(0,l.circleState)(e,i||{scanned:n,hidden:new Set})),clearedStages:u.reduce((e,t)=>e+(t.stage-1)+ +!!t.complete,0)}})({recs:e,sentIds:n,added:i,mappedIds:a,reach:c}),[e,n,i,a,c]),[k,j]=(0,r.useState)(null),[v,w]=(0,r.useState)(null),{level:_}=S;async function F(e,t){await y(e);let r=t.done+1,n=String(t.bridge.name||"").split(/[\s,]+/)[0];w(r>=t.targets.length?`+${s[e.tier]||2} \xb7 Stage ${t.stage} of ${n}'s circle cleared — the next 5 are up`:`+${s[e.tier]||2} \xb7 ${n}'s circle ${r}/${t.targets.length}`),setTimeout(()=>w(null),3500)}let z=S.clusters.find(e=>e.bridge.id===k);return(0,t.jsxs)("div",{style:{maxWidth:1100,margin:"0 auto",padding:"16px 20px 60px"},children:[(0,t.jsxs)("div",{style:{display:"flex",gap:16,alignItems:"center",flexWrap:"wrap",padding:16,borderRadius:12,border:p,background:"linear-gradient(135deg, rgba(255,107,53,0.10), rgba(155,89,182,0.08))"},children:[(0,t.jsxs)("div",{style:{width:64,height:64,borderRadius:16,background:"linear-gradient(135deg, #FFD700, #FF6B35)",color:"#000",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"},children:[(0,t.jsx)("div",{style:{fontSize:10,fontWeight:800},children:"LEVEL"}),(0,t.jsx)("div",{style:{fontSize:26,fontWeight:900,lineHeight:1},children:_.level})]}),(0,t.jsxs)("div",{style:{flex:1,minWidth:220},children:[(0,t.jsxs)("div",{style:{fontSize:13,color:"#dfe6e9"},children:[(0,t.jsx)("b",{children:S.points})," points · ",(0,t.jsx)("b",{children:_.next-S.points})," to level ",_.level+1]}),(0,t.jsx)("div",{style:{height:8,borderRadius:4,background:"rgba(255,255,255,0.08)",marginTop:6,overflow:"hidden"},children:(0,t.jsx)("div",{style:{height:"100%",width:`${Math.round(100*_.progress)}%`,background:"linear-gradient(90deg, #FFD700, #FF6B35)",transition:"width 0.5s"}})}),(0,t.jsx)("div",{style:{fontSize:11.5,color:"#8b9a9a",marginTop:6},children:"Points come from invites you send and people who accept — not from browsing."})]}),[[S.sentTotal,"invites sent"],[S.addedTotal,"people added"],[S.clearedStages,"stages cleared"]].map(([e,r])=>(0,t.jsxs)("div",{style:{textAlign:"center",minWidth:80},children:[(0,t.jsx)("div",{style:{fontSize:24,fontWeight:900},children:e}),(0,t.jsx)("div",{style:{fontSize:11,color:"#8b9a9a"},children:r})]},r))]}),S.newDoors.length>0&&(0,t.jsxs)("div",{style:{marginTop:12,padding:"10px 14px",borderRadius:10,border:"1px solid rgba(0,255,136,0.3)",background:"rgba(0,255,136,0.06)",fontSize:13},children:["🚪 ",(0,t.jsxs)("b",{children:[S.newDoors.length," new ",1===S.newDoors.length?"door":"doors",":"]})," people you added through a circle, whose own circle isn’t mapped yet. That’s the next degree. ",(0,t.jsx)(o.default,{href:"/setup",style:{color:"#00ff88"},children:"Map them on the Scan page →"})]}),S.nextMoves.length>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("h3",{style:{margin:"22px 0 10px",fontSize:15},children:"Next best moves"}),(0,t.jsx)("div",{style:{display:"grid",gridTemplateColumns:"repeat(auto-fit, minmax(300px, 1fr))",gap:12},children:S.nextMoves.map(({person:e,cluster:r},n)=>(0,t.jsxs)("div",{style:{padding:14,borderRadius:12,border:`1px solid ${g[e.tier]}55`,background:"rgba(255,255,255,0.03)",position:"relative"},children:[(0,t.jsxs)("div",{style:{position:"absolute",top:10,right:12,fontSize:11,fontWeight:800,color:"#FF6B35"},children:["#",n+1]}),(0,t.jsxs)("div",{style:{display:"flex",gap:10,alignItems:"center"},children:[(0,t.jsx)(h,{person:e,size:44}),(0,t.jsxs)("div",{style:{minWidth:0},children:[(0,t.jsx)("div",{style:{fontWeight:700,fontSize:14},children:e.name}),(0,t.jsx)("div",{style:{fontSize:11.5,color:"#8b9a9a",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",maxWidth:220},children:e.headline})]})]}),(0,t.jsxs)("div",{style:{fontSize:11.5,color:"#aab7b7",margin:"10px 0"},children:["via ",(0,t.jsx)("b",{style:{color:g[r.bridge.tier]},children:r.bridge.name})," · their circle ",r.done,"/",r.targets.length," this stage"]}),(0,t.jsxs)("div",{style:{display:"flex",gap:8},children:[e.profile_url&&(0,t.jsx)("a",{href:e.profile_url,target:"_blank",rel:"noopener noreferrer",style:b,children:"Open on LinkedIn"}),(0,t.jsxs)("button",{onClick:()=>F(e,r),style:x,children:["I sent an invite · +",s[e.tier]||2]})]})]},e.id))})]}),(0,t.jsx)("h3",{style:{margin:"26px 0 4px",fontSize:15},children:"Circles to work through"}),(0,t.jsxs)("div",{style:{fontSize:12,color:"#8b9a9a",marginBottom:12},children:["Each is one of your connections and the best people they know, ",5," at a time. Fill the ring to clear a stage."]}),(0,t.jsx)("div",{style:{display:"grid",gridTemplateColumns:"repeat(auto-fill, minmax(190px, 1fr))",gap:12},children:S.clusters.map(e=>{let r=k===e.bridge.id;return(0,t.jsxs)("button",{onClick:()=>j(r?null:e.bridge.id),style:{padding:12,borderRadius:12,cursor:"pointer",textAlign:"center",color:"#fff",border:r?"1px solid #FF6B35":p,background:e.complete?"rgba(0,255,136,0.06)":"rgba(255,255,255,0.03)",display:"flex",flexDirection:"column",alignItems:"center",gap:6},children:[(0,t.jsx)(f,{progress:e.progress,color:e.complete?"#00ff88":"#FF6B35",children:(0,t.jsx)(h,{person:e.bridge,size:60})}),(0,t.jsx)("div",{style:{fontWeight:700,fontSize:13,maxWidth:170,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.bridge.name}),(0,t.jsx)("div",{style:{fontSize:11,color:e.complete?"#00ff88":"#aab7b7"},children:e.complete?"Circle cleared":`Stage ${e.stage} of ${e.stages} \xb7 ${e.done}/${e.targets.length}`}),(0,t.jsx)("div",{style:{display:"flex",gap:4},children:e.targets.map(e=>(0,t.jsx)("span",{title:e.name,style:{width:12,height:12,borderRadius:"50%",border:`2px solid ${g[e.tier]||"#667"}`,background:n.has(e.id)?g[e.tier]||"#667":"transparent"}},e.id))}),(0,t.jsxs)("div",{style:{fontSize:10.5,color:"#778"},children:[e.open.S?`${e.open.S} S \xb7 `:"",e.open.A?`${e.open.A} A \xb7 `:"",e.people.length," worth adding",e.added.length?` \xb7 ★ ${e.added.length} added`:""]})]},e.bridge.id)})}),z&&(0,t.jsxs)("div",{style:{marginTop:14,padding:16,borderRadius:12,border:"1px solid rgba(255,107,53,0.4)",background:"rgba(255,107,53,0.05)"},children:[(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:10,marginBottom:10},children:[(0,t.jsx)(h,{person:z.bridge,size:40}),(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{style:{fontWeight:800},children:[z.bridge.name,"’s circle · stage ",z.stage," of ",z.stages]}),(0,t.jsxs)("div",{style:{fontSize:12,color:"#aab7b7"},children:["Ask ",z.bridge.name?.split(" ")[0]," for an intro, or invite them directly. Mark each one when it’s sent."]})]})]}),z.targets.map(e=>{let r=n.has(e.id);return(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:10,padding:"8px 0",borderTop:"1px solid rgba(255,255,255,0.05)"},children:[(0,t.jsx)(h,{person:e,size:34,ring:r?"#00ff88":void 0}),(0,t.jsxs)("div",{style:{flex:1,minWidth:0},children:[(0,t.jsxs)("div",{style:{fontWeight:600,fontSize:13},children:[e.name," ",(0,t.jsx)("span",{style:{color:g[e.tier],fontSize:11},children:e.tier})]}),(0,t.jsx)("div",{style:{fontSize:11.5,color:"#8b9a9a",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.headline})]}),e.profile_url&&(0,t.jsx)("a",{href:e.profile_url,target:"_blank",rel:"noopener noreferrer",style:b,children:"LinkedIn"}),r?(0,t.jsx)("button",{onClick:()=>m(e),style:{...b,color:"#00ff88"},children:"Sent ✓ (undo)"}):(0,t.jsxs)("button",{onClick:()=>F(e,z),style:x,children:["Sent · +",s[e.tier]||2]})]},e.id)}),z.added.length>0&&(0,t.jsxs)("div",{style:{marginTop:10,fontSize:12,color:"#00ff88"},children:["★ Added from this circle: ",z.added.map(e=>e.name).join(", ")]})]}),v&&(0,t.jsx)("div",{role:"status",style:{position:"fixed",bottom:24,left:"50%",transform:"translateX(-50%)",padding:"10px 18px",borderRadius:24,background:"linear-gradient(135deg, #FFD700, #FF6B35)",color:"#000",fontWeight:800,fontSize:13,boxShadow:"0 8px 30px rgba(0,0,0,0.5)",zIndex:50},children:v})]})}let x={padding:"7px 12px",borderRadius:8,border:"none",cursor:"pointer",fontWeight:800,fontSize:12,background:"linear-gradient(135deg, #FF6B35, #FFD700)",color:"#000"},b={padding:"7px 12px",borderRadius:8,border:p,cursor:"pointer",fontWeight:600,fontSize:12,background:"rgba(255,255,255,0.05)",color:"#dfe6e9",textDecoration:"none"};var y=e.i(2776),m=e.i(15812),S=e.i(90179),k=e.i(28867),j=e.i(86106),v=e.i(7214),w=e.i(40996);let _={S:"#FFD700",A:"#9B59B6",B:"#3498DB",C:"#95A5A6",D:"#BDC3C7"};function F(){let{userId:e,userProfile:s}=(0,m.useUser)(),d=s?.sectors||[],[a,g]=(0,r.useState)([]),[p,h]=(0,r.useState)(!0),[f,x]=(0,r.useState)("all"),[b,y]=(0,r.useState)(new Set),F=(0,k.default)(),[z,B]=(0,r.useState)([]),[C,R]=(0,r.useState)({}),[I,W]=(0,r.useState)("quest"),[A,$]=(0,r.useState)([]),[M,D]=(0,r.useState)(()=>new Set),[T,O]=(0,r.useState)(null),[E,P]=(0,r.useState)(null),[U,L]=(0,r.useState)(()=>{{let e=new URLSearchParams(window.location.search);if(e.get("groupBy"))return e.get("groupBy")}return"bridge"});(0,r.useEffect)(()=>{{let e=new URLSearchParams(window.location.search).get("bridge");e&&P(e)}},[]),(0,r.useEffect)(()=>{!i.IS_DEMO&&e&&t();async function t(){let[t,r,i]=await Promise.all([(0,n.loadNetwork)(e),fetch(`/api/outreach?userId=${e}`).then(e=>e.json()).catch(()=>({pending:[]})),(0,w.loadScanNotes)()]),o=t.degree1,s=t.degree2;$(o.filter(e=>e.unlocked_from_bridge_id)),D(new Set(s.map(e=>e.source_connection_id).filter(Boolean))),O((0,l.reachIndex)(o,s,i));let a=new Set(o.map(e=>e.profile_url)),c={};o.forEach(e=>{c[e.id]=e}),B(r.pending||[]),R(c),g(s.filter(e=>("S"===e.tier||"A"===e.tier||"B"===e.tier)&&!a.has(e.profile_url)).map(e=>{let t,r,n=c[e.source_connection_id],i=(t=parseFloat(e.power_score)||0,r=(e.headline||"").toLowerCase(),(0,S.rowCompanyScore)(e)>=S.TOP_COMPANY&&(t+=1),(d||[]).forEach(e=>{r.includes(e.toLowerCase())&&(t+=.5)}),"S"===e.tier?t*=1.5:"A"===e.tier&&(t*=1.2),t),o="S"===e.tier?50:"A"===e.tier?25:10;return{...e,bridge:n,priority:i,xp:o}}).sort((e,t)=>t.priority-e.priority)),h(!1)}},[e]);let q=(0,r.useMemo)(()=>new Set([...z,...a].filter(e=>(0,j.hasRequest)(e,F)).map(e=>e.id)),[z,a,F]),N=(0,r.useMemo)(()=>{let e=new Set,t=[];for(let r of[...z,...a]){let n=(0,v.keyFor)(r);!e.has(n)&&(0,j.hasRequest)(r,F)&&(e.add(n),t.push({...r,bridge:C[r.source_connection_id]||r.bridge||null}))}return t},[z,a,F,C]);if(i.IS_DEMO)return(0,t.jsxs)("div",{style:{minHeight:"100vh",background:"#0a0a1a",color:"rgba(255,255,255,0.7)",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:10,textAlign:"center",padding:24},children:[(0,t.jsx)("h2",{style:{margin:0,fontSize:18,fontWeight:700,color:"#fff"},children:"Not part of the demo"}),(0,t.jsx)("div",{style:{fontSize:13},children:"The public demo includes the Network Circle and Degrees views only."}),(0,t.jsx)(o.default,{href:"/",style:{fontSize:12,color:"rgba(255,255,255,0.5)",textDecoration:"none"},children:"← Back to the network"})]});let H="all"===f?a:a.filter(e=>e.tier===f);E&&(H=H.filter(e=>e.bridge?.id===E));let V={S:0,A:0,B:0};a.forEach(e=>{void 0!==V[e.tier]&&V[e.tier]++});let Y={};H.forEach(e=>{let t;Y[t="bridge"===U?e.bridge?.id||"unknown":"company"===U?(e.company||"Unknown").trim()||"Unknown":e.tier]||(Y[t]=[]),Y[t].push(e)});let K={S:0,A:1,B:2},G=Object.entries(Y).sort((e,t)=>{if("tier"===U)return(K[e[0]]||9)-(K[t[0]]||9);if("bridge"===U){let r=e[1][0]?.bridge,n=t[1][0]?.bridge,i=K[r?.tier]??9,o=K[n?.tier]??9;if(i!==o)return i-o}return t[1].length-e[1].length});function X(e){y(t=>{let r=new Set(t);return r.has(e)?r.delete(e):r.add(e),r})}return p?(0,t.jsx)("div",{style:{minHeight:"100vh",display:"flex",alignItems:"center",justifyContent:"center",background:"#0a0a1a",color:"#fff"},children:"Loading..."}):(0,t.jsxs)("div",{style:{height:"100vh",background:"#0a0a1a",color:"#fff",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',display:"flex",flexDirection:"column",overflow:"hidden"},children:[(0,t.jsxs)("header",{style:{padding:"14px 24px",borderBottom:"1px solid rgba(255,255,255,0.1)",flexShrink:0},children:[(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:12,marginBottom:10},children:[(0,t.jsxs)(o.default,{href:"/",style:{display:"flex",alignItems:"center",gap:6,color:"#888",textDecoration:"none",fontSize:13,fontWeight:600,padding:"6px 14px",borderRadius:6,background:"rgba(255,255,255,0.06)",border:"1px solid rgba(255,255,255,0.1)"},children:[(0,t.jsx)("span",{style:{fontSize:16},children:"←"})," Map"]}),(0,t.jsx)("h1",{style:{fontSize:20,fontWeight:700,margin:0,background:"linear-gradient(135deg, #FF6B35, #FFD700)",WebkitBackgroundClip:"text",WebkitTextFillColor:"transparent"},children:"Outlink"}),(0,t.jsxs)("div",{style:{display:"flex",gap:2,background:"rgba(255,255,255,0.06)",borderRadius:6,padding:2},children:[(0,t.jsx)("button",{onClick:()=>W("quest"),style:{padding:"5px 12px",borderRadius:4,border:"none",fontSize:11,fontWeight:700,cursor:"pointer",background:"quest"===I?"linear-gradient(135deg, #FFD700, #FF6B35)":"transparent",color:"quest"===I?"#000":"#FFD700"},children:"Circles"}),(0,t.jsxs)("button",{onClick:()=>W("recs"),style:{padding:"5px 12px",borderRadius:4,border:"none",fontSize:11,fontWeight:600,cursor:"pointer",background:"recs"===I?"#fff":"transparent",color:"recs"===I?"#000":"#888"},children:["To Add (",a.length,")"]}),(0,t.jsxs)("button",{onClick:()=>W("pending"),style:{padding:"5px 12px",borderRadius:4,border:"none",fontSize:11,fontWeight:600,cursor:"pointer",background:"pending"===I?"linear-gradient(135deg, #FF6B35, #FFD700)":"transparent",color:"pending"===I?"#000":"#FF6B35"},children:["Pending (",N.length,")"]})]}),(0,t.jsx)("div",{style:{marginLeft:"auto",display:"flex",gap:6},children:"recs"===I&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("button",{onClick:()=>L("tier"),style:{padding:"4px 10px",borderRadius:4,border:"none",fontSize:10,fontWeight:600,cursor:"pointer",background:"tier"===U?"rgba(255,255,255,0.15)":"rgba(255,255,255,0.05)",color:"tier"===U?"#fff":"#666"},children:"By Tier"}),(0,t.jsx)("button",{onClick:()=>L("bridge"),style:{padding:"4px 10px",borderRadius:4,border:"none",fontSize:10,fontWeight:600,cursor:"pointer",background:"bridge"===U?"rgba(255,255,255,0.15)":"rgba(255,255,255,0.05)",color:"bridge"===U?"#fff":"#666"},children:"By Bridge"}),(0,t.jsx)("button",{onClick:()=>L("company"),style:{padding:"4px 10px",borderRadius:4,border:"none",fontSize:10,fontWeight:600,cursor:"pointer",background:"company"===U?"rgba(255,255,255,0.15)":"rgba(255,255,255,0.05)",color:"company"===U?"#fff":"#666"},children:"By Company"})]})})]}),(0,t.jsx)("div",{style:{display:"quest"===I?"none":"flex",gap:6},children:[{k:"all",l:`All (${a.length})`},{k:"S",l:`S (${V.S})`,c:_.S},{k:"A",l:`A (${V.A})`,c:_.A},{k:"B",l:`B (${V.B})`,c:_.B}].map(e=>(0,t.jsx)("button",{onClick:()=>x(e.k),style:{padding:"4px 12px",borderRadius:16,border:"none",fontSize:11,fontWeight:600,cursor:"pointer",background:f===e.k?e.c||"#fff":"rgba(255,255,255,0.06)",color:f===e.k?"#000":e.c||"#888"},children:e.l},e.k))})]}),(0,t.jsx)("div",{id:"scan-bar-slot"}),"recs"===I&&b.size>0&&(0,t.jsxs)("div",{style:{padding:"10px 24px",background:"rgba(255,215,0,0.08)",borderBottom:"1px solid rgba(255,215,0,0.2)",display:"flex",alignItems:"center",gap:12,flexShrink:0},children:[(0,t.jsxs)("span",{style:{fontSize:12,color:"#FFD700",fontWeight:600},children:[b.size," selected"]}),(0,t.jsxs)("button",{onClick:function(){let e=H.filter(e=>b.has(e.id));if(0===e.length)return;if(1===e.length)return void window.open(e[0].profile_url,"_blank");let t=new Blob([`<!DOCTYPE html><html><head><title>Outlink — ${e.length} profiles</title>
|
|
1
|
+
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,2776,e=>{"use strict";var t=e.i(43476),r=e.i(15812);e.s(["default",0,function({children:e}){let{userId:n,ready:i}=(0,r.useUser)();return i&&n?e:(0,t.jsx)("div",{style:{minHeight:"100vh",display:"flex",alignItems:"center",justifyContent:"center",background:"#0a0a1a",color:"#fff",padding:24,textAlign:"center",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'},children:i?(0,t.jsxs)("div",{style:{maxWidth:420},children:[(0,t.jsx)("div",{style:{fontSize:18,fontWeight:700,marginBottom:8},children:"Can’t reach Six Degrees’ local server"}),(0,t.jsx)("div",{style:{color:"#888",fontSize:14,lineHeight:1.6},children:"The page loaded but the app behind it is not answering. If you started it from a terminal, check that window for an error, then reload this page."})]}):(0,t.jsx)("div",{style:{fontSize:18,fontWeight:600},children:"Loading…"})})}])},28867,86106,e=>{"use strict";var t=e.i(71645),r=e.i(7214);let n=Object.freeze({known:!1,sent:new Set,mine:new Map,version:0}),i=new Set,o=n,l=null,s=new Map;function d(e=o.sent,t=o.known){for(let r of(o=Object.freeze({known:t,sent:e,mine:new Map(s),version:o.version+1}),[...i]))r()}function a(e){return i.add(e),l||o.known||(l=fetch("/api/outreach").then(e=>e.ok?e.json():null).then(e=>{e&&d(new Set((e.pending||[]).map(r.keyFor)),!0)}).catch(()=>{}).finally(()=>{l=null})),()=>i.delete(e)}function c(){return o}async function g(e){let t=await fetch("/api/outreach",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}),r=await t.json().catch(()=>({}));if(!t.ok)throw Error(r.error||"Could not save that.");return r}async function p(e,{bridgeId:t}={}){let n=(0,r.keyFor)(e),i=s.has(n)?s.get(n):void 0;s.set(n,!0),d();try{return await g({action:"mark-sent",connectionId:e.id,profileUrl:e.profile_url,bridgeId:t})}catch(e){throw void 0===i?s.delete(n):s.set(n,i),d(),e}}async function h(e){let t=(0,r.keyFor)(e),n=s.has(t)?s.get(t):void 0;s.set(t,!1),d();try{return await g({action:"undo",connectionId:e.id,profileUrl:e.profile_url})}catch(e){throw void 0===n?s.delete(t):s.set(t,n),d(),e}}e.s(["REQUESTS_UNKNOWN",0,n,"hasRequest",0,function(e,t=o){if(!e)return!1;let n=(0,r.keyFor)(e);return t.mine.has(n)?t.mine.get(n):t.known?t.sent.has(n):"pending"===e.unlock_status||"sent"===e.outreach_status},"markRequested",0,p,"requestCount",0,function(e=o){let t=new Set(e.known?e.sent:[]);for(let[r,n]of e.mine)n?t.add(r):t.delete(r);return t.size},"requestsNow",0,c,"undoRequest",0,h,"watchRequests",0,a],86106),e.s(["default",0,function(){return(0,t.useSyncExternalStore)(a,c,()=>n)}],28867)},77305,e=>{"use strict";var t=e.i(43476),r=e.i(71645),n=e.i(19821),i=e.i(64745),o=e.i(22016),l=e.i(48235);let s={S:25,A:15,B:10,C:5,D:2},d={S:100,A:60,B:35,C:15,D:5};var a=e.i(5258),c=e.i(36774);let g={S:"#FFD700",A:"#9B59B6",B:"#3498DB",C:"#95A5A6",D:"#BDC3C7"},p="1px solid rgba(255,255,255,0.1)";function h({person:e,size:r=36,ring:n}){let i=g[e?.tier]||"#667";return(0,t.jsxs)("div",{style:{position:"relative",width:r,height:r,flexShrink:0},children:[(0,t.jsx)("div",{style:{width:r,height:r,borderRadius:"50%",background:i,color:e?.tier==="S"?"#000":"#fff",display:"flex",alignItems:"center",justifyContent:"center",fontSize:.34*r,fontWeight:800,border:`2px solid ${n||i}`},children:(0,a.initialsFor)(e?.name||"?")}),(0,c.localPhoto)(e?.profile_image_url)&&(0,t.jsx)("img",{src:(0,c.localPhoto)(e.profile_image_url),alt:"",onError:e=>{e.currentTarget.style.display="none"},style:{position:"absolute",inset:0,width:r,height:r,borderRadius:"50%",objectFit:"cover",border:`2px solid ${n||i}`}})]})}function f({progress:e,size:r=86,color:n="#FF6B35",children:i}){let o=r/2-5,l=2*Math.PI*o;return(0,t.jsxs)("div",{style:{position:"relative",width:r,height:r},children:[(0,t.jsxs)("svg",{width:r,height:r,style:{position:"absolute",inset:0,transform:"rotate(-90deg)"},children:[(0,t.jsx)("circle",{cx:r/2,cy:r/2,r:o,fill:"none",stroke:"rgba(255,255,255,0.08)",strokeWidth:5}),(0,t.jsx)("circle",{cx:r/2,cy:r/2,r:o,fill:"none",stroke:n,strokeWidth:5,strokeLinecap:"round",strokeDasharray:`${l*Math.min(1,e)} ${l}`,style:{transition:"stroke-dasharray 0.5s ease"}})]}),(0,t.jsx)("div",{style:{position:"absolute",inset:9,display:"flex",alignItems:"center",justifyContent:"center"},children:i})]})}function u({recs:e,sentIds:n,added:i,mappedIds:a,reach:c,onSend:y,onUndo:m}){let S=(0,r.useMemo)(()=>(function({recs:e=[],sentIds:t=new Set,added:r=[],mappedIds:n=new Set,reach:i=null}){var o;let a,c,g,p=new Map,h=new Set;for(let t of[...e].sort((e,t)=>(t.priority||0)-(e.priority||0))){if(!t.bridge)continue;let e=`${t.bridge.id}|${t.profile_url||t.id}`;if(h.has(e))continue;h.add(e);let r=p.get(t.bridge.id);r||(r={bridge:t.bridge,people:[]},p.set(t.bridge.id,r)),r.people.push(t)}let f=new Map;for(let e of r){let t=e.unlocked_from_bridge_id;t&&f.set(t,[...f.get(t)||[],e])}let u=[],x=0,b=0;for(let{bridge:e,people:r}of p.values()){let n=r.filter(e=>t.has(e.id)),i=f.get(e.id)||[];b+=n.length,x+=n.reduce((e,t)=>e+(s[t.tier]||2),0),x+=i.reduce((e,t)=>e+(d[t.tier]||5),0);let o=Math.ceil(r.length/5)||1,l=0;for(;l<o-1&&r.slice(5*l,(l+1)*5).every(e=>t.has(e.id));)l++;let a=r.slice(5*l,(l+1)*5),c=a.filter(e=>t.has(e.id)).length,g=c===a.length&&l===o-1;u.push({bridge:e,people:r,stage:l+1,stages:o,targets:a,done:c,progress:a.length?c/a.length:1,complete:g,sent:n.length,added:i,value:a.filter(e=>!t.has(e.id)).reduce((e,t)=>e+(t.priority||0),0),open:{S:a.filter(e=>"S"===e.tier&&!t.has(e.id)).length,A:a.filter(e=>"A"===e.tier&&!t.has(e.id)).length}})}u.sort((e,t)=>e.complete-t.complete||(t.progress>0&&t.progress<1)-(e.progress>0&&e.progress<1)||t.progress-e.progress||t.value-e.value);let y=u.filter(e=>!e.complete).flatMap(e=>e.targets.filter(e=>!t.has(e.id)).map(t=>({person:t,cluster:e,score:(t.priority||0)*(1+.6*e.progress)}))).sort((e,t)=>t.score-e.score),m=new Set,S=[];for(let e of y){let t=e.person.profile_url||e.person.id;if(!m.has(t)&&(m.add(t),S.push(e),3===S.length))break}let k=r.filter(e=>e.unlocked_from_bridge_id).length;return{clusters:u,nextMoves:S,points:x,level:(c=((a=Math.floor(Math.sqrt(Math.max(0,o=x)/40))+1)-1)**2*40,g=a**2*40,{level:a,floor:c,next:g,progress:(o-c)/(g-c)}),sentTotal:b,addedTotal:k,newDoors:r.filter(e=>e.unlocked_from_bridge_id&&"todo"===(0,l.circleState)(e,i||{scanned:n,hidden:new Set})),clearedStages:u.reduce((e,t)=>e+(t.stage-1)+ +!!t.complete,0)}})({recs:e,sentIds:n,added:i,mappedIds:a,reach:c}),[e,n,i,a,c]),[k,j]=(0,r.useState)(null),[v,w]=(0,r.useState)(null),{level:_}=S;async function F(e,t){await y(e);let r=t.done+1,n=String(t.bridge.name||"").split(/[\s,]+/)[0];w(r>=t.targets.length?`+${s[e.tier]||2} \xb7 Stage ${t.stage} of ${n}'s circle cleared — the next 5 are up`:`+${s[e.tier]||2} \xb7 ${n}'s circle ${r}/${t.targets.length}`),setTimeout(()=>w(null),3500)}let z=S.clusters.find(e=>e.bridge.id===k);return(0,t.jsxs)("div",{style:{maxWidth:1100,margin:"0 auto",padding:"16px 20px 60px"},children:[(0,t.jsxs)("div",{style:{display:"flex",gap:16,alignItems:"center",flexWrap:"wrap",padding:16,borderRadius:12,border:p,background:"linear-gradient(135deg, rgba(255,107,53,0.10), rgba(155,89,182,0.08))"},children:[(0,t.jsxs)("div",{style:{width:64,height:64,borderRadius:16,background:"linear-gradient(135deg, #FFD700, #FF6B35)",color:"#000",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"},children:[(0,t.jsx)("div",{style:{fontSize:10,fontWeight:800},children:"LEVEL"}),(0,t.jsx)("div",{style:{fontSize:26,fontWeight:900,lineHeight:1},children:_.level})]}),(0,t.jsxs)("div",{style:{flex:1,minWidth:220},children:[(0,t.jsxs)("div",{style:{fontSize:13,color:"#dfe6e9"},children:[(0,t.jsx)("b",{children:S.points})," points · ",(0,t.jsx)("b",{children:_.next-S.points})," to level ",_.level+1]}),(0,t.jsx)("div",{style:{height:8,borderRadius:4,background:"rgba(255,255,255,0.08)",marginTop:6,overflow:"hidden"},children:(0,t.jsx)("div",{style:{height:"100%",width:`${Math.round(100*_.progress)}%`,background:"linear-gradient(90deg, #FFD700, #FF6B35)",transition:"width 0.5s"}})}),(0,t.jsx)("div",{style:{fontSize:11.5,color:"#8b9a9a",marginTop:6},children:"Points come from invites you send and people who accept — not from browsing."})]}),[[S.sentTotal,"invites sent"],[S.addedTotal,"people added"],[S.clearedStages,"stages cleared"]].map(([e,r])=>(0,t.jsxs)("div",{style:{textAlign:"center",minWidth:80},children:[(0,t.jsx)("div",{style:{fontSize:24,fontWeight:900},children:e}),(0,t.jsx)("div",{style:{fontSize:11,color:"#8b9a9a"},children:r})]},r))]}),S.newDoors.length>0&&(0,t.jsxs)("div",{style:{marginTop:12,padding:"10px 14px",borderRadius:10,border:"1px solid rgba(0,255,136,0.3)",background:"rgba(0,255,136,0.06)",fontSize:13},children:["🚪 ",(0,t.jsxs)("b",{children:[S.newDoors.length," new ",1===S.newDoors.length?"door":"doors",":"]})," people you added through a circle, whose own circle isn’t mapped yet. That’s the next degree. ",(0,t.jsx)(o.default,{href:"/setup",style:{color:"#00ff88"},children:"Map them on the Scan page →"})]}),S.nextMoves.length>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("h3",{style:{margin:"22px 0 10px",fontSize:15},children:"Next best moves"}),(0,t.jsx)("div",{style:{display:"grid",gridTemplateColumns:"repeat(auto-fit, minmax(300px, 1fr))",gap:12},children:S.nextMoves.map(({person:e,cluster:r},n)=>(0,t.jsxs)("div",{style:{padding:14,borderRadius:12,border:`1px solid ${g[e.tier]}55`,background:"rgba(255,255,255,0.03)",position:"relative"},children:[(0,t.jsxs)("div",{style:{position:"absolute",top:10,right:12,fontSize:11,fontWeight:800,color:"#FF6B35"},children:["#",n+1]}),(0,t.jsxs)("div",{style:{display:"flex",gap:10,alignItems:"center"},children:[(0,t.jsx)(h,{person:e,size:44}),(0,t.jsxs)("div",{style:{minWidth:0},children:[(0,t.jsx)("div",{style:{fontWeight:700,fontSize:14},children:e.name}),(0,t.jsx)("div",{style:{fontSize:11.5,color:"#8b9a9a",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",maxWidth:220},children:e.headline})]})]}),(0,t.jsxs)("div",{style:{fontSize:11.5,color:"#aab7b7",margin:"10px 0"},children:["via ",(0,t.jsx)("b",{style:{color:g[r.bridge.tier]},children:r.bridge.name})," · their circle ",r.done,"/",r.targets.length," this stage"]}),(0,t.jsxs)("div",{style:{display:"flex",gap:8},children:[e.profile_url&&(0,t.jsx)("a",{href:e.profile_url,target:"_blank",rel:"noopener noreferrer",style:b,children:"Open on LinkedIn"}),(0,t.jsxs)("button",{onClick:()=>F(e,r),style:x,children:["I sent an invite · +",s[e.tier]||2]})]})]},e.id))})]}),(0,t.jsx)("h3",{style:{margin:"26px 0 4px",fontSize:15},children:"Circles to work through"}),(0,t.jsxs)("div",{style:{fontSize:12,color:"#8b9a9a",marginBottom:12},children:["Each is one of your connections and the best people they know, ",5," at a time. Fill the ring to clear a stage."]}),(0,t.jsx)("div",{style:{display:"grid",gridTemplateColumns:"repeat(auto-fill, minmax(190px, 1fr))",gap:12},children:S.clusters.map(e=>{let r=k===e.bridge.id;return(0,t.jsxs)("button",{onClick:()=>j(r?null:e.bridge.id),style:{padding:12,borderRadius:12,cursor:"pointer",textAlign:"center",color:"#fff",border:r?"1px solid #FF6B35":p,background:e.complete?"rgba(0,255,136,0.06)":"rgba(255,255,255,0.03)",display:"flex",flexDirection:"column",alignItems:"center",gap:6},children:[(0,t.jsx)(f,{progress:e.progress,color:e.complete?"#00ff88":"#FF6B35",children:(0,t.jsx)(h,{person:e.bridge,size:60})}),(0,t.jsx)("div",{style:{fontWeight:700,fontSize:13,maxWidth:170,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.bridge.name}),(0,t.jsx)("div",{style:{fontSize:11,color:e.complete?"#00ff88":"#aab7b7"},children:e.complete?"Circle cleared":`Stage ${e.stage} of ${e.stages} \xb7 ${e.done}/${e.targets.length}`}),(0,t.jsx)("div",{style:{display:"flex",gap:4},children:e.targets.map(e=>(0,t.jsx)("span",{title:e.name,style:{width:12,height:12,borderRadius:"50%",border:`2px solid ${g[e.tier]||"#667"}`,background:n.has(e.id)?g[e.tier]||"#667":"transparent"}},e.id))}),(0,t.jsxs)("div",{style:{fontSize:10.5,color:"#778"},children:[e.open.S?`${e.open.S} S \xb7 `:"",e.open.A?`${e.open.A} A \xb7 `:"",e.people.length," worth adding",e.added.length?` \xb7 ★ ${e.added.length} added`:""]})]},e.bridge.id)})}),z&&(0,t.jsxs)("div",{style:{marginTop:14,padding:16,borderRadius:12,border:"1px solid rgba(255,107,53,0.4)",background:"rgba(255,107,53,0.05)"},children:[(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:10,marginBottom:10},children:[(0,t.jsx)(h,{person:z.bridge,size:40}),(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{style:{fontWeight:800},children:[z.bridge.name,"’s circle · stage ",z.stage," of ",z.stages]}),(0,t.jsxs)("div",{style:{fontSize:12,color:"#aab7b7"},children:["Ask ",z.bridge.name?.split(" ")[0]," for an intro, or invite them directly. Mark each one when it’s sent."]})]})]}),z.targets.map(e=>{let r=n.has(e.id);return(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:10,padding:"8px 0",borderTop:"1px solid rgba(255,255,255,0.05)"},children:[(0,t.jsx)(h,{person:e,size:34,ring:r?"#00ff88":void 0}),(0,t.jsxs)("div",{style:{flex:1,minWidth:0},children:[(0,t.jsxs)("div",{style:{fontWeight:600,fontSize:13},children:[e.name," ",(0,t.jsx)("span",{style:{color:g[e.tier],fontSize:11},children:e.tier})]}),(0,t.jsx)("div",{style:{fontSize:11.5,color:"#8b9a9a",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.headline})]}),e.profile_url&&(0,t.jsx)("a",{href:e.profile_url,target:"_blank",rel:"noopener noreferrer",style:b,children:"LinkedIn"}),r?(0,t.jsx)("button",{onClick:()=>m(e),style:{...b,color:"#00ff88"},children:"Sent ✓ (undo)"}):(0,t.jsxs)("button",{onClick:()=>F(e,z),style:x,children:["Sent · +",s[e.tier]||2]})]},e.id)}),z.added.length>0&&(0,t.jsxs)("div",{style:{marginTop:10,fontSize:12,color:"#00ff88"},children:["★ Added from this circle: ",z.added.map(e=>e.name).join(", ")]})]}),v&&(0,t.jsx)("div",{role:"status",style:{position:"fixed",bottom:24,left:"50%",transform:"translateX(-50%)",padding:"10px 18px",borderRadius:24,background:"linear-gradient(135deg, #FFD700, #FF6B35)",color:"#000",fontWeight:800,fontSize:13,boxShadow:"0 8px 30px rgba(0,0,0,0.5)",zIndex:50},children:v})]})}let x={padding:"7px 12px",borderRadius:8,border:"none",cursor:"pointer",fontWeight:800,fontSize:12,background:"linear-gradient(135deg, #FF6B35, #FFD700)",color:"#000"},b={padding:"7px 12px",borderRadius:8,border:p,cursor:"pointer",fontWeight:600,fontSize:12,background:"rgba(255,255,255,0.05)",color:"#dfe6e9",textDecoration:"none"};var y=e.i(2776),m=e.i(15812),S=e.i(90179),k=e.i(28867),j=e.i(86106),v=e.i(7214),w=e.i(40996);let _={S:"#FFD700",A:"#9B59B6",B:"#3498DB",C:"#95A5A6",D:"#BDC3C7"};function F(){let{userId:e,userProfile:s}=(0,m.useUser)(),d=s?.sectors||[],[a,g]=(0,r.useState)([]),[p,h]=(0,r.useState)(!0),[f,x]=(0,r.useState)("all"),[b,y]=(0,r.useState)(new Set),F=(0,k.default)(),[z,B]=(0,r.useState)([]),[C,R]=(0,r.useState)({}),[I,W]=(0,r.useState)("quest"),[A,$]=(0,r.useState)([]),[M,D]=(0,r.useState)(()=>new Set),[T,O]=(0,r.useState)(null),[E,P]=(0,r.useState)(null),[U,L]=(0,r.useState)(()=>{{let e=new URLSearchParams(window.location.search);if(e.get("groupBy"))return e.get("groupBy")}return"bridge"});(0,r.useEffect)(()=>{{let e=new URLSearchParams(window.location.search).get("bridge");e&&P(e)}},[]),(0,r.useEffect)(()=>{!i.IS_DEMO&&e&&t();async function t(){let[t,r,i]=await Promise.all([(0,n.loadNetwork)(e),fetch(`/api/outreach?userId=${e}`).then(e=>e.json()).catch(()=>({pending:[]})),(0,w.loadScanNotes)()]),o=t.degree1,s=t.degree2;$(o.filter(e=>e.unlocked_from_bridge_id)),D(new Set(s.map(e=>e.source_connection_id).filter(Boolean))),O((0,l.reachIndex)(o,s,i));let a=new Set(o.map(e=>e.profile_url)),c={};o.forEach(e=>{c[e.id]=e}),B(r.pending||[]),R(c),g(s.filter(e=>("S"===e.tier||"A"===e.tier||"B"===e.tier)&&!a.has(e.profile_url)).map(e=>{let t,r,n=c[e.source_connection_id],i=(t=parseFloat(e.power_score)||0,r=(e.headline||"").toLowerCase(),(0,S.rowCompanyScore)(e)>=S.TOP_COMPANY&&(t+=1),(d||[]).forEach(e=>{r.includes(e.toLowerCase())&&(t+=.5)}),"S"===e.tier?t*=1.5:"A"===e.tier&&(t*=1.2),t),o="S"===e.tier?50:"A"===e.tier?25:10;return{...e,bridge:n,priority:i,xp:o}}).sort((e,t)=>t.priority-e.priority)),h(!1)}},[e]);let q=(0,r.useMemo)(()=>new Set([...z,...a].filter(e=>(0,j.hasRequest)(e,F)).map(e=>e.id)),[z,a,F]),N=(0,r.useMemo)(()=>{let e=new Set,t=[];for(let r of[...z,...a]){let n=(0,v.keyFor)(r);!e.has(n)&&(0,j.hasRequest)(r,F)&&(e.add(n),t.push({...r,bridge:C[r.source_connection_id]||r.bridge||null}))}return t},[z,a,F,C]);if(i.IS_DEMO)return(0,t.jsxs)("div",{style:{minHeight:"100vh",background:"#0a0a1a",color:"rgba(255,255,255,0.7)",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:10,textAlign:"center",padding:24},children:[(0,t.jsx)("h2",{style:{margin:0,fontSize:18,fontWeight:700,color:"#fff"},children:"Not part of the demo"}),(0,t.jsx)("div",{style:{fontSize:13},children:"The public demo includes the Network Circle and Degrees views only."}),(0,t.jsx)(o.default,{href:"/",style:{fontSize:12,color:"rgba(255,255,255,0.5)",textDecoration:"none"},children:"← Back to the network"})]});let H="all"===f?a:a.filter(e=>e.tier===f);E&&(H=H.filter(e=>e.bridge?.id===E));let V={S:0,A:0,B:0};a.forEach(e=>{void 0!==V[e.tier]&&V[e.tier]++});let Y={};H.forEach(e=>{let t;Y[t="bridge"===U?e.bridge?.id||"unknown":"company"===U?(e.company||"Unknown").trim()||"Unknown":e.tier]||(Y[t]=[]),Y[t].push(e)});let K={S:0,A:1,B:2},G=Object.entries(Y).sort((e,t)=>{if("tier"===U)return(K[e[0]]||9)-(K[t[0]]||9);if("bridge"===U){let r=e[1][0]?.bridge,n=t[1][0]?.bridge,i=K[r?.tier]??9,o=K[n?.tier]??9;if(i!==o)return i-o}return t[1].length-e[1].length});function X(e){y(t=>{let r=new Set(t);return r.has(e)?r.delete(e):r.add(e),r})}return p?(0,t.jsx)("div",{style:{minHeight:"100vh",display:"flex",alignItems:"center",justifyContent:"center",background:"#0a0a1a",color:"#fff"},children:"Loading..."}):(0,t.jsxs)("div",{style:{height:"100vh",background:"#0a0a1a",color:"#fff",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',display:"flex",flexDirection:"column",overflow:"hidden"},children:[(0,t.jsxs)("header",{style:{padding:"14px 24px",borderBottom:"1px solid rgba(255,255,255,0.1)",flexShrink:0},children:[(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:12,marginBottom:10},children:[(0,t.jsxs)(o.default,{href:"/",style:{display:"flex",alignItems:"center",gap:6,color:"#888",textDecoration:"none",fontSize:13,fontWeight:600,padding:"6px 14px",borderRadius:6,background:"rgba(255,255,255,0.06)",border:"1px solid rgba(255,255,255,0.1)"},children:[(0,t.jsx)("span",{style:{fontSize:16},children:"←"})," Map"]}),(0,t.jsx)("h1",{style:{fontSize:20,fontWeight:700,margin:0,background:"linear-gradient(135deg, #FF6B35, #FFD700)",WebkitBackgroundClip:"text",WebkitTextFillColor:"transparent"},children:"Outlink"}),(0,t.jsxs)("div",{style:{display:"flex",gap:2,background:"rgba(255,255,255,0.06)",borderRadius:6,padding:2},children:[(0,t.jsx)("button",{onClick:()=>W("quest"),style:{padding:"5px 12px",borderRadius:4,border:"none",fontSize:11,fontWeight:700,cursor:"pointer",background:"quest"===I?"linear-gradient(135deg, #FFD700, #FF6B35)":"transparent",color:"quest"===I?"#000":"#FFD700"},children:"Circles"}),(0,t.jsxs)("button",{onClick:()=>W("recs"),style:{padding:"5px 12px",borderRadius:4,border:"none",fontSize:11,fontWeight:600,cursor:"pointer",background:"recs"===I?"#fff":"transparent",color:"recs"===I?"#000":"#888"},children:["To Add (",a.length,")"]}),(0,t.jsxs)("button",{onClick:()=>W("pending"),style:{padding:"5px 12px",borderRadius:4,border:"none",fontSize:11,fontWeight:600,cursor:"pointer",background:"pending"===I?"linear-gradient(135deg, #FF6B35, #FFD700)":"transparent",color:"pending"===I?"#000":"#FF6B35"},children:["Pending (",N.length,")"]})]}),(0,t.jsx)("div",{style:{marginLeft:"auto",display:"flex",gap:6},children:"recs"===I&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("button",{onClick:()=>L("tier"),style:{padding:"4px 10px",borderRadius:4,border:"none",fontSize:10,fontWeight:600,cursor:"pointer",background:"tier"===U?"rgba(255,255,255,0.15)":"rgba(255,255,255,0.05)",color:"tier"===U?"#fff":"#666"},children:"By Tier"}),(0,t.jsx)("button",{onClick:()=>L("bridge"),style:{padding:"4px 10px",borderRadius:4,border:"none",fontSize:10,fontWeight:600,cursor:"pointer",background:"bridge"===U?"rgba(255,255,255,0.15)":"rgba(255,255,255,0.05)",color:"bridge"===U?"#fff":"#666"},children:"By Bridge"}),(0,t.jsx)("button",{onClick:()=>L("company"),style:{padding:"4px 10px",borderRadius:4,border:"none",fontSize:10,fontWeight:600,cursor:"pointer",background:"company"===U?"rgba(255,255,255,0.15)":"rgba(255,255,255,0.05)",color:"company"===U?"#fff":"#666"},children:"By Company"})]})})]}),(0,t.jsx)("div",{style:{display:"quest"===I?"none":"flex",gap:6},children:[{k:"all",l:`All (${a.length})`},{k:"S",l:`S (${V.S})`,c:_.S},{k:"A",l:`A (${V.A})`,c:_.A},{k:"B",l:`B (${V.B})`,c:_.B}].map(e=>(0,t.jsx)("button",{onClick:()=>x(e.k),style:{padding:"4px 12px",borderRadius:16,border:"none",fontSize:11,fontWeight:600,cursor:"pointer",background:f===e.k?e.c||"#fff":"rgba(255,255,255,0.06)",color:f===e.k?"#000":e.c||"#888"},children:e.l},e.k))})]}),"recs"===I&&b.size>0&&(0,t.jsxs)("div",{style:{padding:"10px 24px",background:"rgba(255,215,0,0.08)",borderBottom:"1px solid rgba(255,215,0,0.2)",display:"flex",alignItems:"center",gap:12,flexShrink:0},children:[(0,t.jsxs)("span",{style:{fontSize:12,color:"#FFD700",fontWeight:600},children:[b.size," selected"]}),(0,t.jsxs)("button",{onClick:function(){let e=H.filter(e=>b.has(e.id));if(0===e.length)return;if(1===e.length)return void window.open(e[0].profile_url,"_blank");let t=new Blob([`<!DOCTYPE html><html><head><title>Outlink — ${e.length} profiles</title>
|
|
2
2
|
<style>body{background:#0a0a1a;color:#fff;font-family:-apple-system,sans-serif;padding:24px;margin:0}
|
|
3
3
|
h2{color:#FFD700;margin-bottom:4px}p{color:#888;font-size:13px;margin-bottom:16px}
|
|
4
4
|
.btn{display:block;padding:12px 16px;margin-bottom:6px;background:rgba(255,255,255,0.06);
|
|
@@ -6,6 +6,63 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.4.11] - 2026-09-29
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- **The Social tab is a personal CRM.** Everyone you've been in touch with on LinkedIn is one contact,
|
|
13
|
+
connection or not: a list on the left with views and a search box, the person on the right (stacked
|
|
14
|
+
on a phone). The views:
|
|
15
|
+
- **Inbox:** they wrote last, or there's something unread. Unread first.
|
|
16
|
+
- **Awaiting reply:** you wrote last and nothing came back for 7 days or more (you can change the 7).
|
|
17
|
+
- **Follow-ups due:** a follow-up date of today or before.
|
|
18
|
+
- **Pipeline:** a board of the people you've given a stage.
|
|
19
|
+
- **Sent:** connection requests you sent (from your export's Invitations.csv, with the date, and the
|
|
20
|
+
note you wrote if Keep my messages is on), requests the app tracked (*Mark sent*), each accepted
|
|
21
|
+
once they're a connection and pending until then, and messages awaiting a reply.
|
|
22
|
+
- **Received:** requests to you from people who aren't connections yet.
|
|
23
|
+
- **All:** everyone and every group conversation, newest first.
|
|
24
|
+
|
|
25
|
+
Each person's panel shows their tier, company and how you're connected (and who can introduce you,
|
|
26
|
+
for 2nd degree), their conversations (the messages themselves if you keep them), requests both ways,
|
|
27
|
+
and **your own stage** (New, Contacted, Replied, Meeting, Won/Partner, Not now; it suggests one),
|
|
28
|
+
**tags**, **notes** and **next follow-up date**. Those are yours, so they're always kept, in a file of
|
|
29
|
+
their own per profile in the app's data folder, and never sent anywhere. Search covers names,
|
|
30
|
+
companies, tags and notes, and what was said while the messages are kept; in All it finds anyone in
|
|
31
|
+
your network, so you can add a note before you've written to them. **Export CSV** saves the table
|
|
32
|
+
(name, company, profile, connection, stage, tags, last contact, who wrote last, next follow-up,
|
|
33
|
+
notes) as a spreadsheet file. The list shows 100 at a time, so thousands of conversations stay quick.
|
|
34
|
+
- **Every conversation in your export, not just your connections'.** People who aren't connections
|
|
35
|
+
are listed by the name the export gives them, marked *Not a connection*, with their profile link when
|
|
36
|
+
it has one. Past (archived), current and ones only you wrote in are all there, from every folder;
|
|
37
|
+
group conversations are listed and marked; Sponsored Messages and InMails are marked, and adverts are
|
|
38
|
+
kept out of the Inbox. Unsent drafts are left out and said so.
|
|
39
|
+
- **Read my whole history**, beside *Sync messages now*: the live messages sync keeps scrolling your
|
|
40
|
+
messages list until no new conversations load (at most 60 scrolls, about 1,000 conversations), at the
|
|
41
|
+
same slow, fixed pace, with no random waits. The daily sync still reads just the top. The sync now
|
|
42
|
+
also brings in people who aren't your connections (with their name) and group conversations (without
|
|
43
|
+
any words), and each sync adds to what earlier ones found instead of replacing it.
|
|
44
|
+
- **Delete my CRM notes**, and *Forget it* asks, separately, whether to delete them too, so notes
|
|
45
|
+
aren't lost by accident.
|
|
46
|
+
|
|
47
|
+
### Changed
|
|
48
|
+
- **"Save a copy of my network" carries the Social tab too.** A new box, ticked by default,
|
|
49
|
+
adds its findings, your CRM stages, tags, notes and follow-ups, and any messages you keep,
|
|
50
|
+
so moving to a new computer brings everything. Importing the copy puts them in place and
|
|
51
|
+
keeps this computer's beside the old network. Untick it to leave them behind.
|
|
52
|
+
- **Waiting on you has become the CRM's Inbox**, and Conversations is part of the CRM.
|
|
53
|
+
- **The Social tab keeps the names of people who aren't your connections**, from your export and the
|
|
54
|
+
sync, since nothing else in the app says who they are. A connection's name still isn't copied: the
|
|
55
|
+
app has it already.
|
|
56
|
+
|
|
57
|
+
## [0.4.10] - 2026-09-29
|
|
58
|
+
|
|
59
|
+
### Changed
|
|
60
|
+
- **The scan status bar is now a notch.** A small pill hangs from the bottom of the header,
|
|
61
|
+
centred, on every page. It shows nothing while nothing runs, only a tiny dimmed *Auto scan*
|
|
62
|
+
while the all-day mode waits, and while a scan runs, what it's doing with a thin progress
|
|
63
|
+
line. Hover or click to open it: who, today's searches, the latest line, *Details* and
|
|
64
|
+
*Stop*. Other long jobs show there too, starting with recording the Galaxy's replay.
|
|
65
|
+
|
|
9
66
|
## [0.4.9] - 2026-09-29
|
|
10
67
|
|
|
11
68
|
### Added
|
|
@@ -20,6 +20,7 @@ export async function POST(request) {
|
|
|
20
20
|
let body = {};
|
|
21
21
|
try { body = await request.json(); } catch { /* no options: the defaults */ }
|
|
22
22
|
const includePhotos = body?.photos !== false;
|
|
23
|
+
const includeSocial = body?.social !== false;
|
|
23
24
|
|
|
24
25
|
const dir = dataDir();
|
|
25
26
|
sweepLeftovers(dir);
|
|
@@ -27,7 +28,7 @@ export async function POST(request) {
|
|
|
27
28
|
try {
|
|
28
29
|
const file = path.join(work, 'export.sixdegrees');
|
|
29
30
|
const made = buildExport(getDb(), {
|
|
30
|
-
dir, outFile: file, includePhotos, appVersion: APP_VERSION, schemaSql: SCHEMA_SQL,
|
|
31
|
+
dir, outFile: file, includePhotos, includeSocial, appVersion: APP_VERSION, schemaSql: SCHEMA_SQL,
|
|
31
32
|
});
|
|
32
33
|
const fd = openSync(file, 'r');
|
|
33
34
|
rmSync(work, { recursive: true, force: true });
|
|
@@ -422,8 +422,12 @@ const ACTIONS = {
|
|
|
422
422
|
company: { flag: '--company', needsName: true, label: 'Scanning' },
|
|
423
423
|
// Photos an older version kept as links to LinkedIn: saved here, once each.
|
|
424
424
|
// No browser, no search; every scan does the same at its end.
|
|
425
|
-
// Experimental, for the Social tab: your messages list, once (who, when, unread;
|
|
425
|
+
// Experimental, for the Social tab: your messages list, once (who, when, unread; the
|
|
426
|
+
// newest message's words only while Keep my messages is on).
|
|
426
427
|
messages: { flag: '--messages', label: 'Reading your messages list' },
|
|
428
|
+
// The same, scrolling until the whole list has loaded (60 scrolls or about
|
|
429
|
+
// 1,000 conversations at most), for the Social tab's "Read my whole history".
|
|
430
|
+
'messages-full': { flag: '--messages --full-history', label: 'Reading your whole messages history' },
|
|
427
431
|
photos: { flag: '--save-photos', label: 'Saving profile photos to this computer' },
|
|
428
432
|
};
|
|
429
433
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { rmSync } from 'node:fs';
|
|
2
|
+
import { cleanCrm, patchCrm, emptyCrm } from '../../../../lib/social-crm';
|
|
3
|
+
import { socialFiles, readJson, writeJsonAtomic } from '../../../../lib/social-store';
|
|
4
|
+
|
|
5
|
+
// The Social tab's CRM: your own stage, tags, notes and next follow-up for each
|
|
6
|
+
// person, in crm-<profile>.json in the data folder (lib/social-crm.js has the
|
|
7
|
+
// shape). Yours, so always kept, whatever Keep my messages says; never sent
|
|
8
|
+
// anywhere, and not in "Save a copy of my network".
|
|
9
|
+
//
|
|
10
|
+
// GET the whole store
|
|
11
|
+
// PATCH { key, set: { stage?, tags?, notes?, followUp? } } one person's
|
|
12
|
+
// fields (null or '' clears one), or { settings: { awaitDays } }
|
|
13
|
+
// DELETE the file gone: only when you've said so, on its own confirm
|
|
14
|
+
|
|
15
|
+
export async function GET() {
|
|
16
|
+
const files = socialFiles();
|
|
17
|
+
if (!files) return Response.json({ crm: emptyCrm() });
|
|
18
|
+
return Response.json({ crm: cleanCrm(readJson(files.crm, null)) });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function PATCH(request) {
|
|
22
|
+
const files = socialFiles();
|
|
23
|
+
if (!files) return Response.json({ error: 'Pick a profile first.' }, { status: 400 });
|
|
24
|
+
let body;
|
|
25
|
+
try { body = await request.json(); } catch { return Response.json({ error: 'That isn’t readable.' }, { status: 400 }); }
|
|
26
|
+
// Read, change one person, write whole: two quick edits in a row can't
|
|
27
|
+
// leave half a file, and the second sees the first (Node runs one at a time).
|
|
28
|
+
const next = patchCrm(readJson(files.crm, null), { key: body?.key, set: body?.set, settings: body?.settings });
|
|
29
|
+
writeJsonAtomic(files.crm, next);
|
|
30
|
+
return Response.json({ ok: true, entry: body?.key ? next.people[body.key] || null : null, settings: next.settings });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function DELETE() {
|
|
34
|
+
const files = socialFiles();
|
|
35
|
+
if (files) rmSync(files.crm, { force: true });
|
|
36
|
+
return Response.json({ ok: true });
|
|
37
|
+
}
|
|
@@ -7,11 +7,14 @@ import { socialFiles, readJson, writeJsonAtomic, readMessages, deleteMessages }
|
|
|
7
7
|
// two files and why they're apart).
|
|
8
8
|
//
|
|
9
9
|
// GET the list, no words: who, when, who wrote last,
|
|
10
|
-
// unread, how many, the thread's link
|
|
10
|
+
// unread, how many, the thread's link; with the
|
|
11
|
+
// requests both ways and people's names, and the
|
|
12
|
+
// requests' notes when the messages are kept
|
|
11
13
|
// GET ?id=<id> | ?with=<key> one thread, a page at a time (before, limit):
|
|
12
14
|
// its messages only if they're kept
|
|
13
15
|
// GET ?q=<words> the conversations whose kept messages say that
|
|
14
16
|
// POST an import's messages, in parts
|
|
17
|
+
// PUT an import's request notes
|
|
15
18
|
// DELETE the messages gone, the list kept
|
|
16
19
|
//
|
|
17
20
|
// Nothing here goes anywhere but this computer's browser: no route of the app
|
|
@@ -25,14 +28,20 @@ function state() {
|
|
|
25
28
|
if (!files) return null;
|
|
26
29
|
const social = readJson(files.social, {}) || {};
|
|
27
30
|
const keep = social.keepMessages === true;
|
|
28
|
-
const kept = keep ? readMessages(files.messages) : { threads: {}, previews: {} };
|
|
29
|
-
|
|
31
|
+
const kept = keep ? readMessages(files.messages) : { threads: {}, previews: {}, invites: {} };
|
|
32
|
+
const names = { ...(social.names || {}) };
|
|
33
|
+
for (const [link, v] of Object.entries(social.liveOthers || {})) if (v?.name && !names[link]) names[link] = v.name;
|
|
34
|
+
for (const g of social.liveGroups || []) for (const [link, n] of Object.entries(g.names || {})) if (!names[link]) names[link] = n;
|
|
35
|
+
const list = conversationList(social.conversations, social.live, { others: social.liveOthers, groups: social.liveGroups, names: social.names });
|
|
36
|
+
return { files, social, keep, kept, names, list };
|
|
30
37
|
}
|
|
31
38
|
|
|
32
39
|
/** A conversation's kept messages, oldest first, with the live sync's newest one after them when it's newer. */
|
|
33
40
|
function messagesOf(c, kept) {
|
|
34
41
|
const msgs = kept.threads[c.id]?.messages || [];
|
|
35
|
-
|
|
42
|
+
// The sync's newest message is kept by the link it gave: for someone who
|
|
43
|
+
// isn't a connection that can differ from the export's (liveKey).
|
|
44
|
+
const preview = !c.group && c.people.length === 1 ? kept.previews[c.people[0]] || (c.liveKey && kept.previews[c.liveKey]) : null;
|
|
36
45
|
if (preview?.text && (!msgs.length || (preview.t || 0) > (msgs[msgs.length - 1].t || 0))) return [...msgs, preview];
|
|
37
46
|
return msgs;
|
|
38
47
|
}
|
|
@@ -70,7 +79,13 @@ export async function GET(request) {
|
|
|
70
79
|
title: s.kept.threads[c.id]?.title || '',
|
|
71
80
|
hasText: s.keep && messagesOf(c, s.kept).length > 0,
|
|
72
81
|
}));
|
|
73
|
-
return Response.json({
|
|
82
|
+
return Response.json({
|
|
83
|
+
keepMessages: s.keep,
|
|
84
|
+
conversations,
|
|
85
|
+
invitations: Array.isArray(s.social.invitations) ? s.social.invitations : [],
|
|
86
|
+
names: s.names,
|
|
87
|
+
inviteNotes: s.keep ? s.kept.invites || {} : {},
|
|
88
|
+
});
|
|
74
89
|
}
|
|
75
90
|
|
|
76
91
|
/** One message as it's kept, or null when it isn't one. */
|
|
@@ -97,8 +112,9 @@ export async function POST(request) {
|
|
|
97
112
|
}
|
|
98
113
|
let into;
|
|
99
114
|
if (part === 0) {
|
|
100
|
-
// A new import replaces the export's messages; the live sync's previews
|
|
101
|
-
|
|
115
|
+
// A new import replaces the export's messages; the live sync's previews
|
|
116
|
+
// and the requests' notes (PUT) stay.
|
|
117
|
+
into = { threads: {}, previews: s.kept.previews || {}, invites: s.kept.invites || {} };
|
|
102
118
|
} else {
|
|
103
119
|
into = readJson(s.files.incoming, null);
|
|
104
120
|
if (!into?.threads) return Response.json({ error: 'The start of this import is missing. Choose the export folder again.' }, { status: 409 });
|
|
@@ -114,7 +130,8 @@ export async function POST(request) {
|
|
|
114
130
|
}
|
|
115
131
|
}
|
|
116
132
|
if (part === parts - 1) {
|
|
117
|
-
|
|
133
|
+
// The notes may have changed while the parts came in: the file's win.
|
|
134
|
+
writeJsonAtomic(s.files.messages, { ...into, invites: readMessages(s.files.messages).invites || into.invites || {} });
|
|
118
135
|
rmSync(s.files.incoming, { force: true });
|
|
119
136
|
} else {
|
|
120
137
|
writeJsonAtomic(s.files.incoming, into);
|
|
@@ -122,6 +139,25 @@ export async function POST(request) {
|
|
|
122
139
|
return Response.json({ ok: true, part, parts, done: part === parts - 1 });
|
|
123
140
|
}
|
|
124
141
|
|
|
142
|
+
// An import's request notes: { invites: { id: note } }, the words sent with a
|
|
143
|
+
// connection request (Invitations.csv's Message). Written by a person like a
|
|
144
|
+
// message, so kept only while Keep my messages is on, in the same file, and
|
|
145
|
+
// gone with it. They replace the notes kept before: an export has all of them.
|
|
146
|
+
export async function PUT(request) {
|
|
147
|
+
const s = state();
|
|
148
|
+
if (!s) return Response.json({ error: 'Pick a profile first.' }, { status: 400 });
|
|
149
|
+
if (!s.keep) return Response.json({ error: 'Keep my messages is off, so nothing was saved.' }, { status: 409 });
|
|
150
|
+
let body;
|
|
151
|
+
try { body = await request.json(); } catch { return Response.json({ error: 'That isn’t readable.' }, { status: 400 }); }
|
|
152
|
+
const invites = {};
|
|
153
|
+
for (const [id, note] of Object.entries(body?.invites && typeof body.invites === 'object' ? body.invites : {}).slice(0, 50000)) {
|
|
154
|
+
if (id && id.length <= 400 && typeof note === 'string' && note.trim()) invites[id] = note.slice(0, 2000);
|
|
155
|
+
}
|
|
156
|
+
const kept = readJson(s.files.messages, {}) || {};
|
|
157
|
+
writeJsonAtomic(s.files.messages, { threads: kept.threads || {}, previews: kept.previews || {}, invites });
|
|
158
|
+
return Response.json({ ok: true, notes: Object.keys(invites).length });
|
|
159
|
+
}
|
|
160
|
+
|
|
125
161
|
// The words gone, the list and the numbers kept: what switching Keep my
|
|
126
162
|
// messages off does (the PATCH that turns it off deletes them as well).
|
|
127
163
|
export async function DELETE() {
|