mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-30 08:50:51 +01:00
Update camera
This commit is contained in:
parent
188ac1bc5d
commit
0a8e8fa67a
@ -62,6 +62,11 @@ $messenger-height: 370px;
|
|||||||
$marketplace-post-offer-width: 430px;
|
$marketplace-post-offer-width: 430px;
|
||||||
$marketplace-post-offer-height: 250px;
|
$marketplace-post-offer-height: 250px;
|
||||||
|
|
||||||
|
$camera-editor-width: 600px;
|
||||||
|
$camera-editor-height: 500px;
|
||||||
|
|
||||||
|
$camera-checkout-width: 350px;
|
||||||
|
|
||||||
$room-info-width: 325px;
|
$room-info-width: 325px;
|
||||||
|
|
||||||
.nitro-app {
|
.nitro-app {
|
||||||
|
@ -85,89 +85,41 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.nitro-camera-editor {
|
.nitro-camera-editor {
|
||||||
width: 600px;
|
width: $camera-editor-width;
|
||||||
|
height: $camera-editor-height;
|
||||||
|
|
||||||
.content-area {
|
.picture-preview {
|
||||||
min-height: 441px;
|
width: 320px;
|
||||||
height: 441px;
|
height: 320px;
|
||||||
resize: vertical;
|
}
|
||||||
|
|
||||||
.picture-preview {
|
.layout-grid-item {
|
||||||
width: 320px;
|
height: 60px !important;
|
||||||
height: 320px;
|
max-height: 60px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.slider {
|
.effect-thumbnail-image {
|
||||||
background: linear-gradient(180deg, transparent, black);
|
|
||||||
text-shadow: 1px 1px rgba(0, 0, 0, .5);
|
img {
|
||||||
}
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
image-rendering: auto;
|
||||||
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.effect-grid {
|
.remove-effect {
|
||||||
|
position: absolute;
|
||||||
.grid-item-container {
|
top: 1px;
|
||||||
height: 60px !important;
|
right: 1px;
|
||||||
max-height: 60px !important;
|
padding: 2px;
|
||||||
|
font-size: 10px;
|
||||||
.grid-item {
|
min-height: unset;
|
||||||
overflow: unset;
|
|
||||||
|
|
||||||
.remove-effect {
|
|
||||||
position: absolute;
|
|
||||||
top: -1px;
|
|
||||||
right: -1px;
|
|
||||||
padding: 2px;
|
|
||||||
font-size: 11px;
|
|
||||||
line-height: 11px;
|
|
||||||
min-height: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
.effect-thumbnail-image {
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
image-rendering: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.effects {
|
|
||||||
height: 363px;
|
|
||||||
min-height: 363px;
|
|
||||||
max-height: 363px;
|
|
||||||
|
|
||||||
.btn-remove-effect {
|
|
||||||
z-index: 10;
|
|
||||||
min-height: 0px;
|
|
||||||
border-radius: 100px;
|
|
||||||
width: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.effect-thumbnail {
|
|
||||||
border-color: $grid-border-color !important;
|
|
||||||
background-color: $grid-bg-color;
|
|
||||||
height: 60px;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
border-color: $grid-active-border-color !important;
|
|
||||||
background-color: $grid-active-bg-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.effect-thumbnail-image {
|
|
||||||
img {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nitro-camera-checkout {
|
.nitro-camera-checkout {
|
||||||
width: 388px;
|
width: $camera-checkout-width;
|
||||||
|
|
||||||
.picture-preview {
|
.picture-preview {
|
||||||
width: 320px;
|
width: 320px;
|
5
src/components/camera/common/CameraEditorTabs.ts
Normal file
5
src/components/camera/common/CameraEditorTabs.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export class CameraEditorTabs
|
||||||
|
{
|
||||||
|
public static readonly COLORMATRIX: string = 'colormatrix';
|
||||||
|
public static readonly COMPOSITE: string = 'composite';
|
||||||
|
}
|
24
src/components/camera/context/CameraWidgetContext.tsx
Normal file
24
src/components/camera/context/CameraWidgetContext.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { createContext, Dispatch, FC, ProviderProps, SetStateAction, useContext } from 'react';
|
||||||
|
import { CameraPicture } from '../common/CameraPicture';
|
||||||
|
|
||||||
|
export interface ICameraWidgetContext
|
||||||
|
{
|
||||||
|
cameraRoll: CameraPicture[],
|
||||||
|
setCameraRoll: Dispatch<SetStateAction<CameraPicture[]>>;
|
||||||
|
selectedPictureIndex: number,
|
||||||
|
setSelectedPictureIndex: Dispatch<SetStateAction<number>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CameraWidgetContext = createContext<ICameraWidgetContext>({
|
||||||
|
cameraRoll: null,
|
||||||
|
setCameraRoll: null,
|
||||||
|
selectedPictureIndex: null,
|
||||||
|
setSelectedPictureIndex: null
|
||||||
|
});
|
||||||
|
|
||||||
|
export const CameraWidgetContextProvider: FC<ProviderProps<ICameraWidgetContext>> = props =>
|
||||||
|
{
|
||||||
|
return <CameraWidgetContext.Provider value={ props.value }>{ props.children }</CameraWidgetContext.Provider>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useCameraWidgetContext = () => useContext(CameraWidgetContext);
|
@ -1,11 +1,21 @@
|
|||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { NitroRectangle, TextureUtils } from '@nitrots/nitro-renderer';
|
import { NitroRectangle, TextureUtils } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useCallback, useRef } from 'react';
|
import { FC, useCallback, useRef } from 'react';
|
||||||
import { GetRoomEngine, GetRoomSession, LocalizeText } from '../../../../api';
|
import { GetRoomEngine, GetRoomSession, LocalizeText } from '../../../../api';
|
||||||
import { CAMERA_SHUTTER, PlaySound } from '../../../../api/utils/PlaySound';
|
import { CAMERA_SHUTTER, PlaySound } from '../../../../api/utils/PlaySound';
|
||||||
|
import { Column } from '../../../../common/Column';
|
||||||
|
import { Flex } from '../../../../common/Flex';
|
||||||
import { DraggableWindow } from '../../../../layout';
|
import { DraggableWindow } from '../../../../layout';
|
||||||
|
import { NotificationUtilities } from '../../../../views/notification-center/common/NotificationUtilities';
|
||||||
import { CameraPicture } from '../../common/CameraPicture';
|
import { CameraPicture } from '../../common/CameraPicture';
|
||||||
import { useCameraWidgetContext } from '../../context/CameraWidgetContext';
|
import { useCameraWidgetContext } from '../../context/CameraWidgetContext';
|
||||||
import { CameraWidgetCaptureViewProps } from './CameraWidgetCaptureView.types';
|
|
||||||
|
export interface CameraWidgetCaptureViewProps
|
||||||
|
{
|
||||||
|
onClose: () => void;
|
||||||
|
onEdit: () => void;
|
||||||
|
onDelete: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
const CAMERA_ROLL_LIMIT: number = 5;
|
const CAMERA_ROLL_LIMIT: number = 5;
|
||||||
|
|
||||||
@ -40,7 +50,7 @@ export const CameraWidgetCaptureView: FC<CameraWidgetCaptureViewProps> = props =
|
|||||||
|
|
||||||
if(clone.length >= CAMERA_ROLL_LIMIT)
|
if(clone.length >= CAMERA_ROLL_LIMIT)
|
||||||
{
|
{
|
||||||
alert(LocalizeText('camera.full.body'));
|
NotificationUtilities.simpleAlert(LocalizeText('camera.full.body'));
|
||||||
|
|
||||||
clone.pop();
|
clone.pop();
|
||||||
}
|
}
|
||||||
@ -52,12 +62,12 @@ export const CameraWidgetCaptureView: FC<CameraWidgetCaptureViewProps> = props =
|
|||||||
}, [ cameraRoll, selectedPictureIndex, getCameraBounds, setCameraRoll, setSelectedPictureIndex ]);
|
}, [ cameraRoll, selectedPictureIndex, getCameraBounds, setCameraRoll, setSelectedPictureIndex ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DraggableWindow>
|
<DraggableWindow uniqueKey="nitro-camera-capture">
|
||||||
<div className="d-flex flex-column justify-content-center align-items-center nitro-camera-capture">
|
<Column center className="nitro-camera-capture" gap={ 0 }>
|
||||||
{ selectedPicture && <img alt="" className="camera-area" src={ selectedPicture.imageUrl } /> }
|
{ selectedPicture && <img alt="" className="camera-area" src={ selectedPicture.imageUrl } /> }
|
||||||
<div className="camera-canvas drag-handler">
|
<div className="camera-canvas drag-handler">
|
||||||
<div className="position-absolute header-close" onClick={ onClose }>
|
<div className="position-absolute header-close" onClick={ onClose }>
|
||||||
<i className="fas fa-times" />
|
<FontAwesomeIcon icon="times" />
|
||||||
</div>
|
</div>
|
||||||
{ !selectedPicture && <div ref={ elementRef } className="camera-area camera-view-finder" /> }
|
{ !selectedPicture && <div ref={ elementRef } className="camera-area camera-view-finder" /> }
|
||||||
{ selectedPicture &&
|
{ selectedPicture &&
|
||||||
@ -72,13 +82,13 @@ export const CameraWidgetCaptureView: FC<CameraWidgetCaptureViewProps> = props =
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{ (cameraRoll.length > 0) &&
|
{ (cameraRoll.length > 0) &&
|
||||||
<div className="camera-roll d-flex justify-content-center py-2">
|
<Flex gap={ 2 } justifyContent="center" className="camera-roll d-flex justify-content-center py-2">
|
||||||
{ cameraRoll.map((picture, index) =>
|
{ cameraRoll.map((picture, index) =>
|
||||||
{
|
{
|
||||||
return <img alt="" key={ index } className={ (index < (cameraRoll.length - 1) ? 'me-2' : '') } src={ picture.imageUrl } onClick={ event => setSelectedPictureIndex(index) } />;
|
return <img alt="" key={ index } src={ picture.imageUrl } onClick={ event => setSelectedPictureIndex(index) } />;
|
||||||
}) }
|
}) }
|
||||||
</div> }
|
</Flex> }
|
||||||
</div>
|
</Column>
|
||||||
</DraggableWindow>
|
</DraggableWindow>
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -0,0 +1,175 @@
|
|||||||
|
import { CameraPublishStatusMessageEvent, CameraPurchaseOKMessageEvent, CameraStorageUrlMessageEvent, PublishPhotoMessageComposer, PurchasePhotoMessageComposer } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
|
import { GetConfiguration, GetRoomEngine, LocalizeText } from '../../../../api';
|
||||||
|
import { Button } from '../../../../common/Button';
|
||||||
|
import { Column } from '../../../../common/Column';
|
||||||
|
import { Flex } from '../../../../common/Flex';
|
||||||
|
import { LayoutImage } from '../../../../common/layout/LayoutImage';
|
||||||
|
import { Text } from '../../../../common/Text';
|
||||||
|
import { InventoryEvent } from '../../../../events';
|
||||||
|
import { BatchUpdates, CreateMessageHook, dispatchUiEvent, SendMessageHook } from '../../../../hooks';
|
||||||
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
|
||||||
|
import { CurrencyIcon } from '../../../../views/shared/currency-icon/CurrencyIcon';
|
||||||
|
|
||||||
|
export interface CameraWidgetCheckoutViewProps
|
||||||
|
{
|
||||||
|
base64Url: string;
|
||||||
|
onCloseClick: () => void;
|
||||||
|
onCancelClick: () => void;
|
||||||
|
price: { credits: number, duckets: number, publishDucketPrice: number };
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CameraWidgetCheckoutView: FC<CameraWidgetCheckoutViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { base64Url = null, onCloseClick = null, onCancelClick = null, price = null } = props;
|
||||||
|
const [ pictureUrl, setPictureUrl ] = useState<string>(null);
|
||||||
|
const [ publishUrl, setPublishUrl ] = useState<string>(null);
|
||||||
|
const [ picturesBought, setPicturesBought ] = useState(0);
|
||||||
|
const [ wasPicturePublished, setWasPicturePublished ] = useState(false);
|
||||||
|
const [ isWaiting, setIsWaiting ] = useState(false);
|
||||||
|
const [ publishCooldown, setPublishCooldown ] = useState(0);
|
||||||
|
|
||||||
|
const onCameraPurchaseOKMessageEvent = useCallback((event: CameraPurchaseOKMessageEvent) =>
|
||||||
|
{
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
|
setPicturesBought(value => (value + 1));
|
||||||
|
setIsWaiting(false);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
CreateMessageHook(CameraPurchaseOKMessageEvent, onCameraPurchaseOKMessageEvent);
|
||||||
|
|
||||||
|
const onCameraPublishStatusMessageEvent = useCallback((event: CameraPublishStatusMessageEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
|
setPublishUrl(parser.extraDataId);
|
||||||
|
setPublishCooldown(parser.secondsToWait);
|
||||||
|
setWasPicturePublished(parser.ok);
|
||||||
|
setIsWaiting(false);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
CreateMessageHook(CameraPublishStatusMessageEvent, onCameraPublishStatusMessageEvent);
|
||||||
|
|
||||||
|
const onCameraStorageUrlMessageEvent = useCallback((event: CameraStorageUrlMessageEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
setPictureUrl(GetConfiguration<string>('camera.url') + '/' + parser.url);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
CreateMessageHook(CameraStorageUrlMessageEvent, onCameraStorageUrlMessageEvent);
|
||||||
|
|
||||||
|
const processAction = (type: string, value: string | number = null) =>
|
||||||
|
{
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case 'close':
|
||||||
|
onCloseClick();
|
||||||
|
return;
|
||||||
|
case 'buy':
|
||||||
|
if(isWaiting) return;
|
||||||
|
|
||||||
|
setIsWaiting(true);
|
||||||
|
SendMessageHook(new PurchasePhotoMessageComposer(''));
|
||||||
|
return;
|
||||||
|
case 'publish':
|
||||||
|
if(isWaiting) return;
|
||||||
|
|
||||||
|
setIsWaiting(true);
|
||||||
|
SendMessageHook(new PublishPhotoMessageComposer());
|
||||||
|
return;
|
||||||
|
case 'cancel':
|
||||||
|
onCancelClick();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!base64Url) return;
|
||||||
|
|
||||||
|
GetRoomEngine().saveBase64AsScreenshot(base64Url);
|
||||||
|
}, [ base64Url ]);
|
||||||
|
|
||||||
|
if(!price) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NitroCardView className="nitro-camera-checkout" simple={ true }>
|
||||||
|
<NitroCardHeaderView headerText={ LocalizeText('camera.confirm_phase.title') } onCloseClick={ event => processAction('close') } />
|
||||||
|
<NitroCardContentView>
|
||||||
|
<Flex center>
|
||||||
|
{ (pictureUrl && pictureUrl.length) &&
|
||||||
|
<LayoutImage fit={ false } className="picture-preview border" imageUrl={ pictureUrl } /> }
|
||||||
|
{ (!pictureUrl || !pictureUrl.length) &&
|
||||||
|
<Flex center className="picture-preview border">
|
||||||
|
<Text bold>{ LocalizeText('camera.loading') }</Text>
|
||||||
|
</Flex> }
|
||||||
|
</Flex>
|
||||||
|
<Flex justifyContent="between" alignItems="center" className="bg-muted rounded p-2">
|
||||||
|
<Column gap={ 1 }>
|
||||||
|
<Text bold>
|
||||||
|
{ LocalizeText('camera.purchase.header') }
|
||||||
|
</Text>
|
||||||
|
{ ((price.credits > 0) || (price.duckets > 0)) &&
|
||||||
|
<Flex gap={ 1 }>
|
||||||
|
<Text>{ LocalizeText('catalog.purchase.confirmation.dialog.cost') }</Text>
|
||||||
|
{ (price.credits > 0) &&
|
||||||
|
<Flex gap={ 1 }>
|
||||||
|
<Text bold>{ price.credits }</Text>
|
||||||
|
<CurrencyIcon type={ -1 } />
|
||||||
|
</Flex> }
|
||||||
|
{ (price.duckets > 0) &&
|
||||||
|
<Flex gap={ 1 }>
|
||||||
|
<Text bold>{ price.duckets }</Text>
|
||||||
|
<CurrencyIcon type={ 5 } />
|
||||||
|
</Flex> }
|
||||||
|
</Flex> }
|
||||||
|
{ (picturesBought > 0) &&
|
||||||
|
<Text>
|
||||||
|
<Text bold>{ LocalizeText('camera.purchase.count.info') }</Text> { picturesBought }
|
||||||
|
<u className="ms-1 cursor-pointer" onClick={ () => dispatchUiEvent(new InventoryEvent(InventoryEvent.SHOW_INVENTORY)) }>{ LocalizeText('camera.open.inventory') }</u>
|
||||||
|
</Text> }
|
||||||
|
</Column>
|
||||||
|
<Flex alignItems="center">
|
||||||
|
<Button variant="success" disabled={ isWaiting } onClick={ event => processAction('buy') }>{ LocalizeText(!picturesBought ? 'buy' : 'camera.buy.another.button.text') }</Button>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
<Flex justifyContent="between" alignItems="center" className="bg-muted rounded p-2">
|
||||||
|
<Column gap={ 1 }>
|
||||||
|
<Text bold>
|
||||||
|
{ LocalizeText(wasPicturePublished ? 'camera.publish.successful' : 'camera.publish.explanation') }
|
||||||
|
</Text>
|
||||||
|
<Text>
|
||||||
|
{ LocalizeText(wasPicturePublished ? 'camera.publish.success.short.info' : 'camera.publish.detailed.explanation') }
|
||||||
|
</Text>
|
||||||
|
{ wasPicturePublished && <a href={ publishUrl } rel="noreferrer" target="_blank">{ LocalizeText('camera.link.to.published') }</a> }
|
||||||
|
{ !wasPicturePublished && (price.publishDucketPrice > 0) &&
|
||||||
|
<Flex gap={ 1 }>
|
||||||
|
<Text>{ LocalizeText('catalog.purchase.confirmation.dialog.cost') }</Text>
|
||||||
|
<Flex gap={ 1 }>
|
||||||
|
<Text bold>{ price.publishDucketPrice }</Text>
|
||||||
|
<CurrencyIcon type={ 5 } />
|
||||||
|
</Flex>
|
||||||
|
</Flex> }
|
||||||
|
{ (publishCooldown > 0) && <div className="mt-1 text-center fw-bold">{ LocalizeText('camera.publish.wait', [ 'minutes' ], [ Math.ceil( publishCooldown / 60).toString() ]) }</div> }
|
||||||
|
</Column>
|
||||||
|
{ !wasPicturePublished &&
|
||||||
|
<Flex className="d-flex align-items-end">
|
||||||
|
<Button variant="success" size="sm" disabled={ (isWaiting || (publishCooldown > 0)) } onClick={ event => processAction('publish') }>
|
||||||
|
{ LocalizeText('camera.publish.button.text') }
|
||||||
|
</Button>
|
||||||
|
</Flex> }
|
||||||
|
</Flex>
|
||||||
|
<Text center>{ LocalizeText('camera.warning.disclaimer') }</Text>
|
||||||
|
<Flex justifyContent="end">
|
||||||
|
<Button onClick={ event => processAction('cancel') }>{ LocalizeText('generic.cancel') }</Button>
|
||||||
|
</Flex>
|
||||||
|
</NitroCardContentView>
|
||||||
|
</NitroCardView>
|
||||||
|
);
|
||||||
|
}
|
@ -1,13 +1,32 @@
|
|||||||
import { IRoomCameraWidgetSelectedEffect, RoomCameraWidgetSelectedEffect } from '@nitrots/nitro-renderer';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import { IRoomCameraWidgetEffect, IRoomCameraWidgetSelectedEffect, RoomCameraWidgetSelectedEffect } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import ReactSlider from 'react-slider';
|
import ReactSlider from 'react-slider';
|
||||||
import { GetRoomCameraWidgetManager, LocalizeText } from '../../../../api';
|
import { GetRoomCameraWidgetManager, LocalizeText } from '../../../../api';
|
||||||
|
import { Button } from '../../../../common/Button';
|
||||||
|
import { ButtonGroup } from '../../../../common/ButtonGroup';
|
||||||
|
import { Column } from '../../../../common/Column';
|
||||||
|
import { Flex } from '../../../../common/Flex';
|
||||||
|
import { Grid } from '../../../../common/Grid';
|
||||||
|
import { LayoutImage } from '../../../../common/layout/LayoutImage';
|
||||||
|
import { Text } from '../../../../common/Text';
|
||||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../layout';
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../layout';
|
||||||
|
import { CameraEditorTabs } from '../../common/CameraEditorTabs';
|
||||||
|
import { CameraPicture } from '../../common/CameraPicture';
|
||||||
import { CameraPictureThumbnail } from '../../common/CameraPictureThumbnail';
|
import { CameraPictureThumbnail } from '../../common/CameraPictureThumbnail';
|
||||||
import { CameraWidgetEditorTabs, CameraWidgetEditorViewProps } from './CameraWidgetEditorView.types';
|
|
||||||
import { CameraWidgetEffectListView } from './effect-list/CameraWidgetEffectListView';
|
import { CameraWidgetEffectListView } from './effect-list/CameraWidgetEffectListView';
|
||||||
|
|
||||||
const TABS: string[] = [ CameraWidgetEditorTabs.COLORMATRIX, CameraWidgetEditorTabs.COMPOSITE ];
|
export interface CameraWidgetEditorViewProps
|
||||||
|
{
|
||||||
|
picture: CameraPicture;
|
||||||
|
availableEffects: IRoomCameraWidgetEffect[];
|
||||||
|
myLevel: number;
|
||||||
|
onClose: () => void;
|
||||||
|
onCancel: () => void;
|
||||||
|
onCheckout: (pictureUrl: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TABS: string[] = [ CameraEditorTabs.COLORMATRIX, CameraEditorTabs.COMPOSITE ];
|
||||||
|
|
||||||
export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
||||||
{
|
{
|
||||||
@ -30,7 +49,7 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
|||||||
|
|
||||||
const getEffectList = useCallback(() =>
|
const getEffectList = useCallback(() =>
|
||||||
{
|
{
|
||||||
if(currentTab === CameraWidgetEditorTabs.COLORMATRIX)
|
if(currentTab === CameraEditorTabs.COLORMATRIX)
|
||||||
{
|
{
|
||||||
return getColorMatrixEffects;
|
return getColorMatrixEffects;
|
||||||
}
|
}
|
||||||
@ -170,45 +189,49 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
|||||||
}) }
|
}) }
|
||||||
</NitroCardTabsView>
|
</NitroCardTabsView>
|
||||||
<NitroCardContentView>
|
<NitroCardContentView>
|
||||||
<div className="row h-100">
|
<Grid>
|
||||||
<div className="col-5 d-flex flex-column h-100">
|
<Column size={ 5 } overflow="hidden">
|
||||||
<CameraWidgetEffectListView myLevel={ myLevel } selectedEffects={ selectedEffects } effects={ getEffectList() } thumbnails={ effectsThumbnails } processAction={ processAction } />
|
<CameraWidgetEffectListView myLevel={ myLevel } selectedEffects={ selectedEffects } effects={ getEffectList() } thumbnails={ effectsThumbnails } processAction={ processAction } />
|
||||||
</div>
|
</Column>
|
||||||
<div className="col-7 d-flex flex-column h-100">
|
<Column size={ 7 } justifyContent="between" overflow="hidden">
|
||||||
<div className="picture-preview">
|
<Column center>
|
||||||
<img alt="" src={ getCurrentPictureUrl } />
|
<LayoutImage fit={ false } imageUrl={ getCurrentPictureUrl } className="picture-preview" />
|
||||||
</div>
|
{ selectedEffectName &&
|
||||||
{ selectedEffectName &&
|
<Column center fullWidth gap={ 1 }>
|
||||||
<div className="w-100 p-2 d-flex flex-column justify-content-center slider">
|
<Text>{ LocalizeText('camera.effect.name.' + selectedEffectName) }</Text>
|
||||||
<div className="w-100 text-center">{ LocalizeText('camera.effect.name.' + selectedEffectName) }</div>
|
<ReactSlider
|
||||||
<ReactSlider
|
className={ 'nitro-slider' }
|
||||||
className={ 'nitro-slider' }
|
min={ 0 }
|
||||||
min={ 0 }
|
max={ 1 }
|
||||||
max={ 1 }
|
step={ 0.01 }
|
||||||
step={ 0.01 }
|
value={ getCurrentEffect.alpha }
|
||||||
value={ getCurrentEffect.alpha }
|
onChange={ event => setSelectedEffectAlpha(event) }
|
||||||
onChange={ event => setSelectedEffectAlpha(event) }
|
renderThumb={ (props, state) => <div { ...props }>{ state.valueNow }</div> } />
|
||||||
renderThumb={ (props, state) => <div { ...props }>{ state.valueNow }</div> } />
|
</Column> }
|
||||||
</div> }
|
</Column>
|
||||||
<div className="d-flex justify-content-between mt-2">
|
<Flex justifyContent="between">
|
||||||
<div className="btn-group">
|
<ButtonGroup>
|
||||||
<button className="btn btn-primary" onClick={ event => processAction('clear_effects') }>
|
<Button size="sm" onClick={ event => processAction('clear_effects') }>
|
||||||
<i className="fas fa-trash"></i>
|
<FontAwesomeIcon icon="trash" />
|
||||||
</button>
|
</Button>
|
||||||
<button className="btn btn-primary" onClick={ event => processAction('download') }>
|
<Button size="sm" onClick={ event => processAction('download') }>
|
||||||
<i className="fas fa-save"></i>
|
<FontAwesomeIcon icon="save" />
|
||||||
</button>
|
</Button>
|
||||||
<button className="btn btn-primary" onClick={ event => processAction('zoom') }>
|
<Button size="sm" onClick={ event => processAction('zoom') }>
|
||||||
<i className={ `fas fa-search-${ isZoomed ? 'minus': 'plus' }` } />
|
<FontAwesomeIcon icon={ isZoomed ? 'search-minus' : 'search-plus' } />
|
||||||
</button>
|
</Button>
|
||||||
</div>
|
</ButtonGroup>
|
||||||
<div className="d-flex justify-content-end">
|
<Flex gap={ 1 }>
|
||||||
<button className="btn btn-primary me-2" onClick={ event => processAction('cancel') }>{ LocalizeText('generic.cancel') }</button>
|
<Button size="sm" onClick={ event => processAction('cancel') }>
|
||||||
<button className="btn btn-success" onClick={ event => processAction('checkout') }>{ LocalizeText('camera.preview.button.text') }</button>
|
{ LocalizeText('generic.cancel') }
|
||||||
</div>
|
</Button>
|
||||||
</div>
|
<Button size="sm" onClick={ event => processAction('checkout') }>
|
||||||
</div>
|
{ LocalizeText('camera.preview.button.text') }
|
||||||
</div>
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</Column>
|
||||||
|
</Grid>
|
||||||
</NitroCardContentView>
|
</NitroCardContentView>
|
||||||
</NitroCardView>
|
</NitroCardView>
|
||||||
);
|
);
|
@ -0,0 +1,42 @@
|
|||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import { IRoomCameraWidgetEffect } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC } from 'react';
|
||||||
|
import { LocalizeText } from '../../../../../api';
|
||||||
|
import { Button } from '../../../../../common/Button';
|
||||||
|
import { LayoutGridItem } from '../../../../../common/layout/LayoutGridItem';
|
||||||
|
import { Text } from '../../../../../common/Text';
|
||||||
|
|
||||||
|
export interface CameraWidgetEffectListItemViewProps
|
||||||
|
{
|
||||||
|
effect: IRoomCameraWidgetEffect;
|
||||||
|
thumbnailUrl: string;
|
||||||
|
isActive: boolean;
|
||||||
|
isLocked: boolean;
|
||||||
|
selectEffect: () => void;
|
||||||
|
removeEffect: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CameraWidgetEffectListItemView: FC<CameraWidgetEffectListItemViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { effect = null, thumbnailUrl = null, isActive = false, isLocked = false, selectEffect = null, removeEffect = null } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LayoutGridItem title={ LocalizeText(!isLocked ? (`camera.effect.name.${ effect.name }`) : `camera.effect.required.level ${ effect.minLevel }`) } itemActive={ isActive } onClick={ event => (!isActive && selectEffect()) }>
|
||||||
|
{ isActive &&
|
||||||
|
<Button variant="danger" size="sm" className="rounded-circle remove-effect" onClick={ removeEffect }>
|
||||||
|
<FontAwesomeIcon icon="times" />
|
||||||
|
</Button> }
|
||||||
|
{ !isLocked && (thumbnailUrl && thumbnailUrl.length > 0) &&
|
||||||
|
<div className="effect-thumbnail-image border">
|
||||||
|
<img alt="" src={ thumbnailUrl } />
|
||||||
|
</div> }
|
||||||
|
{ isLocked &&
|
||||||
|
<Text center bold>
|
||||||
|
<div>
|
||||||
|
<FontAwesomeIcon icon="lock" />
|
||||||
|
</div>
|
||||||
|
{ effect.minLevel }
|
||||||
|
</Text> }
|
||||||
|
</LayoutGridItem>
|
||||||
|
);
|
||||||
|
}
|
@ -1,14 +1,24 @@
|
|||||||
|
import { IRoomCameraWidgetEffect, IRoomCameraWidgetSelectedEffect } from '@nitrots/nitro-renderer';
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { NitroCardGridView } from '../../../../../layout';
|
import { Grid } from '../../../../../common/Grid';
|
||||||
import { CameraWidgetEffectListItemView } from '../effect-list-item/CameraWidgetEffectListItemView';
|
import { CameraPictureThumbnail } from '../../../common/CameraPictureThumbnail';
|
||||||
import { CameraWidgetEffectListViewProps } from './CameraWidgetEffectListView.types';
|
import { CameraWidgetEffectListItemView } from './CameraWidgetEffectListItemView';
|
||||||
|
|
||||||
|
export interface CameraWidgetEffectListViewProps
|
||||||
|
{
|
||||||
|
myLevel: number;
|
||||||
|
selectedEffects: IRoomCameraWidgetSelectedEffect[];
|
||||||
|
effects: IRoomCameraWidgetEffect[];
|
||||||
|
thumbnails: CameraPictureThumbnail[];
|
||||||
|
processAction: (type: string, name: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
export const CameraWidgetEffectListView: FC<CameraWidgetEffectListViewProps> = props =>
|
export const CameraWidgetEffectListView: FC<CameraWidgetEffectListViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { myLevel = 0, selectedEffects = [], effects = [], thumbnails = [], processAction = null } = props;
|
const { myLevel = 0, selectedEffects = [], effects = [], thumbnails = [], processAction = null } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NitroCardGridView className="effect-grid" columns={ 3 }>
|
<Grid columnCount={ 2 } overflow="auto" columnMinHeight={ 60 }>
|
||||||
{ effects && (effects.length > 0) && effects.map((effect, index) =>
|
{ effects && (effects.length > 0) && effects.map((effect, index) =>
|
||||||
{
|
{
|
||||||
const thumbnailUrl = (thumbnails.find(thumbnail => (thumbnail.effectName === effect.name)));
|
const thumbnailUrl = (thumbnails.find(thumbnail => (thumbnail.effectName === effect.name)));
|
||||||
@ -16,6 +26,6 @@ export const CameraWidgetEffectListView: FC<CameraWidgetEffectListViewProps> = p
|
|||||||
|
|
||||||
return <CameraWidgetEffectListItemView key={ index } effect={ effect } thumbnailUrl={ ((thumbnailUrl && thumbnailUrl.thumbnailUrl) || null) } isActive={ isActive } isLocked={ (effect.minLevel > myLevel) } selectEffect={ () => processAction('select_effect', effect.name) } removeEffect={ () => processAction('remove_effect', effect.name) } />
|
return <CameraWidgetEffectListItemView key={ index } effect={ effect } thumbnailUrl={ ((thumbnailUrl && thumbnailUrl.thumbnailUrl) || null) } isActive={ isActive } isLocked={ (effect.minLevel > myLevel) } selectEffect={ () => processAction('select_effect', effect.name) } removeEffect={ () => processAction('remove_effect', effect.name) } />
|
||||||
}) }
|
}) }
|
||||||
</NitroCardGridView>
|
</Grid>
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
@import './achievements/AchievementsView';
|
@import './achievements/AchievementsView';
|
||||||
@import './avatar-editor/AvatarEditorView';
|
@import './avatar-editor/AvatarEditorView';
|
||||||
|
@import './camera/CameraWidgetView';
|
||||||
@import './catalog/CatalogView';
|
@import './catalog/CatalogView';
|
||||||
@import './inventory/InventoryView';
|
@import './inventory/InventoryView';
|
||||||
@import './navigator/NavigatorView';
|
@import './navigator/NavigatorView';
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
@import "./shared/Shared";
|
@import "./shared/Shared";
|
||||||
@import "./camera/CameraWidgetView";
|
|
||||||
@import "./friends/FriendsView";
|
@import "./friends/FriendsView";
|
||||||
@import "./groups/GroupView";
|
@import "./groups/GroupView";
|
||||||
@import "./hotel-view/HotelView";
|
@import "./hotel-view/HotelView";
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
import { createContext, FC, useContext } from 'react';
|
|
||||||
import { CameraWidgetContextProps, ICameraWidgetContext } from './CameraWidgetContext.types';
|
|
||||||
|
|
||||||
const CameraWidgetContext = createContext<ICameraWidgetContext>({
|
|
||||||
cameraRoll: null,
|
|
||||||
setCameraRoll: null,
|
|
||||||
selectedPictureIndex: null,
|
|
||||||
setSelectedPictureIndex: null
|
|
||||||
});
|
|
||||||
|
|
||||||
export const CameraWidgetContextProvider: FC<CameraWidgetContextProps> = props =>
|
|
||||||
{
|
|
||||||
return <CameraWidgetContext.Provider value={ props.value }>{ props.children }</CameraWidgetContext.Provider>
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useCameraWidgetContext = () => useContext(CameraWidgetContext);
|
|
@ -1,13 +0,0 @@
|
|||||||
import { Dispatch, ProviderProps, SetStateAction } from 'react';
|
|
||||||
import { CameraPicture } from '../common/CameraPicture';
|
|
||||||
|
|
||||||
export interface ICameraWidgetContext
|
|
||||||
{
|
|
||||||
cameraRoll: CameraPicture[],
|
|
||||||
setCameraRoll: Dispatch<SetStateAction<CameraPicture[]>>;
|
|
||||||
selectedPictureIndex: number,
|
|
||||||
setSelectedPictureIndex: Dispatch<SetStateAction<number>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CameraWidgetContextProps extends ProviderProps<ICameraWidgetContext>
|
|
||||||
{}
|
|
@ -1,6 +0,0 @@
|
|||||||
export interface CameraWidgetCaptureViewProps
|
|
||||||
{
|
|
||||||
onClose: () => void;
|
|
||||||
onEdit: () => void;
|
|
||||||
onDelete: () => void;
|
|
||||||
}
|
|
@ -1,147 +0,0 @@
|
|||||||
import { CameraPublishStatusMessageEvent, CameraPurchaseOKMessageEvent, CameraStorageUrlMessageEvent, PublishPhotoMessageComposer, PurchasePhotoMessageComposer } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC, useCallback, useEffect, useState } from 'react';
|
|
||||||
import { GetConfiguration, GetRoomEngine, LocalizeText } from '../../../../api';
|
|
||||||
import { InventoryEvent } from '../../../../events';
|
|
||||||
import { CreateMessageHook, dispatchUiEvent, SendMessageHook } from '../../../../hooks';
|
|
||||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
|
|
||||||
import { CurrencyIcon } from '../../../shared/currency-icon/CurrencyIcon';
|
|
||||||
import { CameraWidgetCheckoutViewProps } from './CameraWidgetCheckoutView.types';
|
|
||||||
|
|
||||||
export const CameraWidgetCheckoutView: FC<CameraWidgetCheckoutViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { base64Url = null, onCloseClick = null, onCancelClick = null, price = null } = props;
|
|
||||||
const [ pictureUrl, setPictureUrl ] = useState<string>(null);
|
|
||||||
const [ publishUrl, setPublishUrl ] = useState<string>(null);
|
|
||||||
const [ picturesBought, setPicturesBought ] = useState(0);
|
|
||||||
const [ wasPicturePublished, setWasPicturePublished ] = useState(false);
|
|
||||||
const [ isWaiting, setIsWaiting ] = useState(false);
|
|
||||||
const [ publishCooldown, setPublishCooldown ] = useState(0);
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
if(!base64Url) return;
|
|
||||||
|
|
||||||
GetRoomEngine().saveBase64AsScreenshot(base64Url);
|
|
||||||
}, [ base64Url ]);
|
|
||||||
|
|
||||||
const onCameraPurchaseOKMessageEvent = useCallback((event: CameraPurchaseOKMessageEvent) =>
|
|
||||||
{
|
|
||||||
setPicturesBought(value => (value + 1));
|
|
||||||
setIsWaiting(false);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
CreateMessageHook(CameraPurchaseOKMessageEvent, onCameraPurchaseOKMessageEvent);
|
|
||||||
|
|
||||||
const onCameraPublishStatusMessageEvent = useCallback((event: CameraPublishStatusMessageEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
|
|
||||||
setPublishUrl(parser.extraDataId);
|
|
||||||
setPublishCooldown(parser.secondsToWait);
|
|
||||||
setWasPicturePublished(parser.ok);
|
|
||||||
setIsWaiting(false);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
CreateMessageHook(CameraPublishStatusMessageEvent, onCameraPublishStatusMessageEvent);
|
|
||||||
|
|
||||||
const onCameraStorageUrlMessageEvent = useCallback((event: CameraStorageUrlMessageEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
|
|
||||||
setPictureUrl(GetConfiguration<string>('camera.url') + '/' + parser.url);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
CreateMessageHook(CameraStorageUrlMessageEvent, onCameraStorageUrlMessageEvent);
|
|
||||||
|
|
||||||
const processAction = useCallback((type: string, value: string | number = null) =>
|
|
||||||
{
|
|
||||||
switch(type)
|
|
||||||
{
|
|
||||||
case 'close':
|
|
||||||
onCloseClick();
|
|
||||||
return;
|
|
||||||
case 'buy':
|
|
||||||
if(isWaiting) return;
|
|
||||||
|
|
||||||
setIsWaiting(true);
|
|
||||||
SendMessageHook(new PurchasePhotoMessageComposer(''));
|
|
||||||
return;
|
|
||||||
case 'publish':
|
|
||||||
if(isWaiting) return;
|
|
||||||
|
|
||||||
setIsWaiting(true);
|
|
||||||
SendMessageHook(new PublishPhotoMessageComposer());
|
|
||||||
return;
|
|
||||||
case 'cancel':
|
|
||||||
onCancelClick();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}, [onCloseClick, isWaiting, onCancelClick]);
|
|
||||||
|
|
||||||
if(!price) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<NitroCardView className="nitro-camera-checkout" simple={ true }>
|
|
||||||
<NitroCardHeaderView headerText={ LocalizeText('camera.confirm_phase.title') } onCloseClick={ event => processAction('close') } />
|
|
||||||
<NitroCardContentView>
|
|
||||||
<div className="d-flex justify-content-center align-items-center picture-preview border mb-2" style={ pictureUrl ? { backgroundImage: 'url(' + pictureUrl + ')' } : {} }>
|
|
||||||
{ !pictureUrl &&
|
|
||||||
<div className="text-black fw-bold">
|
|
||||||
{ LocalizeText('camera.loading') }
|
|
||||||
</div> }
|
|
||||||
</div>
|
|
||||||
{ pictureUrl && <div className="text-black mb-2">{ LocalizeText('camera.confirm_phase.info') }</div> }
|
|
||||||
<div className="d-flex justify-content-between bg-muted rounded p-2 text-black mb-2">
|
|
||||||
<div className="d-flex flex-column">
|
|
||||||
<div className="fw-bold d-flex justify-content-start">{ LocalizeText('camera.purchase.header') }</div>
|
|
||||||
{ ((price.credits > 0) || (price.duckets > 0)) &&
|
|
||||||
<div className="d-flex">
|
|
||||||
<div className="me-1">{ LocalizeText('catalog.purchase.confirmation.dialog.cost') }</div>
|
|
||||||
{ (price.credits > 0) &&
|
|
||||||
<div className="d-flex fw-bold">
|
|
||||||
{ price.credits } <CurrencyIcon type={ -1 } />
|
|
||||||
</div> }
|
|
||||||
{ (price.duckets > 0) &&
|
|
||||||
<div className="d-flex fw-bold">
|
|
||||||
{ price.duckets } <CurrencyIcon type={ 5 } />
|
|
||||||
</div> }
|
|
||||||
</div> }
|
|
||||||
{ (picturesBought > 0) &&
|
|
||||||
<div>
|
|
||||||
<span className="fw-bold">{ LocalizeText('camera.purchase.count.info') }</span> { picturesBought }
|
|
||||||
<u className="ms-1 cursor-pointer" onClick={ () => dispatchUiEvent(new InventoryEvent(InventoryEvent.SHOW_INVENTORY)) }>{ LocalizeText('camera.open.inventory') }</u>
|
|
||||||
</div> }
|
|
||||||
</div>
|
|
||||||
<div className="d-flex align-items-center">
|
|
||||||
<button className="btn btn-success" disabled={ isWaiting } onClick={ event => processAction('buy') }>{ LocalizeText(!picturesBought ? 'buy' : 'camera.buy.another.button.text') }</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="d-flex justify-content-between bg-muted rounded p-2 text-black mb-2">
|
|
||||||
<div className="d-flex flex-column">
|
|
||||||
<div className="fw-bold d-flex justify-content-start">{ LocalizeText(wasPicturePublished ? 'camera.publish.successful' : 'camera.publish.explanation') }</div>
|
|
||||||
<div>
|
|
||||||
{ LocalizeText(wasPicturePublished ? 'camera.publish.success.short.info' : 'camera.publish.detailed.explanation') }
|
|
||||||
</div>
|
|
||||||
{ wasPicturePublished && <a href={ publishUrl } rel="noreferrer" target="_blank">{ LocalizeText('camera.link.to.published') }</a> }
|
|
||||||
{ !wasPicturePublished && (price.publishDucketPrice > 0) &&
|
|
||||||
<div className="d-flex">
|
|
||||||
<div className="me-1">{ LocalizeText('catalog.purchase.confirmation.dialog.cost') }</div>
|
|
||||||
<div className="d-flex fw-bold">
|
|
||||||
{ price.publishDucketPrice } <CurrencyIcon type={ 5 } />
|
|
||||||
</div>
|
|
||||||
</div> }
|
|
||||||
{ (publishCooldown > 0) && <div className="mt-1 text-center fw-bold">{ LocalizeText('camera.publish.wait', [ 'minutes' ], [ Math.ceil( publishCooldown / 60).toString() ]) }</div> }
|
|
||||||
</div>
|
|
||||||
{ !wasPicturePublished &&
|
|
||||||
<div className="d-flex align-items-end">
|
|
||||||
<button className="btn btn-success" disabled={ isWaiting || publishCooldown > 0 } onClick={ event => processAction('publish') }>{ LocalizeText('camera.publish.button.text') }</button>
|
|
||||||
</div> }
|
|
||||||
</div>
|
|
||||||
<div className="text-black mb-2 text-center">{ LocalizeText('camera.warning.disclaimer') }</div>
|
|
||||||
<div className="d-flex justify-content-end">
|
|
||||||
<button className="btn btn-primary" onClick={ event => processAction('cancel') }>{ LocalizeText('generic.cancel') }</button>
|
|
||||||
</div>
|
|
||||||
</NitroCardContentView>
|
|
||||||
</NitroCardView>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
export interface CameraWidgetCheckoutViewProps
|
|
||||||
{
|
|
||||||
base64Url: string;
|
|
||||||
onCloseClick: () => void;
|
|
||||||
onCancelClick: () => void;
|
|
||||||
price: { credits: number, duckets: number, publishDucketPrice: number };
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
import { IRoomCameraWidgetEffect } from '@nitrots/nitro-renderer';
|
|
||||||
import { CameraPicture } from '../../common/CameraPicture';
|
|
||||||
|
|
||||||
export interface CameraWidgetEditorViewProps
|
|
||||||
{
|
|
||||||
picture: CameraPicture;
|
|
||||||
availableEffects: IRoomCameraWidgetEffect[];
|
|
||||||
myLevel: number;
|
|
||||||
onClose: () => void;
|
|
||||||
onCancel: () => void;
|
|
||||||
onCheckout: (pictureUrl: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CameraWidgetEditorTabs
|
|
||||||
{
|
|
||||||
public static readonly COLORMATRIX: string = 'colormatrix';
|
|
||||||
public static readonly COMPOSITE: string = 'composite';
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
import { FC } from 'react';
|
|
||||||
import { LocalizeText } from '../../../../../api';
|
|
||||||
import { NitroCardGridItemView } from '../../../../../layout';
|
|
||||||
import { CameraWidgetEffectListItemViewProps } from './CameraWidgetEffectListItemView.types';
|
|
||||||
|
|
||||||
export const CameraWidgetEffectListItemView: FC<CameraWidgetEffectListItemViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { effect = null, thumbnailUrl = null, isActive = false, isLocked = false, selectEffect = null, removeEffect = null } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<NitroCardGridItemView title={ LocalizeText(!isLocked ? (`camera.effect.name.${ effect.name }`) : `camera.effect.required.level ${ effect.minLevel }`) } itemActive={ isActive } onClick={ event => (!isActive && selectEffect()) }>
|
|
||||||
{ isActive &&
|
|
||||||
<button className="btn btn-danger btn-sm rounded-circle remove-effect" onClick={ removeEffect }>
|
|
||||||
<i className="fas fa-times" />
|
|
||||||
</button> }
|
|
||||||
{ !isLocked && (thumbnailUrl && thumbnailUrl.length > 0) &&
|
|
||||||
<div className="effect-thumbnail-image border">
|
|
||||||
<img alt="" src={ thumbnailUrl } />
|
|
||||||
</div> }
|
|
||||||
{ isLocked &&
|
|
||||||
<div className="text-center text-black">
|
|
||||||
<div>
|
|
||||||
<i className="fas fa-lock" />
|
|
||||||
</div>
|
|
||||||
<div className="fw-bold">{ effect.minLevel }</div>
|
|
||||||
</div> }
|
|
||||||
</NitroCardGridItemView>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
import { IRoomCameraWidgetEffect } from '@nitrots/nitro-renderer';
|
|
||||||
|
|
||||||
export interface CameraWidgetEffectListItemViewProps
|
|
||||||
{
|
|
||||||
effect: IRoomCameraWidgetEffect;
|
|
||||||
thumbnailUrl: string;
|
|
||||||
isActive: boolean;
|
|
||||||
isLocked: boolean;
|
|
||||||
selectEffect: () => void;
|
|
||||||
removeEffect: () => void;
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
import { IRoomCameraWidgetEffect, IRoomCameraWidgetSelectedEffect } from '@nitrots/nitro-renderer';
|
|
||||||
import { CameraPictureThumbnail } from '../../../common/CameraPictureThumbnail';
|
|
||||||
|
|
||||||
export interface CameraWidgetEffectListViewProps
|
|
||||||
{
|
|
||||||
myLevel: number;
|
|
||||||
selectedEffects: IRoomCameraWidgetSelectedEffect[];
|
|
||||||
effects: IRoomCameraWidgetEffect[];
|
|
||||||
thumbnails: CameraPictureThumbnail[];
|
|
||||||
processAction: (type: string, name: string) => void;
|
|
||||||
}
|
|
@ -3,13 +3,13 @@ import { FC, useCallback, useEffect, useState } from 'react';
|
|||||||
import { AddEventLinkTracker, GetCommunication, RemoveLinkEventTracker } from '../../api';
|
import { AddEventLinkTracker, GetCommunication, RemoveLinkEventTracker } from '../../api';
|
||||||
import { AchievementsView } from '../../components/achievements/AchievementsView';
|
import { AchievementsView } from '../../components/achievements/AchievementsView';
|
||||||
import { AvatarEditorView } from '../../components/avatar-editor/AvatarEditorView';
|
import { AvatarEditorView } from '../../components/avatar-editor/AvatarEditorView';
|
||||||
|
import { CameraWidgetView } from '../../components/camera/CameraWidgetView';
|
||||||
import { CatalogView } from '../../components/catalog/CatalogView';
|
import { CatalogView } from '../../components/catalog/CatalogView';
|
||||||
import { InventoryView } from '../../components/inventory/InventoryView';
|
import { InventoryView } from '../../components/inventory/InventoryView';
|
||||||
import { NavigatorView } from '../../components/navigator/NavigatorView';
|
import { NavigatorView } from '../../components/navigator/NavigatorView';
|
||||||
import { ToolbarView } from '../../components/toolbar/ToolbarView';
|
import { ToolbarView } from '../../components/toolbar/ToolbarView';
|
||||||
import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event';
|
import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event';
|
||||||
import { TransitionAnimation, TransitionAnimationTypes } from '../../layout';
|
import { TransitionAnimation, TransitionAnimationTypes } from '../../layout';
|
||||||
import { CameraWidgetView } from '../camera/CameraWidgetView';
|
|
||||||
import { CampaignView } from '../campaign/CampaignView';
|
import { CampaignView } from '../campaign/CampaignView';
|
||||||
import { ChatHistoryView } from '../chat-history/ChatHistoryView';
|
import { ChatHistoryView } from '../chat-history/ChatHistoryView';
|
||||||
import { FloorplanEditorView } from '../floorplan-editor/FloorplanEditorView';
|
import { FloorplanEditorView } from '../floorplan-editor/FloorplanEditorView';
|
||||||
|
Loading…
Reference in New Issue
Block a user