Repository: learningequality/kolibri

Issue:
Automatic Syncing Updates: Create Learner-facing notifications for insufficient storage
## Overview 

This issue is a full-stack issue that creates a banner-style in-Kolibri notification if a learner has run out of storage but their library is trying to sync, or when they are choosing to download more content. **Notifications are present across user permission levels (as some learners will be by-default super admins of their own device)**. 

The notifications change slightly based on how Kolibri was configured.

## Specifications 
### Figma 

Please see [complete figma spec ](https://www.figma.com/file/MpCG7r5PULOCJsEvnTSti8/Android-Designs-2022?node-id=1040%3A20712&t=bVNzyZsQkYnGNOPe-0) for full specs of various states.

<img width="705" alt="Screen Shot 2022-11-18 at 4 51 25 PM" src="https://user-images.githubusercontent.com/17235236/202809225-931eb1b8-d35a-402a-9a55-40d99d83cbdc.png">
<img width="678" alt="Screen Shot 2022-11-18 at 4 51 31 PM" src="https://user-images.githubusercontent.com/17235236/202809231-714fe388-80aa-4cec-bb6b-0d8705955677.png">

### Accessibility requirements
Each banner should include a `visually-hidden` `h1` which will allow the screen reader user to more readily discover the notification and it's context. Please check in with @radinamatic and @marcellamaki with any questions and for final wording. For now, you can use placeholder text of "Storage notification".

The `aria-live` with `polite` should also be used, to interrupt the screen-reader user with the notification. For more details, please see the [MDN Docs on aria-live regions](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions).

## Acceptance Criteria
Learn interface has notifications for: 
Setup: “On my own” and “Full device”
- [ ]   Does not have device permissions, Nothing in My downloads
- [ ]   Does not have device permissions, Has things in My downloads
- [ ]   Super admin, insufficient storage

Setup: Learn-only device
- [ ] Not enough room for assigned things
- [ ] Removed things in My downloads to make room for assigned things


### Out of scope
Implementing banner or other push-style notifications for browser learn-only devices is not part of this issue.

## References 
- [Notion project page](https://www.notion.so/learningequality/Remote-Content-Syncing-Automatic-syncing-d0a28f150b324d4da019790228117068)
- [Figma spec](https://www.figma.com/file/MpCG7r5PULOCJsEvnTSti8/Android-Designs-2022?node-id=194%3A2922&t=bVNzyZsQkYnGNOPe-0)
- [Gherkin scenarios](https://www.notion.so/learningequality/Gherkin-scenarios-02096ac9925844f8902c818cab607d4b#8d768ab75449478783adb84732968e18)


Discussion:

Resolving patch:
diff --git a/kolibri/core/device/api.py b/kolibri/core/device/api.py
--- a/kolibri/core/device/api.py
+++ b/kolibri/core/device/api.py
@@ -247,8 +247,8 @@ def map_status(record):
     the frontend.
     """
     transfer_status = record.pop("transfer_status", None)
-    device_status = record.pop("device_status", None)
-    device_status_sentiment = record.pop("device_status_sentiment", None)
+    device_status = record.get("device_status")
+    device_status_sentiment = record.get("device_status_sentiment")
     queued = record.pop("queued", None)
     recent = record["last_synced"] and (
         timezone.now() - record["last_synced"] < sync_diff


Test patch:
diff --git a/kolibri/core/assets/test/views/side-nav.spec.js b/kolibri/core/assets/test/views/side-nav.spec.js
--- a/kolibri/core/assets/test/views/side-nav.spec.js
+++ b/kolibri/core/assets/test/views/side-nav.spec.js
@@ -6,6 +6,7 @@ import SideNav from '../../src/views/SideNav';
 import logoutSideNavEntry from '../../src/views/LogoutSideNavEntry';
 import LearnOnlyDeviceNotice from '../../src/views/LearnOnlyDeviceNotice';
 import SyncStatusDisplay from '../../src/views/SyncStatusDisplay';
+import { stubWindowLocation } from 'testUtils'; // eslint-disable-line
 
 import { coreStoreFactory as makeStore } from '../../src/state/store';
 
@@ -62,6 +63,8 @@ function emptyNavComponents(n = 1) {
 }
 
 describe('side nav component', () => {
+  stubWindowLocation(beforeAll, afterAll);
+
   it('should be hidden if navShown is false', () => {
     const wrapper = createWrapper({ navShown: false });
     expect(wrapper.find('.side-nav').element).not.toBeVisible();