deviceName.tsx 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import React from 'react';
  2. import {IOSDeviceList} from 'app/types/iOSDeviceList';
  3. export function deviceNameMapper(model: string, iOSDeviceList): string {
  4. const modelIdentifier = model.split(' ')[0];
  5. const modelId = model.split(' ').splice(1).join(' ');
  6. const modelName = iOSDeviceList.generationByIdentifier(modelIdentifier);
  7. return modelName === undefined ? model : modelName + ' ' + modelId;
  8. }
  9. export async function loadDeviceListModule() {
  10. return import(/* webpackChunkName: "iOSDeviceList" */ 'ios-device-list');
  11. }
  12. type Props = {
  13. value: string;
  14. children?: (name: string) => React.ReactNode;
  15. };
  16. type State = {
  17. iOSDeviceList: IOSDeviceList | null;
  18. };
  19. /**
  20. * This is used to map iOS Device Names to model name.
  21. * This asynchronously loads the ios-device-list library because of its size
  22. */
  23. export default class DeviceName extends React.Component<Props, State> {
  24. constructor(props) {
  25. super(props);
  26. this.state = {
  27. iOSDeviceList: null,
  28. };
  29. }
  30. componentDidMount() {
  31. // This is to handle react's warning on calling setState for unmounted components
  32. // Since we can't cancel promises, we need to do this
  33. this._isMounted = true;
  34. // This library is very big, so we are codesplitting it based on size and
  35. // the relatively small utility this library provides
  36. loadDeviceListModule().then(iOSDeviceList => {
  37. if (!this._isMounted) {
  38. return;
  39. }
  40. this.setState({iOSDeviceList});
  41. });
  42. }
  43. componentWillUnmount() {
  44. this._isMounted = false;
  45. }
  46. private _isMounted?: boolean;
  47. render() {
  48. const {value, children} = this.props;
  49. const {iOSDeviceList} = this.state;
  50. // value can be undefined, need to return null or else react throws
  51. if (!value) {
  52. return null;
  53. }
  54. // If library has not loaded yet, then just render the raw model string, better than empty
  55. if (!iOSDeviceList) {
  56. return value;
  57. }
  58. const deviceName = deviceNameMapper(value, iOSDeviceList);
  59. return (
  60. <span data-test-id="loaded-device-name">
  61. {children ? children(deviceName) : deviceName}
  62. </span>
  63. );
  64. }
  65. }