{"action":"created","issue":{"url":"https://api.github.com/repos/impress-org/givewp-campaigns/issues/210","repository_url":"https://api.github.com/repos/impress-org/givewp-campaigns","labels_url":"https://api.github.com/repos/impress-org/givewp-campaigns/issues/210/labels{/name}","comments_url":"https://api.github.com/repos/impress-org/givewp-campaigns/issues/210/comments","events_url":"https://api.github.com/repos/impress-org/givewp-campaigns/issues/210/events","html_url":"https://github.com/impress-org/givewp-campaigns/issues/210","id":524830555,"node_id":"MDU6SXNzdWU1MjQ4MzA1NTU=","number":210,"title":"epic: post-prototype frontend foundation","user":{"login":"knowler","id":6908001,"node_id":"MDQ6VXNlcjY5MDgwMDE=","avatar_url":"https://avatars3.githubusercontent.com/u/6908001?v=4","gravatar_id":"","url":"https://api.github.com/users/knowler","html_url":"https://github.com/knowler","followers_url":"https://api.github.com/users/knowler/followers","following_url":"https://api.github.com/users/knowler/following{/other_user}","gists_url":"https://api.github.com/users/knowler/gists{/gist_id}","starred_url":"https://api.github.com/users/knowler/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/knowler/subscriptions","organizations_url":"https://api.github.com/users/knowler/orgs","repos_url":"https://api.github.com/users/knowler/repos","events_url":"https://api.github.com/users/knowler/events{/privacy}","received_events_url":"https://api.github.com/users/knowler/received_events","type":"User","site_admin":false},"labels":[{"id":1511083731,"node_id":"MDU6TGFiZWwxNTExMDgzNzMx","url":"https://api.github.com/repos/impress-org/givewp-campaigns/labels/Epic","name":"Epic","color":"3E4B9E","default":false,"description":null}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":9,"created_at":"2019-11-19T07:40:08Z","updated_at":"2019-11-27T20:20:16Z","closed_at":null,"author_association":"MEMBER","body":"Currently, we have a working prototype which has served its purpose very well for the WCUS demonstration and will continue to do so until we release an alpha version.\r\n\r\nUnfortunately, the prototype is too focused on the builder view and is structured in a way that does not account for other parts of the application or other contexts that the plugin will provide experiences for (i.e. campaigns outside of the builder). We need to shift a few things around in order to achieve the goals of the MVP, as well, change how we are managing the application state. \r\n\r\nNote that everything that is mentioned below has been confirmed to work already, it’s just a matter of implementing it all in our project.\r\n\r\n## Frontend tasks\r\n\r\n- [ ] Create _four_ necessary clients. _Time estimate: 1 hour_\r\n    1. _Admin_: This is the view we have most worked on already. It includes a manager for managing campaigns in bulk and the builder for creating/modifying a single campaign.\r\n    2. _Landing_: This is the client for campaigns with landing pages.\r\n    3. _Embed_: This is for if the user decides to embed a campaign.\r\n    4. _Gutenberg Block_: This is for embedding the block within a page or post made in the Gutenberg editor. This might rely on the embed client internally.\r\n- [ ] Use Context (and Apollo?) instead of Redux for state management.\r\n    - [Colocating the state] for certain views and components makes the state management less complex. We can leverage hooks and the Context API for this.\r\n    - I think it could be valuable to try and use Apollo Client as well. We don’t have a GraphQL backend (yet?), but we can use local resolvers with REST API requests/cache. @JasonTheAdams what do you think about this?\r\n        - You can also easily mock a data source this way too, by caching static datasets.\r\n- [x] Switch `@givewp/components` to `@givewp/ui` and move client/component specific UI elements to their own namespace (i.e. subdirectory with exports) within this workspace. _Time estimate for all sub-tasks: 1 hour_\r\n    - `@givewp/ui/primitives` will have UI primitives that can either be used as the basis of the namespaced component libraries or they can be used standalone (i.e. layout primitives like `Stack`, `Grid`, can live here).\r\n    - `@givewp/ui/admin` will have all of the UI components used by `@givewp/admin`.\r\n    - `@givewp/ui/campaign` will have all of the UI components used by `@givewp/campaign`.\r\n    - Why not house these specific component in the workspaces that they are associated with? Since they are highly used within those workspaces, it is a bit of a pain to use relative paths to reference them.\r\n- [ ] Use a form controller library for controlling form inputs/state in both the builder and the campaign.\r\n    - This means we don’t have to pass `onChange` events for individual input fields. As well, the form can detect changes and dispatch them at the right time to update the preview.\r\n\r\n### Admin client\r\n\r\n_Time estimate: 2 hours — this is relatively simple once we separate out the builder + campaign into their own workspaces/components_\r\n\r\nFor the most part, the admin client itself is an app shell with a (hash) router. Its state does not need to be complex: it should just have a control for whether it is nested in the WordPress admin UI or filling the viewport and it can also be used for caching common datasets between the Dashboard and the Builder.\r\n\r\n- [x] Move the Router to the top level of the app.\r\n    - Currently, the router is for the campaign settings tabs, but really this should be controlled with a URL search param (or not at all).\r\n    - `/manage` (default) and `/build` will control what view is currently active. We can use URL search params to provide additional context for those views (e.g. `/manage?s=Pandas` would tell the dashboard to only list Campaigns that met that search requirement; `/build?id=11a7c267-21d4-437c-956a-53575dcf8c5a` would open the builder for the corresponding Campaign).\r\n\r\n[Colocating the state]: https://kentcdodds.com/blog/state-colocation-will-make-your-react-app-faster\r\n\r\n#### Manager view\r\n\r\n_Time estimate: 30 minutes for scaffolding — the actual development of this component is a separate concern_\r\n\r\n- [ ] Begin working on this view\r\n\r\n#### Builder view\r\n\r\n_Estimate: the scaffolding step shouldn’t be too difficult — its more so the changes that need to take places as a result of moving the router up and implementing a form controller._\r\n\r\n- [x] With the router moving to the top of the admin client, a different solution for the settings panels will need to be implmented. I suggest `@reach/tabs`.\r\n\r\n### Campaign component\r\n\r\n_Estimate: this is certainly less component than the builder task, however, it does also include functionality that hasn’t existed yet (i.e. a working campaign outside of the builder)._\r\n\r\nThis is the component that needs the most work in my opinion. Currently, it does not work outside of the builder, so we will need to break it out and get it working on its own, but with enhancements when used within the builder context.\r\n\r\n- [ ] Create a workspace `@givewp/campaign` for the component\r\n    - This component is being used by all the clients.\r\n- [ ] Get this working in a builder-less context + reimplment in the builder."},"comment":{"url":"https://api.github.com/repos/impress-org/givewp-campaigns/issues/comments/559238134","html_url":"https://github.com/impress-org/givewp-campaigns/issues/210#issuecomment-559238134","issue_url":"https://api.github.com/repos/impress-org/givewp-campaigns/issues/210","id":559238134,"node_id":"MDEyOklzc3VlQ29tbWVudDU1OTIzODEzNA==","user":{"login":"knowler","id":6908001,"node_id":"MDQ6VXNlcjY5MDgwMDE=","avatar_url":"https://avatars3.githubusercontent.com/u/6908001?v=4","gravatar_id":"","url":"https://api.github.com/users/knowler","html_url":"https://github.com/knowler","followers_url":"https://api.github.com/users/knowler/followers","following_url":"https://api.github.com/users/knowler/following{/other_user}","gists_url":"https://api.github.com/users/knowler/gists{/gist_id}","starred_url":"https://api.github.com/users/knowler/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/knowler/subscriptions","organizations_url":"https://api.github.com/users/knowler/orgs","repos_url":"https://api.github.com/users/knowler/repos","events_url":"https://api.github.com/users/knowler/events{/privacy}","received_events_url":"https://api.github.com/users/knowler/received_events","type":"User","site_admin":false},"created_at":"2019-11-27T20:20:16Z","updated_at":"2019-11-27T20:20:16Z","author_association":"MEMBER","body":"cc: @DevinWalker\r\n\r\nOk, so an update here. I’m most likely going to resolve this epic and any related issues in one massive PR that I already have quite a bit of progress on:\r\n\r\n- [x] Router is implemented\r\n- [x] Builder view is separated\r\n- [ ] Manager view is implemented\r\n\t- [x] Header page with working \"New Campaigns\" button\r\n    - [ ] Manager lists campaigns in a table\r\n- [x] UI primitives package is created\r\n- [x] Admin UI package is created\r\n- [ ] The Campaign component is extracted and visibly functions on its own (new functionality, but nothing new MVP scope-wise)\r\n- [ ] Apollo/Context API is used \"in the place\" of Redux.\r\n\t- [x] Context API is used for view/component specific state\r\n\t- [ ] Apollo is used for sending and retrieving data to and from the server (new functionality, but nothing new MVP scope-wise)\r\n- [x] Final Form is implemented\r\n\t- [x] Final Form field adapter is implemented\r\n\t- [ ] Our form control components use a common API so that we can just use one field adapter\r\n\r\nNote that a lot of this isn’t refactoring, even though refactoring is taking place in order to implement the MVP requirements.\r\n\r\nFurther explanation for why some of these steps have been taken:\r\n\r\n<details><summary>Some definitions for clarity</summary>\r\n\r\n* _Manager_ — the default, list view that the user is presented with when they navigate to the \"Campaigns\" sub-page in the Donations menu. \r\n    * I am open to change the name of this, but \"List\" seems a little too abstract and doesn’t fully communicate the capability of the user as far as their ability to manage many campaigns from a high level (i.e. create, delete, change some high-level options).\r\n* _Builder_ — the campaign builder. This lets the user change the fine details of a single campaign.\r\n* _Campaign_ — the component that is the campaign. \r\n    * This same component will be reused in various contexts such as the Builder (a part of the `admin-campaigns` client), its own landing page (a part of the `landing` client), its own `emebed` client, a Gutenberg block.\r\n* _client_ — a self contained React app which is loaded as a part of a single PHP view. \r\n    * For example, the \"Campaigns\" sub-page loads a client called `admin-campaigns` or the \"Reports\" sub-page will load a client called `admin-reports` or for the public facing landing pages, a client called `landing` will be used.\r\n\r\n</details>\r\n\r\n<details><summary>Why are we replacing Redux?</summary>\r\n\r\nWe actually were not using Redux a ton in the first place, however, there was a lot of boilerplate for it despite that. Using the Context API is simpler since it keeps related state together and is much easier to implement (less boilerplate). Also, we aren’t really replacing it, we are just using the Context API for view/component specific state how would probably would have alongside it and then opting to use Apollo for remote data sending/retrieving (something that wasn't implemented yet). Better tools for the job — and way less files/boilerplate to do so.\r\n\r\n</details>\r\n\r\n<details><summary>Why are we using Final Form as a form controller?</summary>\r\n\r\nForms are hard and React itself doesn’t solve that outside of advising you to make sure your forms are controlled — that React is the single source of truth as far as what is the current value of a field and that only React can update it. Implementing a form controller on our own is very tedious and error-prone, so we opt to use a pre-made form controller library. Form controller libraries are great because on top of making it easy to control our form fields, they also give us great tools for field-level validation and field-level error messaging, and allow to fields to subscribe to the state of each other, which makes for a better experience on the user side (e.g. a field can adjust based on the value of another field).\r\n\r\nFollowing the advice of the Give.io team, we will be using Final Form, so that we can share knowledge between projects and make maintainability easier.\r\n\r\n**What are the implications of implementing this?**\r\n\r\n* Reduced boilerplate per field. 👍\r\n* We will need to make a field adapter similar to what Give.io is using and perhaps adjust some of the field components we have to follow a consistent API so that the field adapter doesn’t need to be modified per field.\r\n    * This is great, because the Builder and the Campaign can reuse the same adapter.\r\n\r\n</details>\r\n\r\n<details><summary>Why are we making the Campaign its own component?</summary>\r\n\r\nWe are making the Campaign its own component so that it can function on its own in different contexts (i.e. in the Builder, on its landing page, in an emebed, in a Gutenberg block). Currently, the Campaign is built into the Builder and cannot exist on its own since:\r\n\r\n1. There’s currently no way of referencing it for reuse.\r\n2. The underlying logic to make it function is inseperable from the Builder.\r\n\r\n</details>\r\n\r\n<details><summary>What does state management look like for our app?</summary>\r\n\r\nThis is a break down of how the state management works at different levels:\r\n\r\n* Apollo — in charge of communicating data with the server.\r\n  * This is to be used at the top level of the client so that views can pull from the same cache.\r\n* Context API — in charge of contextual state and holding mutated server data until it is ready to be sumbitted.\r\n* Final Form — in charge of collecting and validating data from any forms and passing that to the Context API. It also lets us know if and when we are ready to submit.\r\n* Prop drilling — def: simply passing data down the component tree until to gets to where it needs to go. We use this in the cases that the underlying component really doesn’t need to be getting data via a hook — which is a lot of cases.\r\n\r\n</details>\r\n\r\n<details><summary>Building out the Manager page</summary>\r\n\r\nCurrently, I already have the app chrome implemented for the Manager with a working \"New Campaign\" button.\r\n\r\n![app-shell-header](https://user-images.githubusercontent.com/6908001/69756219-320f3980-1117-11ea-8f08-e73ff8f2ff51.gif)\r\n\r\n_Note that in this preview the application flow isn’t what the MVP will be. I have yet to implement the new functionality where the build detects that this is a new campaign that it is editing and displays the new campaign splash first. The preview’s goal is to demonstrate that the two app header bars use a common component like the design specifies. Also, the Campaign page selector is missing since I am in the midsts of extracting the Campaign and that needs to be reworked a little to work with that._\r\n\r\n</details>\r\n\r\n<details><summary>Is all of this a step backwards?</summary>\r\n\r\nYes and no. Yes, there are a few things we need to refactor, however, this is all to help us achieve the MVP. For example, moving the router was absolutely necessary since otherwise we would not be able to implement the Manager view. Also, replacing Redux goes hand-in-hand with this change since previously, the state management was Builder-centric and even if we kept Redux, we would have started using the Context API anyway for view/component-specific state. Redux isn’t being replaced per se, it’s just not useful since app-level state doesn’t exist when we use a router. The choice to use Apollo at the app-level for sending and retrieving data to and from the server is just using a better tool for the task — a task that actually wasn’t implemented yet using Redux. Also, it aligns us with the Give.io team and their use of Apollo — except that we don’t have a GraphQL backend (yet — perhaps in the future).\r\n\r\n</details>\r\n\r\nAll in all, I will have this all finished by the time you all get back from Thanksgiving. 🦃 Let me know if you have any questions or concerns about any of this. I wanted to send this before all of you had to go, so it might have been better written."}}
{"actor":{"display_login":"knowler"}}