{"id":29168355,"url":"https://github.com/pocket/web-client","last_synced_at":"2026-06-06T05:32:09.708Z","repository":{"id":279468534,"uuid":"292395839","full_name":"Pocket/web-client","owner":"Pocket","description":"The user facing web client for Pocket","archived":false,"fork":false,"pushed_at":"2025-05-22T19:25:38.000Z","size":34014,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-05-22T19:44:34.494Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://getpocket.com","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Pocket.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-09-02T21:13:11.000Z","updated_at":"2025-05-22T19:24:29.000Z","dependencies_parsed_at":"2025-02-25T18:48:44.153Z","dependency_job_id":"30680c23-60d9-472a-b9eb-233b18e69ea7","html_url":"https://github.com/Pocket/web-client","commit_stats":null,"previous_names":["pocket/web-client"],"tags_count":1050,"template":false,"template_full_name":null,"purl":"pkg:github/Pocket/web-client","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pocket%2Fweb-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pocket%2Fweb-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pocket%2Fweb-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pocket%2Fweb-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Pocket","download_url":"https://codeload.github.com/Pocket/web-client/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pocket%2Fweb-client/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262941557,"owners_count":23388150,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-07-01T10:07:21.179Z","updated_at":"2025-12-12T02:30:49.086Z","avatar_url":"https://github.com/Pocket.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ⚠️ Notice: Pocket Has Been Shut Down\n\nAs of July 8, 2025, Pocket has been shut down and is no longer under active development.\n\nThis repository is preserved for historical reference only and will not receive further updates, bug fixes, or security patches.\n\nFor more details, see [Mozilla’s announcement](https://support.mozilla.org/en-US/kb/future-of-pocket).\n\n# Web Client\n\n\u003e Reaching for the promise of a healthy internet.\n\nThe \"web-client\" code repository represents the front end code for a unified Pocket user experience that is not siloed into discover vs app. For Pocket to truly \"Capture the Magic of the Web\" we need to take a holistic approach to what the value of Pocket is.\n\n\n---\n\n## Installation\n\n#### Authenticating With Github Package Registry\n\nThis package is published to Github Package Registry. GHPR uses the same syntax/API as NPM, using a `package.json` file and the same NPM commands. The first time you interact with GHPR, you’ll have to authenticate with it:\n\nPrepare your username and password\n- Your username is your Github username\n- For your password, if you have not gone through this process before, you must generate a Personal Access Token through Github.\n  - Check for existing:\n    - Check your `~/.npmrc` file for an existing access token\n  - Create New:\n      - In github, go to your avatar in top right corner, select Settings\n      - Go to Developer Settings, and click Personal Access Token\n      - Create new token, checking the \"repo\", \"read:packages\" and \"write:packages\" scopes\n- When prompted for password, paste in the copied token\n\nLogin\n- Open a terminal and enter `npm login --registry=https://npm.pkg.github.com/`\n- Enter your username and password\n\n---\n\n## Structures\n\n#### Folders\nThe site content is represented by five primary folders under the `/src` directory\n\n`/pages`\n\n This is a NEXTjs convention that provides automatic routing.  Each page of the site will be represented here.  There should be a folder representing the page which contains an `index.js` file as a top level and additional files representing any _page specific_ components or layouts\n\n`/common`\n\nThis will contain _site specific_ contstants and utilities.  No visual components should be placed here.\n\n`/components`\n\nThis should contain _site specific_, components.\n\n`/connectors`\n\nThis should contain _site specific_, shared state\n\n`/containers`\n\nThese are where _page level_ containers will live along with co-located state files\n\n#### Conventions\n\nThe `/containers` folder contains a `layouts` folder. The components in this folder are meant to be wrappers, that every page should leverage.  They provide a space to provide site wide functionality.  By default they have the following:\n\n- Ability to set title (optional - defaults to `Pocket`)\n- Nav\n- Header\n- Footer\n\n## Localization\n\n### Library\nWe use i18n (specificaly react-i18n) to handle localization throughout the project.  The library provides two patterns a `useTranslation` hook and a `\u003cTrans\u003e` component. We prefer the `useTranslation` hook in almost all instances.  If the translated block contains markup such as links or images the `\u003cTrans\u003e` component can be used for clarity, but it has limitations you should be aware of.\n\n- `useTranslations`: https://react.i18next.com/latest/usetranslation-hook\n- `Trans`: https://react.i18next.com/latest/trans-component\n\n\u003e _IMPORTANT_ — At present, this library is initialized into our nextJS instance via a third-party library called `next-i18next`.  This is the recommended way to do this in nextJS using the `pages` pattern.  It does mean when you are importing `useTranslation` or `Trans` you should do so from `next-i18next` and _NOT_ directly from `react-i18next`.  The reason for this is that nextJS is universal and `next-i18next` does some additional work for us to support server side rendering (ssr).\n\n### Translations\nTranslations are handled by Smartling via a Github integration.  This should make it a more streamlined to write your code normally and then run some simple scripts to prep them and trigger a job on Smartling. Once that job on Smartling has been authorized and completed, Smartling will submit a new PR back to our repo with all the translated files.\n\n1) As you write code, when you are including a new string, be sure to wrap it appropriately and use a namespace. Namespace is seperated by a `:` This helps us break up translations so we can load only what we need.\n```javascript\nmycoolnamespace:mystring-key\n```\n2) We use default fallbacks, so your code will be fine to ship so long as all stakeholders are aware that english will show up across all locales until the translations come back.\n```javascript\nt(`mycoolnamespace:mystring-key`, 'My default string that will be translated`)\n```\n3) In order for a string to be eligible for translation, you need to wrap it appropriately and we will end up picking it up with a parsing script.\n\n```js\nimport { useTranslation } from 'next-i18next'\n\nexport const Nav = ()=\u003e{\n  const { t } = useTranslation()\n  return \u003cdiv\u003e{t(`nav:lists`, 'Lists')}\u003c/div\u003e\n}\n```\n\n4) Once you are ready to make your PR, running `npm run locale:parse` from the root directory will add new string to the `en.json` which you will be able to see as code changes in git.  Once those changes are merged into main, Smartling will automatically see and create a job for starting translations.\n\nPlease use `locale` as the type and whatever we are operating on.\n```\nlocales(nav): adding updates for shared lists\n```\n\n5) Once the PR from Smartling comes back it can be merged and other locales will pick up the appropriate language and there will be much rejoicing.\n\n\n\n---\n\n## Server\nWe are using standard nextJS to handle servers side building/rendering/caching.\n\n#### Pages\nWhen serving a page, it should live in the `pages` directory. If you have no special requirements, _**nextJS will automatically serve it**_.\n\nWe prefer `getStaticProps` props over `getServerProps` to help with caching and reducing server load. You can read up on the nuances here: https://nextjs.org/docs/basic-features/data-fetching\n\n```javascript\nimport MyContainer from 'containers/my-container/my-container'\n\n// This makes this a build time static page.\nexport async function getStaticProps() {\n  return { props: { namespacesRequired: ['common'], subset: 'unread' } }\n}\n\nexport default MyContainer\n\n```\n---\n\n## Local Development\n\n#### Local Installation\n\nClone this repo locally. Then simply:\n\n```bash\ncd web-client\nnpm install\n```\n\n#### Setting up local certificate\n\nChromium browser now require SSL to access cookies that will allow the site to auth and run locally.\n\nThere are some challenges to doing this properly but we can streamline it quite a bit with a package called [mkcert](https://github.com/FiloSottile/mkcert). Visit the site and follow instructions to install it on your machine (for both chrome and firefox)\n\nOnce installed run the following to install a valid certificate on your machine.:\n```bash\nmkcert -install\n```\n\nFinalize things by running the following command from the root of the web-client folder. This will generate the certificates that the `server.local` is expecting.\n```bash\nmkcert localhost.web-client.getpocket.com\n```\n\n#### Running Locally\n\nTo run the `web-client` site locally :\n\n```bash\nnpm run dev\n```\nYou will need to update your hosts file to point localhost (127.0.0.1) to the hostname `localhost.web-client.getpocket.com`. Some of our third party API keys are only enabled for `getpocket.com`, and so will not work at `localhost`. See: https://linuxize.com/post/how-to-edit-your-hosts-file/\n\nThe discover pages will be deployed locally on `localhost.web-client.getpocket.com`.\n\n### Storybook\n\nThis app also has an instance of Storybook, for developing components that will be shared inside of this repo.\n\nTo run Storybook (launches window at `localhost.web-client.getpocket.com` with a random port):\n\n```bash\nnpm run storybook\n```\n\n### Testing\n\n#### Unit Tests\n\nFor unit testing, we use `jest` and `react-test-library` for rendering. The primary goal with our unit tests is to flex an isolated chunk of code (e.g. a function, component, or class), and ensure that it satisfies all requirements - verify expected output, given possible inputs. It also serves as documentation for expected behavior of that unit.\n\nUnit test files are co-located alongside our JS files, named as `*.spec.js`. Any file ending in `.spec.js` in the `src` folder will get picked up by mocha and included in tests.\n\nUnit tests can be run locally and are also run via CI as a requirement for PR merging. To run unit tests:\n\n```bash\nnpm test\n```\n\n##### Test Users\n\nTests that verify the logged-in user experience will require user auth. Since we don't want to store passwords in Git, the password for test user accounts will need to be set/stored on your own machine. Test users should all use the same password, and be created using the `frontend-test@getpocket.com` alias and \"plus sign\" gmail syntax, e.g. `frontend-test+fran@getpocket.com`. The password should be set within your `.bash_profile` file like:\n\n```bash\nexport CYPRESS_POCKET_TEST_USER_SECRET=\"get the password from a fellow dev\"\n```\n\nThis will make a Cypress environment variable available as `POCKET_TEST_USER_SECRET` that can be used for login credentials. Usernames are stored in the Cypress support folder.\n\n*NOTE: We cannot currently log test users in programmatically, and so test user login is currently incomplete*\n\n---\n\n## Deployment\n\n#### Production Release\nProduction release will happen automatically when a PR is merged to `main`.  Main is a protected branch and can only be modified with an approved PR.\n\n---\n## Contributing\n\n#### Next.js\n\nThe `web-client` repo is set up to use [NEXT.js](https://nextjs.org/docs/) for development and deployment.\n\n#### Pocket Web UI\n\nFor shared components and consistent styling we leverage `web-ui` of Pocket.  This provides us with global styles, resets, icons, design tokens, typography, colors, and shared components.  To avoid duplication, all components that will be shared across multiple properties will be pulled in from there: [web-ui](https://github.com/Pocket/web-ui)\n\n#### PrettierJS\n\nThis project uses PrettierJS to help keep code formatting consistent. It's recommended that you set up your IDE to support Prettier. Read more here: https://prettier.io/docs/en/editors.html\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpocket%2Fweb-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpocket%2Fweb-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpocket%2Fweb-client/lists"}