react-bootstrap#Accordion JavaScript Examples
The following examples show how to use
react-bootstrap#Accordion.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Description.jsx From cosmoscan-front with Apache License 2.0 | 6 votes |
AccordionToggle = styled(Accordion.Toggle)`
border: none;
text-align: left;
cursor: pointer;
transition: background-color 0.2s;
display: flex;
justify-content: space-between;
${({ theme: { blue4 } }) => css`
&:hover {
background-color: ${blue4};
border-color: ${blue4};
}
`}
`
Example #2
Source File: Description.jsx From cosmoscan-front with Apache License 2.0 | 6 votes |
Description = ({ title, desc, className }) => {
const [currEventKey, setCurrEventKey] = useState(null);
return (
<Accordion className={className} onSelect={setCurrEventKey}>
<Card>
<Card.Header as={AccordionToggle} eventKey="0">
<TitleChart>
{ title }
</TitleChart>
<FontAwesomeIcon
icon={currEventKey === '0' ? 'chevron-up' : 'chevron-down'}
/>
</Card.Header>
<Accordion.Collapse eventKey="0">
<Card.Body>
<div
dangerouslySetInnerHTML={{ __html: parseParagraphs(linkify(desc)) }}
className="w-75"
/>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
);
}
Example #3
Source File: accordian-item.js From stacker.news with MIT License | 6 votes |
export default function AccordianItem ({ header, body, headerColor = 'var(--theme-grey)', show }) {
const [open, setOpen] = useState(show)
useEffect(() => {
setOpen(show)
}, [])
return (
<Accordion
defaultActiveKey={show ? '0' : undefined}
>
<Accordion.Toggle
as={props => <div {...props} />}
eventKey='0'
style={{ cursor: 'pointer', display: 'flex', alignItems: 'center' }}
onClick={() => setOpen(!open)}
>
{open
? <ArrowDown style={{ fill: headerColor }} height={20} width={20} />
: <ArrowRight style={{ fill: headerColor }} height={20} width={20} />}
<div style={{ color: headerColor }}>{header}</div>
</Accordion.Toggle>
<Accordion.Collapse eventKey='0' className='mt-2'>
<div>{body}</div>
</Accordion.Collapse>
</Accordion>
)
}
Example #4
Source File: Subsystems.js From Website2020 with MIT License | 5 votes |
function Posts() {
return (
<Router>
<div className="section team-data landing-section">
<Container>
<Row className="d-flex justify-content-center">
<Col className="ml-auto mr-auto" md="12">
<h2 className="text-center heading-main">Subsystems</h2>
</Col>
</Row>
<Accordion defaultActiveKey="0">
<div className="accordian-section">
<Accordion.Toggle as={Card.Header} eventKey="0" className="accordian-toggle text-center">
MECHANICAL <i class="fa fa-cogs fa-lg"></i>
</Accordion.Toggle>
<Accordion.Collapse eventKey="0">
<div>
<Mechanical />
</div>
</Accordion.Collapse>
</div>
<div className="accordian-section">
<Accordion.Toggle as={Card.Header} eventKey="1" className="accordian-toggle text-center">
ELECTRICAL <img src={electronics} style={{ width: "25px", height: "25px" }} />
</Accordion.Toggle>
<Accordion.Collapse eventKey="1">
<div>
<Electrical />
</div>
</Accordion.Collapse>
</div>
<div className="accordian-section">
<Accordion.Toggle as={Card.Header} eventKey="2" className="accordian-toggle text-center my-auto">
SOFTWARE <i class="fa fa-code fa-lg" />
</Accordion.Toggle>
<Accordion.Collapse eventKey="2">
<div>
<Software />
</div>
</Accordion.Collapse>
</div>
<div className="accordian-section">
<Accordion.Toggle as={Card.Header} eventKey="3" className="accordian-toggle text-center">
BUSINESS <i class="fa fa-briefcase fa-lg"></i>
</Accordion.Toggle>
<Accordion.Collapse eventKey="3">
<div>
<Business />
</div>
</Accordion.Collapse>
</div>
</Accordion>
</Container>
</div>
</Router>
);
}
Example #5
Source File: FooterAccordion.js From flotiq-blog with MIT License | 5 votes |
FooterAccordion = ({ data }) => (
<Accordion>
<Card>
<Card.Header>
<ContextAwareToggle eventKey="0">
{data.footer_1_column_header}
</ContextAwareToggle>
</Card.Header>
<Accordion.Collapse eventKey="0">
<Card.Body>
<ul className="main-footer-list">
{data.footer_1_column.map((item) => (
<li key={item.text}>
<a target="_blank" href={item.url} rel="noreferrer">{item.text}</a>
</li>
))}
</ul>
</Card.Body>
</Accordion.Collapse>
</Card>
<Card>
<Card.Header>
<ContextAwareToggle eventKey="1">
{data.footer_2_column_header}
</ContextAwareToggle>
</Card.Header>
<Accordion.Collapse eventKey="1">
<Card.Body>
<ul className="main-footer-list">
{data.footer_2_column.map((item) => (
<li key={item.text}>
<a target="_blank" href={item.url} rel="noreferrer">{item.text}</a>
</li>
))}
</ul>
</Card.Body>
</Accordion.Collapse>
</Card>
<Card>
<Card.Header>
<ContextAwareToggle eventKey="2">
{data.footer_3_column_header}
</ContextAwareToggle>
</Card.Header>
<Accordion.Collapse eventKey="2">
<Card.Body>
<ul className="main-footer-list">
{data.footer_3_column.map((item) => (
<li key={item.text}>
<a target="_blank" href={item.url} rel="noreferrer">{item.text}</a>
</li>
))}
</ul>
</Card.Body>
</Accordion.Collapse>
</Card>
<Card>
<Card.Header>
<ContextAwareToggle eventKey="3">Subscribe</ContextAwareToggle>
</Card.Header>
<Accordion.Collapse eventKey="3">
<Card.Body>
<ul className="main-footer-list">
<SubscriptionForm />
</ul>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
)
Example #6
Source File: ListCard.jsx From caricovidsite with MIT License | 5 votes |
render() {
return (
<div>
{this.state.hideHighestActiveBox ? null : (
<div className="statsCard">
<Accordion>
<Card type="rounded-0" style={cardStyle}>
<Card.Body
className="div-only-mobile-cards"
style={cardBodyStyle}
>
<Card.Text style={cardTextStyle}>
<div
style={dismissMessageStyle}
onClick={this.onClickHideHighest}
>
x
</div>
<AccordionToggle eventKey="1" style={cardTextStyle}>
{this.props.title}
</AccordionToggle>
<Accordion.Collapse eventKey="1">
<div style={dataStyle}>
{this.props.cases?.map((caseEntry) => (
<div>
<b>
{new Intl.NumberFormat().format(
caseEntry[this.props.param]
)}
</b>{" "}
{fetchCountryCode(caseEntry.country) &&
emojiFlags.countryCode(
fetchCountryCode(caseEntry.country)
).emoji}
{caseEntry.country}
</div>
))}
</div>
</Accordion.Collapse>
</Card.Text>
</Card.Body>
</Card>
</Accordion>
</div>
)}
</div>
);
}
Example #7
Source File: SubsystemSpecs.js From Website2020 with MIT License | 4 votes |
function Posts() {
// console.log(specs);
return (
<>
{
<div className="section landing-section">
<Container>
<div className="title-block">
<Row className="justify-content-center heading-components">
<div style={{ textAlign: 'center' }}>
<b style={{ fontSize: "4rem" }}>COMPONENTS</b>
</div>
</Row>
</div>
<Row className="subsystem-headings">
<h3>Mechanical</h3>
</Row>
<FadeIn>
<div className="spec-container">
<Row>
{/* <Col lg="5" className="text-center my-auto imgCol">
<img src={mech_main} alt="spec-img" className="w-100"></img>
<p className="small-heading-edited">
ANAHITA VEHICLE : STRUCTURE
</p>
</Col> */}
<Col lg="1"></Col>
<Col lg="10" className="featureCol my-auto">
The mechanical subsystem is responsible for design and manufacture of the vehicle. Anahita’s mechanical system consists of the vehicle’s frame, grabber, marker dropper, torpedo, connectors and penetrators. The mechanical design of Anahita is made more modular, easy to assemble and robust as compared to its predecessor Varun. Furthermore, the addition of interchangeable components and task specific parts increases the vehicle's modularity significantly.
<div style={{ marginBottom: '20px' }}></div>
{
specs.mechanical.map(
(data) => (
<Accordion defaultActiveKey="">
<Card className="card-plain spec-card">
<Accordion.Toggle className="accord-head" as={Card.Header} eventKey={String(data.id)}>
<svg className="add-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm6 13h-5v5h-2v-5h-5v-2h5v-5h2v5h5v2z" /></svg>
{data.title}
</Accordion.Toggle>
<>
<Accordion.Collapse eventKey={String(data.id)}>
<Card.Body>
<div>
{data.content}
</div>
<div style={{ display: 'grid', placeItems: 'center' }}>
{data.img && <img className="w-75 accord-img" alt="spec-img" src={require("assets/img/anahita/" + data.img)} />}
<div className="card-image-description" style={{ fontFamily: 'monospace', textAlign: 'center' }} >
{data.imgDesc}
</div>
</div>
</Card.Body>
</Accordion.Collapse>
</>
</Card>
</Accordion>
)
)
}
</Col>
<Col lg="1"></Col>
</Row>
</div>
</FadeIn>
<Row className="subsystem-headings">
<h3>Electrical</h3>
</Row>
<FadeIn>
<div className="spec-container">
<Row>
<Col lg="1"></Col>
<Col lg="10" className="my-auto featureCol">
The Electrical System in Anahita acts as an interface between the mechanical structure and software logic. It is designed for providing power, driving actuators and interfacing with various sensors installed in the robot. Major improvements over Varun's electrical system are the custom made PCBs designed to suit the specific needs of Anahita.
<div style={{ marginBottom: '20px' }}></div>
{
specs.electrical.map(
(data) => (
<Accordion defaultActiveKey="">
<Card className="card-plain spec-card">
<Accordion.Toggle className="accord-head" as={Card.Header} eventKey={String(data.id)}>
<svg className="add-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm6 13h-5v5h-2v-5h-5v-2h5v-5h2v5h5v2z" /></svg>
{data.title}
</Accordion.Toggle>
<Accordion.Collapse eventKey={String(data.id)}>
<Card.Body>
<div>
{data.content}
</div>
<div style={{ display: 'grid', placeItems: 'center' }}>
{data.img && <img className="w-75 accord-img" alt="spec-img" src={require("assets/img/anahita/" + data.img)} />}
<div className="card-image-description" style={{ fontFamily: 'monospace', textAlign: 'center' }} >
{data.imgDesc}
</div>
</div>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
)
)
}
</Col>
<Col lg="1"></Col>
{/* <Col md="5" className="text-center my-auto imgCol">
<img src={powerimg} alt="spec-img" className="w-100"></img>
<p className="small-heading-edited">
ELECTRICAL ARCHITECTURE
</p>
</Col> */}
</Row>
</div>
</FadeIn>
<Row className="subsystem-headings">
<h3>Software</h3>
</Row>
<FadeIn>
<div className="spec-container">
<Row>
{/* <Col md="5" className="text-center my-auto imgCol">
<img src={soft} alt="spec-img" className="w-100"></img>
<p className="small-heading-edited">
SOFTWARE DATA & CONTROL FLOW
</p>
</Col> */}
<Col lg="1"></Col>
<Col lg="10" className="my-auto featureCol">
The software stack of Anahita consists of dedicated layers for the hardware integration, controls and navigation, motion planning, perception and acoustic localization. It is built over the Robot Operating System (ROS) framework by Willow Garage, which acts as a communication middleware between all processes running on our robot.
<div style={{ marginBottom: '20px' }}></div>
<Accordion defaultActiveKey="">
<Card className="card-plain spec-card">
<Accordion.Toggle className="accord-head" as={Card.Header} eventKey='100'>
<svg className="add-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm6 13h-5v5h-2v-5h-5v-2h5v-5h2v5h5v2z" /></svg>
Architecture
</Accordion.Toggle>
<Accordion.Collapse eventKey='100' >
<Card.Body>
<div>
In order to make the code modular, it is divided into five layers:
<ol>
<li><b>Master Layer:</b> The master layer is responsible for initiating each process. It instructs the task handler layer to execute node sequence in which the task has to be performed.</li>
<li><b>Task Handler Layer:</b> This layer has task-specific code written for each task and uses a motion library to achieve the target.</li>
<li><b>Motion Library:</b> This layer assists the task handler layer to achieve a goal. It consists of six PID control loops for six degrees of freedom.</li>
<li><b>Vision Layer: </b>The vision layer is responsible for providing the information about the mission elements present in the arena. It detects the targets from the raw image of the camera and provides the coordinates of the vehicle to the task handler layer.</li>
<li><b>Hardware Layer:</b> This layer is responsible for integrating sensors with the software stack. It collects all the information from the sensors and advertises it over topics from where any node that needs it might want to take it. The design specifications are such that it is independent and extendable. As a result, the software can scale concerning the tasks or missions to accomplish.</li>
</ol>
</div>
<div style={{ display: 'grid', placeItems: 'center' }}>
<img className="w-75 accord-img" alt="spec-img" src={require("assets/img/anahita/AnahitaSoft.jpg")} />
<div className="card-image-description" style={{ fontFamily: 'monospace', textAlign: 'center' }} >
SOFTWARE DATA & CONTROL FLOW
</div>
</div>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
{
specs.software.map(
(data) => (
<Accordion>
<Card className="card-plain spec-card">
<Accordion.Toggle className="accord-head" as={Card.Header} eventKey={String(data.id)}>
<svg className="add-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm6 13h-5v5h-2v-5h-5v-2h5v-5h2v5h5v2z" /></svg>
{data.title}
</Accordion.Toggle>
<Accordion.Collapse eventKey={String(data.id)}>
<Card.Body>
<div>
{data.content}
</div>
<div style={{ display: 'grid', placeItems: 'center' }}>
{data.img && <img className="w-75 accord-img" alt="spec-img" src={require("assets/img/anahita/" + data.img)} />}
<div className="card-image-description" style={{ fontFamily: 'monospace', textAlign: 'center' }} >
{data.imgDesc}
</div>
</div>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
)
)
}
</Col>
<Col lg="1"></Col>
</Row>
</div>
</FadeIn>
</Container>
</div>
}
</>
);
}
Example #8
Source File: SubsystemSpecs.js From Website2020 with MIT License | 4 votes |
function Posts() {
// console.log(specs);
return (
<>
{
<div className="section landing-section">
<Container>
<div className="title-block">
<Row className="justify-content-center heading-components">
<div style={{ textAlign: 'center' }}>
<b style={{ fontSize: "4rem" }}>COMPONENTS</b>
</div>
</Row>
</div>
<Row className="subsystem-headings">
<h3>Mechanical</h3>
</Row>
<FadeIn>
<div className="spec-container">
<Row>
<Col lg="1"></Col>
<Col lg="10" className="featureCol my-auto">
Although the design of our previous AUV: Anahita, was acknowledged worldwide, it still had a few flaws. The design involved multiple hulls, leading to high susceptibility to leakages, often damaging the electronic components during pool testing. In addition, multiple hulls and casings limited the accessibility of the internal components, and the positioning of hulls produced relatively high hydrodynamic drag during motion. Finally, the heat dissipation was poor as acrylic is an inferior conductor of heat, resulting in performance degradation and often rendering electronic components inoperable. We tried improving these aspects while designing our new bot.
<div style={{ marginBottom: '20px' }}></div>
{
specs.mechanical.map(
(data) => (
<Accordion defaultActiveKey="">
<Card className="card-plain spec-card">
<Accordion.Toggle className="accord-head" as={Card.Header} eventKey={String(data.id)}>
<svg className="add-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm6 13h-5v5h-2v-5h-5v-2h5v-5h2v5h5v2z"/></svg>
{data.title}
</Accordion.Toggle>
<Accordion.Collapse eventKey={String(data.id)}>
<Card.Body>
<div>
{data.content}
</div>
<div style={{ display: 'grid', placeItems: 'center' }}>
{data.img && <img className={(data.img === 'md working2.PNG') ? 'w-50' : 'w-75'+' accord-img' } alt="spec-img" src={require("assets/img/tarang/" + data.img)} />}
<div className="card-image-description" style={{ fontFamily: 'monospace', textAlign: 'center' }} >
{data.imgDesc}
</div>
</div>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
)
)
}
</Col>
<Col lg="1"></Col>
</Row>
</div>
</FadeIn>
<Row className="subsystem-headings">
<h3>Electrical</h3>
</Row>
<FadeIn>
<div className="spec-container">
<Row>
<Col lg="1"></Col>
<Col lg="10" className="my-auto featureCol">
Tarang's Electrical system includes power sources, sensors, actuators and all the computational resources required for autonomous underwater tasks. We have designed our own PCBs for multiple purposes. This year, we have designed a dedicated power board for power monitoring and distribution to all components. The power system includes a custom buck and boost converter designed to our specifications and requirements with the flexibility of placement and connections. We have also built a custom micro-controller board for Tarang instead of using Arduino boards with shields, saving us a lot of PCB space and cost. The previous micro-controller board (a shield to Arduino Mega) was huge due to unnecessary GPIO pins unused by the Arduino. We use 2 ESC boards with 4 ESCs on each board, of which one ESC on each board is a backup in case of failure. There are 2 layers of stacks inside the hull, which will be used for mounting different electronic devices.
<div style={{ marginBottom: '20px' }}></div>
<Accordion defaultActiveKey="">
<Card className="card-plain spec-card">
<Accordion.Toggle className="accord-head" as={Card.Header} eventKey={42}>
<svg className="add-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm6 13h-5v5h-2v-5h-5v-2h5v-5h2v5h5v2z"/></svg>
Power Distribution
</Accordion.Toggle>
<Accordion.Collapse eventKey={42}>
<Card.Body>
<div>
We use two 14.8V 18A-h batteries to power the complete system. One battery is wholly dedicated to the thrusters, which have a high power consumption and cameras with low power consumption, ensuring supply voltage is within the battery voltage range. The other battery powers all the rest of the electronics by generating 12V and 19V with high-efficiency buck and boost converters, respectively.The microcontroller on the powerboard features a display and multiple LED indicators for battery monitoring and threat alarming.
</div>
<br />
<div><b>Custom made Boost Converter</b></div>
<div>The custom boost converter powers the onboard computer, which operates at 19V. As the power rating for the computer is high (54W), the boost converter had to be very efficient as the computer will be powered on for the complete duration of the mission.
<div style={{ display: 'grid', placeItems: 'center' }}>
<img className="w-50 accord-img" alt="spec-img" src={require("assets/img/tarang/boost_render.png")}/>
<div className="card-image-description" style={{ fontFamily: 'monospace', textAlign: 'center' }} >
Boost Converter
</div>
</div>
</div>
<br />
<div><b>Custom made Buck Converter</b></div>
<div>Most of the low power electronics are powered through the custom-designed buck converter, which outputs 12V. We ensured high efficiency for the buck to minimize the power losses. The power will be controlled through the buck converter using micro-controller GPIO. It will enable us to completely turn it off and save power.
<div style={{ display: 'grid', placeItems: 'center' }}>
<img className="w-50 accord-img" alt="spec-img" src={require("assets/img/tarang/buck_render.png")}/>
<div className="card-image-description" style={{ fontFamily: 'monospace', textAlign: 'center' }} >
Buck Converter
</div>
</div>
</div>
<br />
<div><b>5V power supply for servo</b></div>
<div>The 5V power supply required for driving the servos is created through a regulator with the 12V input from the buck. The power losses of the regulator are insignificant as the regulator will be turned on only for the duration of servo usage. This saves us a lot of space and cost that can be expended in the making/using of another buck converter.We used the RP2040 micro-controller module on the Power board to build a robust and small solution while getting sufficient GPIOs for sensors and other peripherals.</div>
<div style={{ display: 'grid', placeItems: 'center' }}>
<img className="w-100 accord-img" alt="spec-img" src={require("assets/img/tarang/electrical_architecture.jpg")}/>
<div className="card-image-description" style={{ fontFamily: 'monospace', textAlign: 'center' }} >
Tarang's Electrical Architecture
</div>
</div>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
{
specs.electrical.map(
(data) => (
<Accordion>
<Card className="card-plain spec-card">
<Accordion.Toggle className="accord-head" as={Card.Header} eventKey={String(data.id)}>
<svg className="add-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm6 13h-5v5h-2v-5h-5v-2h5v-5h2v5h5v2z"/></svg>
{data.title}
</Accordion.Toggle>
<Accordion.Collapse eventKey={String(data.id)}>
<Card.Body>
<div>
{data.content}
</div>
<div style={{ display: 'grid', placeItems: 'center' }}>
{data.img && <img className="w-75 accord-img" alt="spec-img" src={require("assets/img/tarang/" + data.img)} />}
<div className="card-image-description" style={{ fontFamily: 'monospace', textAlign: 'center' }} >
{data.imgDesc}
</div>
</div>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
)
)
}
{/* </Accordion> */}
</Col>
<Col lg="1"></Col>
</Row>
</div>
</FadeIn>
<Row className="subsystem-headings">
<h3>Software</h3>
</Row>
<FadeIn>
<div className="spec-container">
<Row>
<Col lg="1"></Col>
<Col lg="10" className="my-auto featureCol">
We have improved the software architecture to make the code modular making it easier to test, debug and integrate. In addition, we have made significant advancements in Simultaneous Localization and Mapping strategy (SLAM), tuning of the controller and vision algorithms. The software stack uses the Robot Operating System (ROS noetic) framework by Willow Garage, which works on Ubuntu 20.04 OS that acts as communication middleware between all the processes running on the robot. We have migrated our code from python 2 (which has been deprecated) to python 3. In addition to it, we have also updated the code for our previous vehicles to use the latest versions of the third-party libraries like OpenCV, YOLO and other ROS packages.
<div style={{ marginBottom: '20px' }}></div>
<Accordion defaultActiveKey="">
<Card className="card-plain spec-card">
<Accordion.Toggle className="accord-head" as={Card.Header} eventKey={42}>
<svg className="add-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm6 13h-5v5h-2v-5h-5v-2h5v-5h2v5h5v2z"/></svg>
Software Architecture
</Accordion.Toggle>
<Accordion.Collapse eventKey={42}>
<Card.Body>
<div>
The software stack of Tarang consists of dedicated layers for hardware integration, controls, navigation, motion planning and acoustic localization. The software stack consists of the following layers:
<ol>
<li>
<b>Master Layer:</b> It controls and coordinates the actions of all other layers to perform the tasks autonomously. All the decision making and strategy gets coded in the master layer, which commands the nodes in the other layers to perform different functions. The master layer contains the task-specific code. The signals and instructions for completing all the tasks originate from the master layer.
</li>
<li>
<b>Control Layer:</b> It contains the implementation of the cascaded PID controller the bot uses. The control layer calculates the thrust for each of the thrusters to manoeuvre the bot as desired. It also generates the trajectory and waypoints to perform the wanted task.
</li>
<li>
<b>Navigation Layer:</b> It contains the code for the Simultaneous Localization and Mapping (SLAM) algorithm. It performs sensor fusion, estimates the bot's current position in the world, and generates the world's map based upon the filtered sensor information.
</li>
<li>
<b>Vision Layer:</b> It contains the code for all the image processing and vision-related tasks. The vision layer receives the feed directly from the cameras, performs computation on the received data for preprocessing, object detection or visual odometry and sends the processed output to other nodes which require it.
</li>
<li>
<b>Hardware Layer:</b> It is responsible for integrating sensors with the software stack. It collects the sensors-specific plugins and utilities to receive information from the sensors and publishes it on topics for the other nodes to use.
</li>
</ol>
</div>
<br />
<div>
Advantages of such a software architecture are:
<ol>
<li>It makes the development easier as different layers can be developed independently and tested asynchronously.</li>
<li>It enables easy debugging and troubleshooting.</li>
<li>It ensures that the code is scalable and maintainable and provides a straightforward way to integrate external libraries and expand the codebase.</li>
</ol>
</div>
<div style={{ display: 'grid', placeItems: 'center' }}>
{<img className="w-100 accord-img" alt="spec-img" src={require("assets/img/tarang/Software_Architecture.png")} />}
<div className="card-image-description" style={{ fontFamily: 'monospace', textAlign: 'center' }} >
Tarang's Software Architecture
</div>
</div>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
<Accordion>
<Card className="card-plain spec-card">
<Accordion.Toggle className="accord-head" as={Card.Header} eventKey={43}>
<svg className="add-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm6 13h-5v5h-2v-5h-5v-2h5v-5h2v5h5v2z"/></svg>
Image-Preprocessing
</Accordion.Toggle>
<Accordion.Collapse eventKey={43}>
<Card.Body>
<div><b>Undistortion</b></div>
<div>We preprocess the video feed by applying multiple filters before extracting any information from it. Since the images are used to estimate the location of various objects and the vehicle itself, the lengths represented in the images must be true. The camera distorts the features in the image changing their shape and length, so images are undistorted in the preprocessing pipeline. To undistort images, we need to have distortion coefficients of the camera. To obtain these, we need to calibrate the camera using images of known size and shape images. In our case, a checkerboard pattern distortion known beforehand was used to calculate these coefficients. </div>
<br />
<div><b>Relative Global Histogram Stretching</b></div>
<div>The Relative Global Histogram Stretching method aims to improve image quality by applying contrast correction and colour correction to the camera output. </div>
<br />
<div><b>Contrast Correction</b></div>
<div>The contrast correction pipeline applies colour equalization on the image's green-blue(G-B) channels, followed by relative global histogram stretching.</div>
<br />
<div><b>Bilateral Filter</b></div>
<div>A bilateral filter reduces the noise by using a non-linear smoothing filter to the image. The contrast-corrected image is then passed to the colour correction phase, which converts the image to CIE-Lab colour space and stretches L, a and b components followed by CIE-Lab to RGB conversion</div>
<div style={{ display: 'grid', placeItems: 'center' }}>
{<img className="w-75 accord-img" alt="spec-img" src={require("assets/img/tarang/processing_combined.png")} />}
<div className="card-image-description" style={{ fontFamily: 'monospace', textAlign: 'center' }} >
Image Before Preprocessing Vs Image After Preprocessing
</div>
</div>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
{
specs.software.map(
(data) => (
<Accordion>
<Card className="card-plain spec-card">
<Accordion.Toggle className="accord-head" as={Card.Header} eventKey={String(data.id)}>
<svg className="add-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm6 13h-5v5h-2v-5h-5v-2h5v-5h2v5h5v2z"/></svg>
{data.title}
</Accordion.Toggle>
<Accordion.Collapse eventKey={String(data.id)}>
<Card.Body>
<div>
{data.content}
</div>
<div style={{ display: 'grid', placeItems: 'center' }}>
{data.img && <img className="w-75 accord-img" alt="spec-img" src={require("assets/img/tarang/" + data.img)} />}
<div className="card-image-description" style={{ fontFamily: 'monospace', textAlign: 'center' }} >
{data.imgDesc}
</div>
</div>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
)
)
}
{/* </Accordion> */}
</Col>
<Col lg="1"></Col>
</Row>
</div>
</FadeIn>
</Container>
</div>
}
</>
);
}
Example #9
Source File: SubsystemSpecs.js From Website2020 with MIT License | 4 votes |
function Posts() {
return (
<>
{
<div className="section landing-section">
<Container>
<div className="title-block">
<Row className="justify-content-center heading-components">
<div style={{ textAlign: 'center' }}>
<b style={{ fontSize: "4rem" }}>COMPONENTS</b>
</div>
</Row>
</div>
<Row className="subsystem-headings">
<h3>Mechanical</h3>
</Row>
<FadeIn>
<div className="spec-container">
<Row>
{/* <Col lg="5" className="text-center my-auto imgCol">
<img src={mech_main} alt="spec-img" className="w-100"></img>
<p className="small-heading-edited">
VARUN: STRUCTURE
</p>
</Col> */}
<Col lg="1"></Col>
<Col lg="10" className="featureCol my-auto">
Varun's mechanical system comprises an aluminium structural frame, pressure casings, and electromagnetic actuators. The mechanical parts were first designed in Solidworks and Autodesk Inventor and then improved using Ansys Workbench before its final fabrication using available in-house facilities at the institute.
<div style={{ marginBottom: '20px' }}></div>
{
specs.mechanical.map(
(data) => (
<Accordion defaultActiveKey="">
<Card className="card-plain spec-card">
<Accordion.Toggle className="accord-head" as={Card.Header} eventKey={String(data.id)}>
<svg className="add-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm6 13h-5v5h-2v-5h-5v-2h5v-5h2v5h5v2z" /></svg>
{data.title}
</Accordion.Toggle>
<Accordion.Collapse eventKey={String(data.id)}>
<Card.Body>
<div>
{data.content}
</div>
<div style={{ display: 'grid', placeItems: 'center' }}>
{data.img && <img className="w-75 accord-img" alt="spec-img" src={require("assets/img/varun/VARUN-AUV/" + data.img)} />}
<div className="card-image-description" style={{ fontFamily: 'monospace', textAlign: 'center' }} >
{data.imgDesc}
</div>
</div>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
)
)
}
</Col>
<Col lg="1"></Col>
</Row>
</div>
</FadeIn>
<Row className="subsystem-headings">
<h3>Electrical</h3>
</Row>
<FadeIn>
<div className="spec-container">
<Row>
<Col lg="1"></Col>
<Col lg="10" className="my-auto featureCol">
The Electrical system provides the interface between the processor and the other electronic devices. There will be three layers of stacks inside the hull, which will be used for mounting different electronic devices and PCBs.The Arduino used in Varun is the ATmega1280 microcontroller and has an operating voltage of 5V. It has 16 Analog input pins and 54 digital I/O pins (of which 15 provide PWM output). The open-source Arduino platform is used to process the input signals from the main processor and convert it into desired signals to the actuators like motor drivers and pneumatic system.
<div style={{ marginBottom: '20px' }}></div>
{
specs.electrical.map(
(data) => (
<Accordion defaultActiveKey="">
<Card className="card-plain spec-card">
<Accordion.Toggle className="accord-head" as={Card.Header} eventKey={String(data.id)}>
<svg className="add-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm6 13h-5v5h-2v-5h-5v-2h5v-5h2v5h5v2z" /></svg>
{data.title}
</Accordion.Toggle>
<Accordion.Collapse eventKey={String(data.id)}>
<Card.Body>
<div>
{data.content}
</div>
<div style={{ display: 'grid', placeItems: 'center' }}>
{data.img && <img className="w-75 accord-img" alt="spec-img" src={require("assets/img/varun/VARUN-AUV/" + data.img)} />}
<div className="card-image-description" style={{ fontFamily: 'monospace', textAlign: 'center' }} >
{data.imgDesc}
</div>
</div>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
)
)
}
</Col>
<Col lg="1"></Col>
{/* <Col lg="5" className="text-center my-auto imgCol">
<img src={elec_main} alt="spec-img" className="w-100"></img>
<p className="small-heading-edited">
VARUN: ELECTRICAL ARCHITECTURE
</p>
</Col> */}
</Row>
</div>
</FadeIn>
<Row className="subsystem-headings">
<h3>Software</h3>
</Row>
<FadeIn>
<div className="spec-container">
<Row>
{/* <Col lg="5" className="text-center my-auto imgCol">
<img src={soft_main} alt="spec-img" className="w-100"></img>
<p className="small-heading-edited">
VARUN: SOFTWARE ARCHIETECTURE
</p>
</Col> */}
<Col lg="1"></Col>
<Col lg="10" className="my-auto featureCol">
The Software Architecture of Varun is based on the Robot Operating System (ROS) Software Framework from Willow Garage, which encompasses the underlying messaging infrastructure for inter-process communications in our distributed system.
<div style={{ marginBottom: '20px' }}></div>
{
specs.software.map(
(data) => (
<Accordion defaultActiveKey="">
<Card className="card-plain spec-card">
<Accordion.Toggle className="accord-head" as={Card.Header} eventKey={String(data.id)}>
<svg className="add-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm6 13h-5v5h-2v-5h-5v-2h5v-5h2v5h5v2z" /></svg>
{data.title}
</Accordion.Toggle>
<Accordion.Collapse eventKey={String(data.id)}>
<Card.Body>
<div>
{data.content}
</div>
<div style={{ display: 'grid', placeItems: 'center' }}>
{data.img && <img className="w-75 accord-img" alt="spec-img" src={require("assets/img/varun/VARUN-AUV/" + data.img)} />}
<div className="card-image-description" style={{ fontFamily: 'monospace', textAlign: 'center' }} >
{data.imgDesc}
</div>
</div>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
)
)
}
</Col>
<Col lg="1"></Col>
</Row>
</div>
</FadeIn>
</Container>
</div>
}
</>
);
}
Example #10
Source File: index.js From ActiveLearningStudio-react-client with GNU Affero General Public License v3.0 | 4 votes |
function ExistingActivitySearch(props) {
const { fromTeam, addActivity, libraries } = props;
const [toggleStates, setToggleStates] = useState({
searchLibrary: true,
subject: true,
education: false,
type: false,
});
const allState = useSelector((state) => state.search);
const activityTypesState = useSelector((state) => state.resource.types);
const { currentOrganization, permission } = useSelector((state) => state.organization);
const dispatch = useDispatch();
const [activityTypes, setActivityTypes] = useState([]);
const [search, setSearch] = useState([]);
const [searchQueries, SetSearchQuery] = useState('');
const [searchInput, setSearchInput] = useState('');
const [meta, setMeta] = useState({});
const [activePage, setActivePage] = useState(1);
const [totalCount, setTotalCount] = useState(0);
const [activeModel, setActiveModel] = useState('activities');
const [activeType, setActiveType] = useState([]);
const [activeSubject, setActiveSubject] = useState([]);
const [activeEducation, setActiveEducation] = useState([]);
const [searchType, setSearchType] = useState(null);
const [authorName, SetAuthor] = useState('');
const [activetab, setActiveTab] = useState('activities');
const [todate, Settodate] = useState(undefined);
const [fromdate, Setfromdate] = useState(undefined);
useEffect(() => {
if (localStorage.getItem('refreshPage') === 'true' && currentOrganization && searchType) {
let dataSend;
if (searchType === 'orgSearch') {
dataSend = {
phrase: searchInput.trim(),
subjectArray: activeSubject,
gradeArray: activeEducation,
standardArray: activeType,
author: authorName || undefined,
type: searchType,
from: 0,
size: 20,
model: 'activities',
standardArray: libraries,
};
} else {
dataSend = {
phrase: searchInput.trim(),
subjectArray: activeSubject,
gradeArray: activeEducation,
standardArray: activeType,
author: authorName || undefined,
type: searchType,
from: 0,
size: 20,
model: 'activities',
standardArray: libraries,
};
}
let result;
(async () => {
result = await dispatch(simpleSearchAction(dataSend));
})();
setTotalCount(result?.meta?.total);
const tempEducation = [];
const tempSubject = [];
if (activeEducation) {
activeEducation.forEach((edu) => {
if (String(edu).includes('&')) {
const temp = String(edu).replace('&', 'and');
tempEducation.push(temp);
} else {
tempEducation.push(edu);
}
});
setActiveEducation(tempEducation);
}
if (activeSubject) {
activeSubject.forEach((sub) => {
if (String(sub).includes('&')) {
const temp = String(sub).replace('&', 'and');
tempSubject.push(temp);
} else {
tempSubject.push(sub);
}
});
setActiveSubject(tempSubject);
}
}
}, [currentOrganization]);
useEffect(() => {
if (allState.searchResult) {
if (allState.searchResult.length > 0) {
setSearch(allState.searchResult);
SetSearchQuery(allState.searchQuery);
setSearchInput(allState.searchQuery);
setMeta(allState.searchMeta);
localStorage.setItem('loading', 'false');
Swal.close();
} else if (allState.searchMeta.total === 0) {
setSearch([]);
SetSearchQuery(allState.searchQuery);
setSearchInput(allState.searchQuery);
setMeta({});
localStorage.setItem('loading', 'false');
Swal.close();
}
}
}, [allState.searchMeta, allState.searchQuery, allState.searchResult]);
useEffect(() => {
if (allState.searchResult) {
if (allState.searchResult.length > 0 && paginationStarter) {
paginationStarter = false;
setTotalCount(allState.searchMeta.total);
}
}
}, [allState.searchMeta, allState.searchResult, totalCount]);
useEffect(() => {
if (localStorage.getItem('loading') === 'true') {
Swal.fire({
html: 'Searching...', // add html attribute if you want or remove
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
}
});
useEffect(() => {
if (activityTypesState.length === 0) {
dispatch(loadResourceTypesAction());
}
}, []);
const compare = (a, b) => {
// Use toUpperCase() to ignore character casing
const bandA = a.title.toUpperCase();
const bandB = b.title.toUpperCase();
let comparison = 0;
if (bandA > bandB) {
comparison = 1;
} else if (bandA < bandB) {
comparison = -1;
}
return comparison;
};
useEffect(() => {
const allItems = [];
activityTypesState?.data?.map((data) => data.activityItems.map((itm) => allItems.push(itm)));
setActivityTypes(allItems.sort(compare));
}, [activityTypesState]);
return (
<>
<div>
<div className={!fromTeam && 'search-wrapper'}>
<div className="content-search">
{true ? (
<div className="search-result-main">
{!fromTeam && <div className="current-org-search">{currentOrganization?.name}</div>}
{!fromTeam && <div className="exp-lib-cnt">Explore library content</div>}
<div
className="total-count"
style={{
display: totalCount > 1000 || !!searchQueries ? 'block' : 'none',
}}
>
{totalCount > 10000 ? (
<div>
Your search returned more than <span>10,000</span> results. Please refine your search criteria.
</div>
) : null}
{!!searchQueries && (
<div>
Showing {search ? meta.total : '0'} results For <span>{searchQueries}</span>
</div>
)}
</div>
<div className="main-content-search">
<div className="left-search">
<div className="search-library">
<Accordion defaultActiveKey="0">
<Card>
<Accordion.Toggle
as={Card.Header}
eventKey="0"
onClick={() =>
setToggleStates({
...toggleStates,
searchLibrary: !toggleStates.searchLibrary,
})
}
>
Search Library
<FontAwesomeIcon className="ml-2" icon={toggleStates.searchLibrary ? 'chevron-up' : 'chevron-down'} />
</Accordion.Toggle>
<Accordion.Collapse eventKey="0">
<Card.Body>
<div className="body-search">
<input
// style={{ display: searchType === 'orgSearch' ? 'none' : 'block' }}
value={searchInput}
onChange={(e) => {
setSearchInput(e.target.value);
}}
onKeyPress={async (e) => {
if (e.key === 'Enter') {
if (!searchInput.trim() && searchType !== 'orgSearch') {
Swal.fire('Search field is required.');
} else if (searchInput.length > 255) {
Swal.fire('Character limit should be less than 255.');
} else {
Swal.fire({
title: 'Searching...', // add html attribute if you want or remove
html: 'We are fetching results for you!',
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
let dataSend;
if (searchType === 'orgSearch') {
dataSend = {
phrase: searchInput.trim(),
subjectArray: activeSubject,
gradeArray: activeEducation,
authors: authorName || undefined,
standardArray: activeType,
type: searchType,
from: 0,
size: 20,
model: 'activities',
standardArray: libraries,
};
} else {
dataSend = {
phrase: searchInput.trim(),
subjectArray: activeSubject,
gradeArray: activeEducation,
authors: authorName || undefined,
standardArray: activeType,
type: searchType,
from: 0,
size: 20,
model: 'activities',
standardArray: libraries,
};
}
const result = await dispatch(simpleSearchAction(dataSend));
setTotalCount(result.meta?.total);
const tempEducation = [];
const tempSubject = [];
if (activeEducation) {
activeEducation.forEach((edu) => {
if (String(edu).includes('&')) {
const temp = String(edu).replace('&', 'and');
tempEducation.push(temp);
} else {
tempEducation.push(edu);
}
});
setActiveEducation(tempEducation);
}
if (activeSubject) {
activeSubject.forEach((sub) => {
if (String(sub).includes('&')) {
const temp = String(sub).replace('&', 'and');
tempSubject.push(temp);
} else {
tempSubject.push(sub);
}
});
setActiveSubject(tempSubject);
}
}
}
}}
type="search"
placeholder="Search"
/>
<div className="form-group">
<div className="radio-btns">
{true && (
<label>
<input
name="type"
onChange={(e) => {
setSearchType(e.target.value);
}}
value="private"
checked={searchType === 'private'}
type="radio"
/>
<span>My Projects</span>
</label>
)}
{true && (
<label>
<input
name="type"
onChange={(e) => {
setSearchType(e.target.value);
}}
value="public"
checked={searchType === 'public'}
type="radio"
/>
<span>All Shared Projects</span>
</label>
)}
{true && (
<label>
<input
name="type"
onChange={(e) => {
setSearchType(e.target.value);
}}
value="orgSearch"
checked={searchType === 'orgSearch'}
type="radio"
/>
<span>All Shared Projects In My Org</span>
</label>
)}
</div>
</div>
{permission?.Organization?.includes('organization:view-user') && searchType !== 'private' && <div className="author-label">Author</div>}
<div
className="form-group"
style={{
display: permission?.Organization?.includes('organization:view-user') && searchType !== 'private' ? 'block' : 'none',
}}
>
<input
placeholder="Enter author name"
className="authorName"
value={authorName}
onChange={({ target }) => {
if (target.value) {
SetAuthor(target.value);
} else {
SetAuthor('');
}
}}
/>
</div>
<div
className="src-btn"
onClick={async () => {
Setfromdate(undefined);
Settodate(undefined);
setActiveTab('activities');
if (!searchInput.trim() && searchType !== 'orgSearch') {
Swal.fire('Search field is required.');
} else if (searchInput.length > 255) {
Swal.fire('Character limit should be less than 255.');
} else if (!searchType) {
Swal.fire('Search type is required. Click one of the radio buttons.');
} else {
Swal.fire({
title: 'Searching...', // add html attribute if you want or remove
html: 'We are fetching results for you!',
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
let dataSend;
if (searchType === 'orgSearch') {
dataSend = {
phrase: searchInput.trim(),
subjectArray: activeSubject,
gradeArray: activeEducation,
standardArray: activeType,
author: authorName || undefined,
fromDate: fromdate || undefined,
toDate: todate || undefined,
type: searchType,
from: 0,
size: 20,
model: 'activities',
standardArray: libraries,
};
} else {
dataSend = {
phrase: searchInput.trim(),
subjectArray: activeSubject,
author: authorName || undefined,
fromDate: fromdate || undefined,
toDate: todate || undefined,
gradeArray: activeEducation,
standardArray: activeType,
type: searchType,
from: 0,
size: 20,
model: 'activities',
standardArray: libraries,
};
}
const result = await dispatch(simpleSearchAction(dataSend));
setTotalCount(result.meta?.total);
const tempEducation = [];
const tempSubject = [];
if (activeEducation) {
activeEducation.forEach((edu) => {
if (String(edu).includes('&')) {
const temp = String(edu).replace('&', 'and');
tempEducation.push(temp);
} else {
tempEducation.push(edu);
}
});
setActiveEducation(tempEducation);
}
if (activeSubject) {
activeSubject.forEach((sub) => {
if (String(sub).includes('&')) {
const temp = String(sub).replace('&', 'and');
tempSubject.push(temp);
} else {
tempSubject.push(sub);
}
});
setActiveSubject(tempSubject);
}
}
}}
>
<FontAwesomeIcon icon="search" />
Search
</div>
</div>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
</div>
<div className="refine-search">
<div className="headline">Refine your search</div>
<Accordion defaultActiveKey="0">
<Card>
<Accordion.Toggle
as={Card.Header}
eventKey="0"
onClick={() =>
setToggleStates({
...toggleStates,
type: false,
education: false,
subject: !toggleStates.subject,
})
}
>
Subject
<FontAwesomeIcon className="ml-2" icon={toggleStates.subject ? 'chevron-up' : 'chevron-down'} />
</Accordion.Toggle>
<Accordion.Collapse eventKey="0">
<Card.Body>
{subjects.map((data) => (
<div
className="list-item-keys"
key={data.value}
value={data.subject}
onClick={() => {
if (activeSubject.includes(data.subject)) {
if (data.subject === 'Career & Technical Education') {
setActiveSubject(
activeSubject.filter((index) => {
if (index === 'Career & Technical Education' || index === 'Career and Technical Education') {
return false;
}
return true;
})
);
} else {
setActiveSubject(activeSubject.filter((index) => index !== data.subject));
}
} else {
setActiveSubject([...activeSubject, data.subject]);
}
}}
>
{data.subject === 'Career & Technical Education' ? (
activeSubject.includes('Career & Technical Education') || activeSubject.includes('Career and Technical Education') ? (
<FontAwesomeIcon icon="check-square" />
) : (
<FontAwesomeIcon icon="square" />
)
) : activeSubject.includes(data.subject) ? (
<FontAwesomeIcon icon="check-square" />
) : (
<FontAwesomeIcon icon="square" />
)}
<span>{data.subject}</span>
</div>
))}
</Card.Body>
</Accordion.Collapse>
</Card>
<Card>
<Accordion.Toggle
as={Card.Header}
eventKey="1"
onClick={() =>
setToggleStates({
...toggleStates,
type: false,
subject: false,
education: !toggleStates.education,
})
}
>
Education Level
<FontAwesomeIcon className="ml-2" icon={toggleStates.education ? 'chevron-up' : 'chevron-down'} />
</Accordion.Toggle>
<Accordion.Collapse eventKey="1">
<Card.Body>
{educationLevels.map((data) => (
<div
className="list-item-keys"
key={data.value}
value={data.name}
onClick={() => {
if (activeEducation.includes(data.name)) {
if (data.name === 'College & Beyond') {
setActiveEducation(
activeEducation.filter((index) => {
if (index === 'College & Beyond' || index === 'College and Beyond') {
return false;
}
return true;
})
);
} else {
setActiveEducation(activeEducation.filter((index) => index !== data.name));
}
} else {
setActiveEducation([...activeEducation, data.name]);
}
}}
>
{data.name === 'College & Beyond' ? (
activeEducation.includes('College & Beyond') || activeEducation.includes('College and Beyond') ? (
<FontAwesomeIcon icon="check-square" />
) : (
<FontAwesomeIcon icon="square" />
)
) : activeEducation.includes(data.name) ? (
<FontAwesomeIcon icon="check-square" />
) : (
<FontAwesomeIcon icon="square" />
)}
<span>{data.name}</span>
</div>
))}
</Card.Body>
</Accordion.Collapse>
</Card>
<Card>
<Accordion.Toggle
as={Card.Header}
eventKey="3"
onClick={() =>
setToggleStates({
...toggleStates,
subject: false,
education: false,
type: !toggleStates.type,
})
}
>
Type of Activity
<FontAwesomeIcon className="ml-2" icon={toggleStates.type ? 'chevron-up' : 'chevron-down'} />
</Accordion.Toggle>
<Accordion.Collapse eventKey="3">
<Card.Body
style={{
'max-height': '300px',
'overflow-y': 'auto',
}}
>
{activityTypes.map((data) => (
<div
className="list-item-keys"
key={data.id}
value={data.h5pLib}
onClick={() => {
if (activeType.includes(data.h5pLib)) {
// eslint-disable-next-line eqeqeq
setActiveType(activeType.filter((index) => index != data.h5pLib));
} else {
setActiveType([...activeType, data.h5pLib]);
}
}}
>
{activeType.includes(data.h5pLib) ? <FontAwesomeIcon icon="check-square" /> : <FontAwesomeIcon icon="square" />}
<span>{data.title}</span>
</div>
))}
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
</div>
</div>
<div className="right-search" id="right-search-branding-style">
<Tabs
activeKey={activetab}
id="uncontrolled-tab-example"
onSelect={async (e) => {
if (!searchInput && searchType !== 'orgSearch') {
Swal.fire('Search field is required.');
} else {
setActiveTab(e);
if (e === 'total') {
let searchData;
if (searchType === 'orgSearch') {
searchData = {
phrase: searchQueries.trim() || searchInput,
from: 0,
size: 20,
type: searchType,
author: authorName || undefined,
fromDate: fromdate || undefined,
toDate: todate || undefined,
subjectArray: activeSubject,
gradeArray: activeEducation,
standardArray: activeType,
};
} else {
searchData = {
phrase: searchQueries.trim() || searchInput,
from: 0,
size: 20,
author: authorName || undefined,
fromDate: fromdate || undefined,
toDate: todate || undefined,
type: searchType,
subjectArray: activeSubject,
gradeArray: activeEducation,
standardArray: activeType,
};
}
Swal.fire({
title: 'Loading...', // add html attribute if you want or remove
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
const resultModel = await dispatch(simpleSearchAction(searchData));
Swal.close();
setTotalCount(resultModel.meta[e]);
setActiveModel(e);
setActivePage(1);
} else {
let searchData;
if (searchType === 'orgSearch') {
searchData = {
phrase: searchQueries.trim() || searchInput,
from: 0,
size: 20,
author: authorName || undefined,
fromDate: fromdate || undefined,
toDate: todate || undefined,
model: e,
type: searchType,
subjectArray: activeSubject,
gradeArray: activeEducation,
standardArray: activeType,
standardArray: libraries,
};
} else {
searchData = {
phrase: searchQueries.trim() || searchInput,
from: 0,
size: 20,
model: e,
author: authorName || undefined,
fromDate: fromdate || undefined,
toDate: todate || undefined,
type: searchType,
subjectArray: activeSubject,
gradeArray: activeEducation,
standardArray: activeType,
standardArray: libraries,
};
}
Swal.fire({
title: 'Loading...', // add html attribute if you want or remove
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
const resultModel = await dispatch(simpleSearchAction(searchData));
Swal.close();
setTotalCount(resultModel.meta[e]);
setActiveModel(e);
setActivePage(1);
}
}
}}
>
{!fromTeam && (
<Tab eventKey="activities" title={!!search && !!meta.activities ? `activity (${meta.activities})` : 'activity (0)'}>
<div className="content">
<div className="results_search">
{!!search && search.length > 0 ? (
search.map((res) => (
<>
{res.model === 'Activity' && (
<div className="box">
<div className="imgbox">
{res.thumb_url ? (
<div
style={{
backgroundImage: res.thumb_url.includes('pexels.com')
? `url(${res.thumb_url})`
: `url(${global.config.resourceUrl}${res.thumb_url})`,
}}
/>
) : (
<div
style={{
// eslint-disable-next-line max-len
backgroundImage:
'https://images.pexels.com/photos/593158/pexels-photo-593158.jpeg?auto=compress&cs=tinysrgb&dpr=1&fit=crop&h=200&w=280',
}}
/>
)}
</div>
<div className="contentbox">
<div className="search-content">
<a
href={
res.model === 'Activity'
? `/activity/${res.id}/preview`
: res.model === 'Playlist'
? `/playlist/${res.id}/preview/lti`
: `/project/${res.id}/preview`
}
target="_blank"
rel="noreferrer"
>
<h2>{res.title || res.name}</h2>
</a>
<ul>
{res.user && (
<li>
by <span>{res.user.first_name}</span>
</li>
)}
<li>
Type <span className="type">{res.model}</span>
</li>
</ul>
<p>{res.description}</p>
</div>
<Buttons text="Add" secondary={true} width="153px" height="36px" onClick={() => addActivity(res)} hover={true} />
</div>
</div>
)}
</>
))
) : (
<div className="box">No result found !</div>
)}
</div>
</div>
</Tab>
)}
</Tabs>
{totalCount > 20 && (
<Pagination
activePage={activePage}
itemsCountPerPage={20}
totalItemsCount={totalCount > 10000 ? 10000 : totalCount}
pageRangeDisplayed={8}
onChange={async (e) => {
setActivePage(e);
if (activeModel === 'total') {
const searchData = {
phrase: searchQueries.trim(),
from: e * 20 - 20,
size: 20,
type: searchType,
subjectArray: activeSubject || undefined,
gradeArray: activeEducation || undefined,
standardArray: activeType || undefined,
author: authorName || undefined,
};
Swal.fire({
title: 'Loading...',
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
await dispatch(simpleSearchAction(searchData));
Swal.close();
} else {
const searchData = {
phrase: searchQueries.trim(),
from: e * 20 - 20,
size: 20,
type: searchType,
model: activeModel,
subjectArray: activeSubject || undefined,
gradeArray: activeEducation || undefined,
standardArray: activeType || undefined,
author: authorName || undefined,
standardArray: libraries,
};
Swal.fire({
title: 'Loading...',
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
await dispatch(simpleSearchAction(searchData));
Swal.close();
}
}}
itemClass="page-item"
linkClass="page-link"
/>
)}
</div>
</div>
</div>
) : (
<Alert variant="danger">You are not authorized to view this page!</Alert>
)}
</div>
</div>
</div>
</>
);
}
Example #11
Source File: index.js From ActiveLearningStudio-react-client with GNU Affero General Public License v3.0 | 4 votes |
LTIProjectShared = (props) => {
const [activeProject, setActiveProject] = useState(null);
const [activePlaylist, setActivePlaylist] = useState(null);
const [activeActivity, setActiveActivity] = useState(null);
const [defaultPlaylist, setDefaultPlaylist] = useState(null);
const [allProjects, setAllProjects] = useState([]);
const [formData, setFormData] = useState({});
const dispatch = useDispatch();
const project = useSelector((state) => state.project);
const { match } = props;
useEffect(() => {
dispatch(
loadMyProjectsLtiAction(
decodeURIComponent(match.params.lmsUrl),
decodeURIComponent(match.params.ltiClientId),
),
);
}, [dispatch, match.params.lmsUrl, match.params.ltiClientId]);
useEffect(() => {
if (project.projects) {
setAllProjects(project.projects);
}
}, [project.projects]);
return (
<div className="lti-all-project">
<Accordion>
{!!allProjects && allProjects.map((data, counterTop) => (
<Card>
<Card.Header className="top-card">
<Accordion.Toggle
as={Button}
variant="link"
eventKey={counterTop + 1}
className="top-card-btn"
>
<span
onClick={() => {
if (activeProject === counterTop + 1) {
setActiveProject(null);
} else {
setActiveProject(counterTop + 1);
setActiveActivity(null);
}
// setActivePlaylist(null);
}}
>
<div className="flex-bar">
<div>
{/* {activeProject === counterTop + 1 ? (
<i
className="fa fa-check-square"
aria-hidden="true"
/>
) : (
<i className="fa fa-square" aria-hidden="true" />
)} */}
{data.name}
</div>
{activeProject === counterTop + 1 ? (
<FontAwesomeIcon icon="chevron-up" />
) : (
<FontAwesomeIcon icon="chevron-down" />
)}
</div>
</span>
</Accordion.Toggle>
</Card.Header>
<Accordion.Collapse eventKey={counterTop + 1}>
<Card.Body>
{!!data.playlists && data.playlists.length > 0 ? (
<Accordion>
{data.playlists.map((data2, counterPlaylist) => (
<Card>
<Card.Header className="middle-card">
<Accordion.Toggle
as={Button}
variant="link"
eventKey={counterPlaylist + counterTop + 1}
>
<span
onClick={() => {
if (activePlaylist === counterPlaylist + counterTop + 1) {
setActivePlaylist(null);
setFormData({});
} else {
if (!activeActivity) {
setActivePlaylist(counterPlaylist + counterTop + 1);
}
setActiveActivity(null);
setDefaultPlaylist(data2.id);
setFormData({
name: data2.title,
id: data2.id,
entity: 'playlist',
});
}
}}
>
<div className="flex-bar">
<div>
<span>
{activePlaylist === (counterPlaylist + counterTop + 1) ? (
<FontAwesomeIcon icon="stop-circle" className="mr-2" />
) : (
<FontAwesomeIcon icon="circle" className="mr-2" />
)}
{data2.title}
</span>
</div>
{activePlaylist === (counterPlaylist + counterTop + 1) ? (
<FontAwesomeIcon icon="chevron-up" />
) : (
<FontAwesomeIcon icon="chevron-down" />
)}
</div>
</span>
</Accordion.Toggle>
</Card.Header>
<Accordion.Collapse eventKey={counterPlaylist + counterTop + 1}>
<Card.Body className="last-card">
{!!data2.activities && data2.activities.length > 0 ? (
<ul>
{data2.activities.map(
(data3, counter3) => (
<li
onClick={() => {
if (activeActivity === counter3) {
setActiveActivity(null);
setFormData(null);
setDefaultPlaylist(data2.id);
setActivePlaylist(counterPlaylist + counterTop + 1);
setFormData({
name: data2.title,
id: data2.id,
entity: 'playlist',
});
} else {
setActiveActivity(counter3);
setActivePlaylist(null);
setFormData({
name: data3.title,
id: data3.id,
entity: 'activity',
});
}
}}
key={counter3}
>
{activeActivity === counter3 ? (
<FontAwesomeIcon icon="stop-circle" className="mr-2" />
) : (
<FontAwesomeIcon icon="circle" className="mr-2" />
)}
{data3.title}
</li>
),
)}
</ul>
) : (
<span className="error">
No activity found
</span>
)}
</Card.Body>
</Accordion.Collapse>
</Card>
))}
{' '}
</Accordion>
) : (
<span className="error">No Playlists found</span>
)}
</Card.Body>
</Accordion.Collapse>
</Card>
))}
</Accordion>
<button
type="button"
className="button-submit"
onClick={() => {
let finalUrl;
if (activePlaylist) {
finalUrl = `${decodeURIComponent(match.params.redirectUrl)}&title=${
encodeURIComponent(formData.name)}&entity=${formData.entity}&id=${formData.id}`;
} else {
finalUrl = `${decodeURIComponent(match.params.redirectUrl)}&title=${
encodeURIComponent(formData.name)}&entity=${formData.entity}&id=${formData.id}&playlist=${defaultPlaylist}`;
}
if (formData.id) {
Swal.fire({
html: `You have selected <strong>${formData.entity}: ${formData.name}</strong><br>Do you want to continue ?`,
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Ok',
}).then((result) => {
if (result.value) {
window.location.href = finalUrl;
}
});
}
}}
>
Proceed
</button>
</div>
);
}
Example #12
Source File: CloneModel.js From ActiveLearningStudio-react-client with GNU Affero General Public License v3.0 | 4 votes |
function LtiProjectShared(props) {
const { clone } = props;
const [activeProject, setActiveProject] = useState(null);
const [activePlaylist, setActivePlaylist] = useState(null);
const [currentProject, setCurrentProject] = useState(null);
const [currentPlaylist, setCurrentPlaylist] = useState(null);
const dispatch = useDispatch();
const project = useSelector((state) => state.project);
useEffect(() => {
dispatch(
loadMyCloneProjectsAction(),
// loadMyProjectsAction(),
);
}, [dispatch]);
return (
<>
<div className="lti-all-project">
<div className="information-clone">
<p>
Select a
{' '}
{clone.clone.model === 'Activity' ? 'Playlist' : 'Project'}
{' '}
from your library that you would like to place this
{' '}
{clone.clone.model}
.
</p>
<div className="active-resource">
<h2>{clone.clone.title}</h2>
<h3>
Type:
<span>{clone.clone.model}</span>
</h3>
</div>
</div>
<Accordion className="top-box-project">
{!!project.clone && project.clone.map((data, counterTop) => (
<Card>
<Card.Header className="top-card">
<Accordion.Toggle
as={Button}
variant="link"
eventKey={counterTop + 1}
className="top-card-btn"
>
<span
onClick={() => {
if (activeProject === counterTop + 1) {
setActiveProject(null);
setCurrentProject(null);
} else {
setActiveProject(counterTop + 1);
setCurrentProject(data);
setCurrentPlaylist(null);
}
// setActivePlaylist(null);
}}
>
<div className="flex-bar">
<div className="text-align-left">
{activeProject === counterTop + 1 ? (
<FontAwesomeIcon icon="check-square" />
) : (
<FontAwesomeIcon icon="square" />
)}
{data.name}
</div>
{clone.clone.model === 'Activity' && (activeProject === counterTop + 1 ? (
<FontAwesomeIcon icon="chevron-up" />
) : (
<FontAwesomeIcon icon="chevron-down" />
))}
</div>
</span>
</Accordion.Toggle>
</Card.Header>
<Accordion.Collapse eventKey={counterTop + 1}>
<Card.Body>
{clone.clone.model === 'Activity' && (!!data.playlists && data.playlists.length > 0 ? (
<Accordion>
{data.playlists.map((data2, counterPlaylist) => (
<Card>
<Card.Header className="middle-card">
<Accordion.Toggle
as={Button}
variant="link"
eventKey={counterPlaylist + counterTop + 1}
>
<span
onClick={() => {
if (activePlaylist === counterPlaylist + counterTop + 1) {
setActivePlaylist(null);
setCurrentPlaylist(null);
} else {
setActivePlaylist(counterPlaylist + counterTop + 1);
setCurrentPlaylist(data2);
}
}}
>
<div className="flex-bar">
<div className="text-align-left">
<span>
{activePlaylist === counterPlaylist + counterTop + 1 ? (
<FontAwesomeIcon icon="stop-circle" className="mr-2" />
) : (
<FontAwesomeIcon icon="circle" className="mr-2" />
)}
{data2.title}
</span>
</div>
</div>
</span>
</Accordion.Toggle>
</Card.Header>
</Card>
))}
{' '}
</Accordion>
) : (
clone.clone.model === 'Activity' && (<span className="error">No Playlists found</span>)
))}
</Card.Body>
</Accordion.Collapse>
</Card>
))}
</Accordion>
</div>
<div className="footer-model">
<button
type="button"
className="button-submit"
onClick={() => {
if (!currentProject && !currentPlaylist) {
Swal.fire('Kindly select Project or playlist');
return;
}
let activeAssetDirection;
if (!currentPlaylist) {
activeAssetDirection = currentProject.name;
} else {
activeAssetDirection = currentPlaylist.title;
}
Swal.fire({
html: `You have selected <strong>${activeAssetDirection}</strong><br>Do you want to continue ?`,
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Ok',
}).then((result) => {
if (result.value) {
if (currentPlaylist) {
cloneActivity(currentPlaylist.id, clone.clone.id);
} else {
clonePlaylist(currentProject.id, clone.clone.id);
}
}
});
}}
>
Done
</button>
</div>
</>
);
}
Example #13
Source File: SearchNetlify.js From ActiveLearningStudio-react-client with GNU Affero General Public License v3.0 | 4 votes |
function SearchInterface(props) {
const { history } = props;
const allState = useSelector((state) => state.search);
const activityTypesState = useSelector((state) => state.resource.types);
const { currentOrganization, permission } = useSelector((state) => state.organization);
const dispatch = useDispatch();
const [activityTypes, setActivityTypes] = useState([]);
const [search, setSearch] = useState([]);
const [searchQueries, SetSearchQuery] = useState('');
const [searchInput, setSearchInput] = useState('');
const [meta, setMeta] = useState({});
const [activePage, setActivePage] = useState(1);
const [totalCount, setTotalCount] = useState(0);
const [activeModel, setActiveModel] = useState('');
const [activeType, setActiveType] = useState([]);
const [activeSubject, setActiveSubject] = useState([]);
const [activeEducation, setActiveEducation] = useState([]);
const [searchType, setSearchType] = useState(null);
const [authorName, SetAuthor] = useState('');
useMemo(() => {
setActiveEducation([]);
setActiveSubject([]);
setActiveType([]);
// eslint-disable-next-line no-restricted-globals
const query = QueryString.parse(location.search);
console.log(query);
if (query.type) {
if (query.type === 'private') {
setSearchType('private');
} else if (query.type === 'public') {
setSearchType('public');
} else {
setSearchType('orgSearch');
}
}
if (query.h5p) {
setActiveType(query.h5p.split(','));
}
if (query.grade) {
// if (query.grade.includes('and')) {
// query.grade = query.grade.replace('and', '&');
// }
setActiveSubject(query?.grade?.replace('and', '&')?.split(','));
}
if (query.education) {
// if (query.education.includes('and')) {
// query.education = query.education.replace('and', '&');
// }
setActiveEducation(query?.education?.replace('and', '&')?.split(','));
}
if (query.author) {
SetAuthor(query.author);
}
if (query?.q) {
setSearchInput(query?.q);
}
// eslint-disable-next-line no-restricted-globals
}, [location.search]);
window.onbeforeunload = () => {
localStorage.setItem('refreshPage', 'true');
};
useEffect(() => {
if (localStorage.getItem('refreshPage') === 'true' && currentOrganization && searchType) {
let dataSend;
if (searchType === 'orgSearch') {
dataSend = {
subjectArray: activeSubject,
gradeArray: activeEducation,
standardArray: activeType,
author: authorName || undefined,
type: searchType,
from: 0,
size: 20,
};
} else {
dataSend = {
phrase: searchInput.trim(),
subjectArray: activeSubject,
gradeArray: activeEducation,
standardArray: activeType,
author: authorName || undefined,
type: searchType,
from: 0,
size: 20,
};
}
let result;
(async () => {
result = await dispatch(simpleSearchAction(dataSend));
})();
setTotalCount(result?.meta?.total);
const tempEducation = [];
const tempSubject = [];
if (activeEducation) {
activeEducation.forEach((edu) => {
if (String(edu).includes('&')) {
const temp = String(edu).replace('&', 'and');
tempEducation.push(temp);
} else {
tempEducation.push(edu);
}
});
setActiveEducation(tempEducation);
}
if (activeSubject) {
activeSubject.forEach((sub) => {
if (String(sub).includes('&')) {
const temp = String(sub).replace('&', 'and');
tempSubject.push(temp);
} else {
tempSubject.push(sub);
}
});
setActiveSubject(tempSubject);
}
// eslint-disable-next-line max-len
history.push(`/org/${currentOrganization?.domain}/search?q=${searchInput.trim()}&type=${searchType}&grade=${tempSubject}&education=${tempEducation}&h5p=${activeType}&author=${authorName}`);
}
}, [currentOrganization]);
useEffect(() => {
if (allState.searchResult) {
if (allState.searchResult.length > 0) {
setSearch(allState.searchResult);
SetSearchQuery(allState.searchQuery);
setSearchInput(allState.searchQuery);
setMeta(allState.searchMeta);
localStorage.setItem('loading', 'false');
Swal.close();
} else if (allState.searchMeta.total === 0) {
setSearch([]);
SetSearchQuery(allState.searchQuery);
setSearchInput(allState.searchQuery);
setMeta({});
localStorage.setItem('loading', 'false');
Swal.close();
}
}
}, [allState.searchMeta, allState.searchQuery, allState.searchResult]);
useEffect(() => {
if (allState.searchResult) {
if (allState.searchResult.length > 0 && paginationStarter) {
paginationStarter = false;
setTotalCount(allState.searchMeta.total);
}
}
}, [allState.searchMeta, allState.searchResult, totalCount]);
useEffect(() => {
if (localStorage.getItem('loading') === 'true') {
Swal.fire({
html: 'Searching...', // add html attribute if you want or remove
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
}
});
useEffect(() => {
// setTimeout(() => {
// Swal.close();
// localStorage.setItem('loading', 'false');
// }, 5000);
});
useEffect(() => {
if (activityTypesState.length === 0) {
dispatch(loadResourceTypesAction());
}
}, []);
const compare = (a, b) => {
// Use toUpperCase() to ignore character casing
const bandA = a.title.toUpperCase();
const bandB = b.title.toUpperCase();
let comparison = 0;
if (bandA > bandB) {
comparison = 1;
} else if (bandA < bandB) {
comparison = -1;
}
return comparison;
};
useEffect(() => {
const allItems = [];
activityTypesState.map((data) => data.activityItems.map((itm) => allItems.push(itm)));
setActivityTypes(allItems.sort(compare));
}, [activityTypesState]);
// console.log(activeSubject, activeEducation);
return (
<>
<div>
<div className="content-wrapper">
<div className="content">
{true
? (
<div className="search-result-main">
<div className="total-count">
{totalCount > 10000
? (
<div>
Your search returned more than
{' '}
<span>10,000</span>
{' '}
results. Please refine your search criteria.
</div>
)
: null}
{!!searchQueries && (
<div>
Showing
{' '}
{search ? meta.total : '0'}
{' '}
results For
{' '}
<span>{searchQueries}</span>
</div>
)}
</div>
<div className="main-content-search">
<div className="left-search">
<div className="search-library">
<Accordion defaultActiveKey="0">
<Card>
<Accordion.Toggle as={Card.Header} eventKey="0">
Search Library
<FontAwesomeIcon className="ml-2" icon="plus" />
</Accordion.Toggle>
<Accordion.Collapse eventKey="0">
<Card.Body>
<div className="body-search">
<input
style={{ display: searchType === 'orgSearch' ? 'none' : 'block' }}
value={searchInput}
onChange={(e) => {
setSearchInput(e.target.value);
}}
onKeyPress={async (e) => {
if (e.key === 'Enter') {
if (!searchInput.trim() && searchType !== 'orgSearch') {
Swal.fire('Search field is required.');
} else if (searchInput.length > 255) {
Swal.fire('Character limit should be less than 255.');
} else {
Swal.fire({
title: 'Searching...', // add html attribute if you want or remove
html: 'We are fetching results for you!',
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
let dataSend;
if (searchType === 'orgSearch') {
dataSend = {
subjectArray: activeSubject,
gradeArray: activeEducation,
authors: authorName || undefined,
standardArray: activeType,
type: searchType,
from: 0,
size: 20,
};
} else {
dataSend = {
phrase: searchInput.trim(),
subjectArray: activeSubject,
gradeArray: activeEducation,
authors: authorName || undefined,
standardArray: activeType,
type: searchType,
from: 0,
size: 20,
};
}
const result = await dispatch(simpleSearchAction(dataSend));
setTotalCount(result.meta?.total);
const tempEducation = [];
const tempSubject = [];
if (activeEducation) {
activeEducation.forEach((edu) => {
if (String(edu).includes('&')) {
const temp = String(edu).replace('&', 'and');
tempEducation.push(temp);
} else {
tempEducation.push(edu);
}
});
setActiveEducation(tempEducation);
}
if (activeSubject) {
activeSubject.forEach((sub) => {
if (String(sub).includes('&')) {
const temp = String(sub).replace('&', 'and');
tempSubject.push(temp);
} else {
tempSubject.push(sub);
}
});
setActiveSubject(tempSubject);
}
// eslint-disable-next-line max-len
history.push(`/org/${currentOrganization?.domain}/search?q=${searchInput.trim()}&type=${searchType}&grade=${tempSubject}&education=${tempEducation}&h5p=${activeType}&author=${authorName}`);
}
}
}}
type="search"
placeholder="Search"
/>
<div className="form-group" style={{ display: permission?.Organization?.includes('organization:view-user') && searchType !== 'private' ? 'block' : 'none' }}>
<input
placeholder="Enter author name"
className="authorName"
value={authorName}
onChange={({ target }) => {
if (target.value) {
SetAuthor(target.value);
} else {
SetAuthor('');
}
}}
/>
</div>
<div
className="src-btn"
onClick={async () => {
if (!searchInput.trim() && searchType !== 'orgSearch') {
Swal.fire('Search field is required.');
} else if (searchInput.length > 255) {
Swal.fire('Character limit should be less than 255.');
} else {
Swal.fire({
title: 'Searching...', // add html attribute if you want or remove
html: 'We are fetching results for you!',
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
let dataSend;
if (searchType === 'orgSearch') {
dataSend = {
subjectArray: activeSubject,
gradeArray: activeEducation,
standardArray: activeType,
author: authorName || undefined,
type: searchType,
from: 0,
size: 20,
};
} else {
dataSend = {
phrase: searchInput.trim(),
subjectArray: activeSubject,
author: authorName || undefined,
gradeArray: activeEducation,
standardArray: activeType,
type: searchType,
from: 0,
size: 20,
};
}
const result = await dispatch(simpleSearchAction(dataSend));
setTotalCount(result.meta?.total);
const tempEducation = [];
const tempSubject = [];
if (activeEducation) {
activeEducation.forEach((edu) => {
if (String(edu).includes('&')) {
const temp = String(edu).replace('&', 'and');
tempEducation.push(temp);
} else {
tempEducation.push(edu);
}
});
setActiveEducation(tempEducation);
}
if (activeSubject) {
activeSubject.forEach((sub) => {
if (String(sub).includes('&')) {
const temp = String(sub).replace('&', 'and');
tempSubject.push(temp);
} else {
tempSubject.push(sub);
}
});
setActiveSubject(tempSubject);
}
// eslint-disable-next-line max-len
history.push(`/org/${currentOrganization?.domain}/search?q=${searchInput.trim()}&type=${searchType}&grade=${tempSubject}&education=${tempEducation}&h5p=${activeType}&author=${authorName}`);
}
// setModalShow(true);
}}
>
Search
</div>
</div>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
</div>
<div className="refine-search">
<div className="headline">Refine your search</div>
<Accordion defaultActiveKey="0">
<Card>
<Accordion.Toggle as={Card.Header} eventKey="0">
Subject
<FontAwesomeIcon className="ml-2" icon="plus" />
</Accordion.Toggle>
<Accordion.Collapse eventKey="0">
<Card.Body>
{subjects.map((data) => (
<div
className="list-item-keys"
key={data.value}
value={data.subject}
onClick={() => {
if (activeSubject.includes(data.subject)) {
if (data.subject === 'Career & Technical Education') {
setActiveSubject(activeSubject.filter((index) => {
if (index === 'Career & Technical Education' || index === 'Career and Technical Education') {
return false;
}
return true;
}));
} else {
setActiveSubject(activeSubject.filter((index) => index !== data.subject));
}
} else {
setActiveSubject([...activeSubject, data.subject]);
}
}}
>
{data.subject === 'Career & Technical Education'
? (activeSubject.includes('Career & Technical Education') || activeSubject.includes('Career and Technical Education'))
? <FontAwesomeIcon icon="check-square" /> : <FontAwesomeIcon icon="square" />
: activeSubject.includes(data.subject) ? (
<FontAwesomeIcon icon="check-square" />
) : (
<FontAwesomeIcon icon="square" />
)}
<span>{data.subject}</span>
</div>
))}
</Card.Body>
</Accordion.Collapse>
</Card>
<Card>
<Accordion.Toggle as={Card.Header} eventKey="1">
Education Level
<FontAwesomeIcon className="ml-2" icon="plus" />
</Accordion.Toggle>
<Accordion.Collapse eventKey="1">
<Card.Body>
{educationLevels.map((data) => (
<div
className="list-item-keys"
key={data.value}
value={data.name}
onClick={() => {
if (activeEducation.includes(data.name)) {
if (data.name === 'College & Beyond') {
setActiveSubject(activeEducation.filter((index) => {
if (index === 'College & Beyondn' || index === 'College and Beyond') {
return false;
}
return true;
}));
} else {
setActiveEducation(activeEducation.filter((index) => index !== data.name));
}
} else {
setActiveEducation([...activeEducation, data.name]);
}
}}
>
{data.name === 'College & Beyond'
? (activeEducation.includes('College & Beyond') || activeEducation.includes('College and Beyond'))
? <FontAwesomeIcon icon="check-square" /> : <FontAwesomeIcon icon="square" />
: activeEducation.includes(data.name) ? (
<FontAwesomeIcon icon="check-square" />
) : (
<FontAwesomeIcon icon="square" />
)}
<span>{data.name}</span>
</div>
))}
</Card.Body>
</Accordion.Collapse>
</Card>
<Card>
<Accordion.Toggle as={Card.Header} eventKey="3">
Type of Activity
<FontAwesomeIcon className="ml-2" icon="plus" />
</Accordion.Toggle>
<Accordion.Collapse eventKey="3">
<Card.Body
style={{
'max-height': '300px',
'overflow-y': 'auto',
}}
>
{activityTypes.map((data) => (
<div
className="list-item-keys"
key={data.id}
value={data.h5pLib}
onClick={() => {
if (activeType.includes(data.h5pLib)) {
// eslint-disable-next-line eqeqeq
setActiveType(activeType.filter((index) => index != data.h5pLib));
} else {
setActiveType([...activeType, data.h5pLib]);
}
}}
>
{activeType.includes(data.h5pLib) ? (
<FontAwesomeIcon icon="check-square" />
) : (
<FontAwesomeIcon icon="square" />
)}
<span>{data.title}</span>
</div>
))}
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
</div>
</div>
<div className="right-search">
<Tabs
defaultActiveKey="total"
id="uncontrolled-tab-example"
onSelect={async (e) => {
if (e === 'total') {
let searchData;
if (searchType === 'orgSearch') {
searchData = {
from: 0,
size: 20,
type: searchType,
author: authorName || undefined,
subjectArray: activeSubject,
gradeArray: activeEducation,
standardArray: activeType,
};
} else {
searchData = {
phrase: searchQueries.trim(),
from: 0,
size: 20,
author: authorName || undefined,
type: searchType,
subjectArray: activeSubject,
gradeArray: activeEducation,
standardArray: activeType,
};
}
Swal.fire({
title: 'Loading...', // add html attribute if you want or remove
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
const resultModel = await dispatch(simpleSearchAction(searchData));
Swal.close();
setTotalCount(resultModel.meta[e]);
setActiveModel(e);
setActivePage(1);
} else {
let searchData;
if (searchType === 'orgSearch') {
searchData = {
from: 0,
size: 20,
author: authorName || undefined,
model: e,
type: searchType,
subjectArray: activeSubject,
gradeArray: activeEducation,
standardArray: activeType,
};
} else {
searchData = {
phrase: searchQueries.trim(),
from: 0,
size: 20,
model: e,
author: authorName || undefined,
type: searchType,
subjectArray: activeSubject,
gradeArray: activeEducation,
standardArray: activeType,
};
}
Swal.fire({
title: 'Loading...', // add html attribute if you want or remove
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
const resultModel = await dispatch(simpleSearchAction(searchData));
Swal.close();
setTotalCount(resultModel.meta[e]);
setActiveModel(e);
setActivePage(1);
}
}}
>
<Tab
eventKey="total"
title={
!!search && !!meta.total
? `all (${meta.total})`
: 'all (0)'
}
>
<div className="results_search">
{!!search && search.length > 0 ? (
search.map((res) => (
<div className="box">
<div className="imgbox">
{res.thumb_url ? (
<div
style={{
backgroundImage: res.thumb_url.includes('pexels.com')
? `url(${res.thumb_url})`
: `url(${global.config.resourceUrl}${res.thumb_url})`,
}}
/>
) : (
<div
style={{
// eslint-disable-next-line max-len
backgroundImage: 'https://images.pexels.com/photos/593158/pexels-photo-593158.jpeg?auto=compress&cs=tinysrgb&dpr=1&fit=crop&h=200&w=280',
}}
/>
)}
{/* <h5>CALCULUS</h5> */}
</div>
<div className="content">
<div className="search-content">
<a
href={
res.model === 'Activity'
// eslint-disable-next-line max-len
? (permission?.activeRole === 'admin' && searchType !== 'public') || (searchType === 'private') ? `/org/${currentOrganization?.domain}/project/${res.project_id}/playlist/${res.playlist_id}/activity/${res.id}/preview` : `/activity/${res.id}/shared`
: res.model === 'Playlist'
? `/playlist/${res.id}/preview/lti`
: `/project/${res.id}/shared`
}
target="_blank"
rel="noreferrer"
>
<h2>{res.title || res.name}</h2>
</a>
<ul>
{res.user && (
<li>
by
{' '}
<span>
{res.user.first_name}
</span>
</li>
)}
<li>
Type
{' '}
<span className="type">{res.model}</span>
</li>
{/* <li>
Member Rating{" "}
<span className="type">Project</span>
</li> */}
</ul>
<p>{res.description}</p>
</div>
</div>
</div>
))
) : (
<div className="box">No result found !</div>
)}
</div>
</Tab>
<Tab
eventKey="projects"
title={
!!search && !!meta.projects
? `project (${meta.projects})`
: 'project (0)'
}
>
<div className="results_search">
{!!search && search.length > 0 ? (
search.map((res) => (
<>
{res.model === 'Project' && (
<div className="box">
<div className="imgbox">
{res.thumb_url ? (
<div
style={{
backgroundImage: res.thumb_url.includes('pexels.com')
? `url(${res.thumb_url})`
: `url(${global.config.resourceUrl}${res.thumb_url})`,
}}
/>
) : (
<div
style={{
// eslint-disable-next-line max-len
backgroundImage: 'https://images.pexels.com/photos/593158/pexels-photo-593158.jpeg?auto=compress&cs=tinysrgb&dpr=1&fit=crop&h=200&w=280',
}}
/>
)}
{/* <h5>CALCULUS</h5> */}
</div>
<div className="content">
<div className="search-content">
<a
href={
res.model === 'Activity'
? `/activity/${res.id}/shared`
: res.model === 'Playlist'
? `/playlist/${res.id}/preview/lti`
: `/project/${res.id}/shared`
}
target="_blank"
rel="noreferrer"
>
<h2>{res.title || res.name}</h2>
</a>
<ul>
{res.user && (
<li>
by
{' '}
<span>
{res.user.first_name}
</span>
</li>
)}
<li>
Type
{' '}
<span className="type">{res.model}</span>
</li>
{/* <li>
Member Rating{" "}
<span className="type">Project</span>
</li> */}
</ul>
<p>{res.description}</p>
</div>
</div>
</div>
)}
</>
))
) : (
<div className="box">No result found !</div>
)}
</div>
</Tab>
<Tab
eventKey="playlists"
title={
!!search && !!meta.playlists
? `playlist (${meta.playlists})`
: 'playlist (0)'
}
>
<div className="results_search">
{!!search && search.length > 0 ? (
search.map((res) => (
<>
{res.model === 'Playlist' && (
<div className="box">
<div className="imgbox">
{res.thumb_url ? (
<div
style={{
backgroundImage: res.thumb_url.includes('pexels.com')
? `url(${res.thumb_url})`
: `url(${global.config.resourceUrl}${res.thumb_url})`,
}}
/>
) : (
<div
style={{
// eslint-disable-next-line max-len
backgroundImage: 'https://images.pexels.com/photos/593158/pexels-photo-593158.jpeg?auto=compress&cs=tinysrgb&dpr=1&fit=crop&h=200&w=280',
}}
/>
)}
{/* <h5>CALCULUS</h5> */}
</div>
<div className="content">
<div className="search-content">
<a
href={
res.model === 'Activity'
// eslint-disable-next-line max-len
? (permission?.activeRole === 'admin' && searchType !== 'public') || (searchType === 'private') ? `/org/${currentOrganization?.domain}/project/${res.project_id}/playlist/${res.playlist_id}/activity/${res.id}/preview` : `/activity/${res.id}/shared`
: res.model === 'Playlist'
? `/playlist/${res.id}/preview/lti`
: `/project/${res.id}/shared`
}
target="_blank"
rel="noreferrer"
>
<h2>{res.title || res.name}</h2>
</a>
<ul>
{res.user && (
<li>
by
{' '}
<span>
{res.user.first_name}
</span>
</li>
)}
<li>
Type
{' '}
<span className="type">{res.model}</span>
</li>
{/* <li>
Member Rating{" "}
<span className="type">Project</span>
</li> */}
</ul>
<p>{res.description}</p>
</div>
</div>
</div>
)}
</>
))
) : (
<div className="box">No result found !</div>
)}
</div>
</Tab>
<Tab
eventKey="activities"
title={
!!search && !!meta.activities
? `activity (${meta.activities})`
: 'activity (0)'
}
>
<div className="content">
<div className="results_search">
{!!search && search.length > 0 ? (
search.map((res) => (
<>
{res.model === 'Activity' && (
<div className="box">
<div className="imgbox">
{res.thumb_url ? (
<div
style={{
backgroundImage: res.thumb_url.includes('pexels.com')
? `url(${res.thumb_url})`
: `url(${global.config.resourceUrl}${res.thumb_url})`,
}}
/>
) : (
<div
style={{
// eslint-disable-next-line max-len
backgroundImage: 'https://images.pexels.com/photos/593158/pexels-photo-593158.jpeg?auto=compress&cs=tinysrgb&dpr=1&fit=crop&h=200&w=280',
}}
/>
)}
{/* <h5>CALCULUS</h5> */}
</div>
<div className="content">
<div className="search-content">
<a
href={
res.model === 'Activity'
? `/activity/${res.id}/shared`
: res.model === 'Playlist'
? `/playlist/${res.id}/preview/lti`
: `/project/${res.id}/shared`
}
target="_blank"
rel="noreferrer"
>
<h2>{res.title || res.name}</h2>
</a>
<ul>
{res.user && (
<li>
by
{' '}
<span>
{res.user.first_name}
</span>
</li>
)}
<li>
Type
{' '}
<span className="type">{res.model}</span>
</li>
{/* <li>
Member Rating{" "}
<span className="type">Project</span>
</li> */}
</ul>
<p>{res.description}</p>
</div>
</div>
</div>
)}
</>
))
) : (
<div className="box">No result found !</div>
)}
</div>
</div>
</Tab>
</Tabs>
{totalCount > 20 && (
<Pagination
activePage={activePage}
itemsCountPerPage={20}
totalItemsCount={totalCount > 10000 ? 10000 : totalCount}
pageRangeDisplayed={8}
onChange={async (e) => {
setActivePage(e);
if (activeModel === 'total') {
const searchData = {
phrase: searchQueries.trim(),
from: e * 20 - 20,
size: 20,
type: searchType,
};
Swal.fire({
title: 'Loading...',
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
await dispatch(simpleSearchAction(searchData));
Swal.close();
} else {
const searchData = {
phrase: searchQueries.trim(),
from: e * 20 - 20,
size: 20,
type: searchType,
model: activeModel,
};
Swal.fire({
title: 'Loading...',
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
await dispatch(simpleSearchAction(searchData));
Swal.close();
}
}}
itemClass="page-item"
linkClass="page-link"
/>
)}
</div>
</div>
</div>
)
: (
<Alert variant="danger">You are not authorized to view this page!</Alert>
)}
</div>
</div>
</div>
</>
);
}
Example #14
Source File: index.js From ActiveLearningStudio-react-client with GNU Affero General Public License v3.0 | 4 votes |
function SearchInterface(props) {
const { history, fromTeam, selectProject, setSelectProject } = props;
const [toggleStates, setToggleStates] = useState({
searchLibrary: true,
subject: true,
education: false,
authorTag: false,
type: false,
});
const allState = useSelector((state) => state.search);
const activityTypesState = useSelector((state) => state.resource.types);
const { currentOrganization, permission } = useSelector((state) => state.organization);
const dispatcher = useDispatch();
const safariMontagePublishTool = useSelector((state) => state.genericLMS.safariMontagePublishTool);
const allLms = useSelector((state) => state.share);
const dispatch = useDispatch();
const [show, setShow] = useState(false);
const [selectedProjectId, setSelectedProjectId] = useState(0);
const [selectedProjectPlaylistId, setSelectedProjectPlaylistId] = useState(0);
const [activityTypes, setActivityTypes] = useState([]);
const [modalShow, setModalShow] = useState(false);
const [search, setSearch] = useState([]);
const [searchQueries, SetSearchQuery] = useState('');
const [searchInput, setSearchInput] = useState('');
const [meta, setMeta] = useState({});
const [clone, setClone] = useState();
const [activePage, setActivePage] = useState(1);
const [totalCount, setTotalCount] = useState(0);
const [activeModel, setActiveModel] = useState('');
const [activeType, setActiveType] = useState([]);
const [activeSubject, setActiveSubject] = useState([]);
const [activeEducation, setActiveEducation] = useState([]);
const [activeAuthorTag, setActiveAuthorTag] = useState([]);
const [searchType, setSearchType] = useState(null);
const [authorName, SetAuthor] = useState('');
const [activetab, setActiveTab] = useState(fromTeam ? 'projects' : 'total');
const [todate, Settodate] = useState(undefined);
const [fromdate, Setfromdate] = useState(undefined);
const [subjects, setSubjects] = useState([]);
const [authorTags, setAuthorTags] = useState([]);
const [educationLevels, setEducationLevels] = useState([])
// const [selectedAuthor, setSelectedAuthor] = useState([]);
// const [authors, setAuthors] = useState([]);
// var activeSubject1;
// useMemo(() => {
// activeSubject1 = activeSubject.map((data1) => data1.replace('and', '&'))
// },[activeSubject])
const handleShow = () => {
setShow(true); //! state.show
};
const setProjectId = (projectId) => {
setSelectedProjectId(projectId);
};
const setProjectPlaylistId = (playlistId) => {
setSelectedProjectPlaylistId(playlistId);
};
const projectVisibilityLMS = allLms?.shareVendors?.map((data) => {
if (data.project_visibility === true) {
return true;
}
return false;
});
// const playlistVisibilityLMS = allLms?.shareVendors?.filter((data) => data.playlist_visibility === true);
const activityVisibilityLMS = allLms?.shareVendors?.map((data) => {
if (data.activity_visibility === true) {
return true;
}
return false;
});
const safariMontageActivity = allLms?.shareVendors?.map((data) => {
if (data.lms_name === 'safarimontage') {
return true;
}
return false;
});
useMemo(() => {
dispatch(loadLmsAction());
}, []);
useMemo(() => {
setActiveEducation([]);
setActiveSubject([]);
setActiveAuthorTag([]);
setActiveType([]);
// eslint-disable-next-line no-restricted-globals
const query = QueryString.parse(location.search);
if (query.type) {
if (query.type === 'private') {
setSearchType('private');
} else if (query.type === 'public') {
setSearchType('public');
} else {
setSearchType('orgSearch');
}
}
if (query.h5p) {
setActiveType(query.h5p.split(','));
}
if (query.grade) {
// if (query.grade.includes('and')) {
// query.grade = query.grade.replace('and', '&');
// }
setActiveSubject(query?.grade?.split(',').map(Number));
}
if (query.education) {
// if (query.education.includes('and')) {
// query.education = query.education.replace('and', '&');
// }
setActiveEducation(query?.education?.split(',').map(Number));
}
if (query.authorTag) {
setActiveAuthorTag(query?.authorTag?.split(',').map(Number));
}
if (query.author) {
SetAuthor(query.author);
}
if (query.fromDate && query.fromDate !== 'undefined') {
Setfromdate(query.fromDate);
} else {
Setfromdate(undefined);
}
if (query.toDate && query.fromDate !== 'undefined') {
Settodate(query.toDate);
} else {
Settodate(undefined);
}
if (query?.q) {
setSearchInput(query?.q);
}
// eslint-disable-next-line no-restricted-globals
}, [location.search]);
window.onbeforeunload = () => {
localStorage.setItem('refreshPage', 'true');
};
useEffect(() => {
if (localStorage.getItem('refreshPage') === 'true' && currentOrganization && searchType) {
let dataSend;
if (searchType === 'orgSearch') {
dataSend = {
phrase: searchInput.trim(),
subjectArray: activeSubject,
gradeArray: activeEducation,
authorTagsArray: activeAuthorTag,
standardArray: activeType,
author: authorName || undefined,
type: searchType,
from: 0,
size: 20,
};
} else {
dataSend = {
phrase: searchInput.trim(),
subjectArray: activeSubject,
gradeArray: activeEducation,
authorTagsArray: activeAuthorTag,
standardArray: activeType,
author: authorName || undefined,
type: searchType,
from: 0,
size: 20,
};
}
let result;
(async () => {
result = await dispatch(simpleSearchAction(dataSend));
})();
setTotalCount(result?.meta?.total);
const tempEducation = [];
const tempSubject = [];
const tempTag = [];
if (activeEducation) {
activeEducation.forEach((edu) => {
if (String(edu).includes('&')) {
const temp = String(edu).replace('&', 'and');
tempEducation.push(temp);
} else {
tempEducation.push(edu);
}
});
setActiveEducation(tempEducation);
}
if (activeSubject) {
activeSubject.forEach((sub) => {
if (String(sub).includes('&')) {
const temp = String(sub).replace('&', 'and');
tempSubject.push(temp);
} else {
tempSubject.push(sub);
}
});
setActiveSubject(tempSubject);
}
if (activeAuthorTag) {
activeAuthorTag.forEach((sub) => {
if (String(sub).includes('&')) {
const temp = String(sub).replace('&', 'and');
tempTag.push(temp);
} else {
tempTag.push(sub);
}
});
setActiveAuthorTag(tempTag);
}
// eslint-disable-next-line max-len
if (!fromTeam) {
// eslint-disable-next-line max-len
history.push(
`/org/${
currentOrganization?.domain
}/search?q=${searchInput.trim()}&type=${searchType}&grade=${tempSubject}&education=${tempEducation}&authorTag=${tempTag}&h5p=${activeType}&author=${authorName}`
);
}
}
}, [currentOrganization]);
useEffect(() => {
if (allState.searchResult) {
if (allState.searchResult.length > 0) {
setSearch(allState.searchResult);
SetSearchQuery(allState.searchQuery);
setSearchInput(allState.searchQuery);
setMeta(allState.searchMeta);
localStorage.setItem('loading', 'false');
Swal.close();
} else if (allState.searchMeta.total === 0) {
setSearch([]);
SetSearchQuery(allState.searchQuery);
setSearchInput(allState.searchQuery);
setMeta({});
localStorage.setItem('loading', 'false');
Swal.close();
}
}
}, [allState.searchMeta, allState.searchQuery, allState.searchResult]);
useEffect(() => {
if (allState.searchResult) {
if (allState.searchResult.length > 0 && paginationStarter) {
paginationStarter = false;
setTotalCount(allState.searchMeta.total);
}
}
}, [allState.searchMeta, allState.searchResult, totalCount]);
useEffect(() => {
if (localStorage.getItem('loading') === 'true') {
Swal.fire({
html: 'Searching...', // add html attribute if you want or remove
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
}
});
useEffect(() => {
// setTimeout(() => {
// Swal.close();
// localStorage.setItem('loading', 'false');
// }, 5000);
});
useEffect(() => {
if (activityTypesState?.length === 0) {
dispatch(loadResourceTypesAction());
}
}, []);
const compare = (a, b) => {
// Use toUpperCase() to ignore character casing
const bandA = a.title.toUpperCase();
const bandB = b.title.toUpperCase();
let comparison = 0;
if (bandA > bandB) {
comparison = 1;
} else if (bandA < bandB) {
comparison = -1;
}
return comparison;
};
useEffect(() => {
const allItems = [];
activityTypesState?.data?.map((data) => data.activityItems.map((itm) => allItems.push(itm)));
setActivityTypes(allItems.sort(compare));
}, [activityTypesState]);
useEffect (() => {
if(currentOrganization?.id) {
if(subjects.length == 0) {
const result_sub = dispatcher(getSubjects(currentOrganization?.id || 1));
result_sub.then((data)=>setSubjects(data));
}
if(authorTags.length == 0) {
const result_auth = dispatcher(getAuthorTag(currentOrganization?.id || 1));
result_auth.then((data)=>setAuthorTags(data));
}
if(educationLevels.length == 0) {
const result_edu = dispatcher(getEducationLevel(currentOrganization?.id || 1));
result_edu.then((data)=>setEducationLevels(data));
}
}
}, currentOrganization);
return (
<>
<div>
<div className={!fromTeam && 'search-wrapper'}>
<MyVerticallyCenteredModal show={modalShow} onHide={() => setModalShow(false)} className="clone-lti" clone={clone} />
<div className="content-search">
{true ? (
<div className="search-result-main">
{!fromTeam && <div className="current-org-search">{currentOrganization?.name}</div>}
{!fromTeam && <div className="exp-lib-cnt">Explore library content</div>}
<div
className="total-count"
style={{
display: totalCount > 1000 || !!searchQueries ? 'block' : 'none',
}}
>
{totalCount > 10000 ? (
<div>
Your search returned more than <span>10,000</span> results. Please refine your search criteria.
</div>
) : null}
{!!searchQueries && (
<div>
Showing {search ? meta.total : '0'} results For <span>{searchQueries}</span>
</div>
)}
</div>
<div className="main-content-search">
<div className="left-search">
<div className="search-library">
<Accordion defaultActiveKey="0">
<Card>
<Accordion.Toggle
as={Card.Header}
eventKey="0"
onClick={() =>
setToggleStates({
...toggleStates,
searchLibrary: !toggleStates.searchLibrary,
})
}
>
Search Library
<FontAwesomeIcon className="ml-2" icon={toggleStates.searchLibrary ? 'chevron-up' : 'chevron-down'} />
</Accordion.Toggle>
<Accordion.Collapse eventKey="0">
<Card.Body>
<div className="body-search">
<input
// style={{ display: searchType === 'orgSearch' ? 'none' : 'block' }}
value={searchInput}
onChange={(e) => {
setSearchInput(e.target.value);
}}
onKeyPress={async (e) => {
if (e.key === 'Enter') {
if (!searchInput.trim() && searchType !== 'orgSearch') {
Swal.fire('Search field is required.');
} else if (searchInput.length > 255) {
Swal.fire('Character limit should be less than 255.');
} else {
Swal.fire({
title: 'Searching...', // add html attribute if you want or remove
html: 'We are fetching results for you!',
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
let dataSend;
if (searchType === 'orgSearch') {
dataSend = {
phrase: searchInput.trim(),
subjectArray: activeSubject,
gradeArray: activeEducation,
authorTagsArray: activeAuthorTag,
authors: authorName || undefined,
standardArray: activeType,
type: searchType,
from: 0,
size: 20,
};
} else {
dataSend = {
phrase: searchInput.trim(),
subjectArray: activeSubject,
gradeArray: activeEducation,
authorTagsArray: activeAuthorTag,
authors: authorName || undefined,
standardArray: activeType,
type: searchType,
from: 0,
size: 20,
};
}
const result = await dispatch(simpleSearchAction(dataSend));
setTotalCount(result.meta?.total);
const tempEducation = [];
const tempSubject = [];
const tempTag = [];
if (activeEducation) {
activeEducation.forEach((edu) => {
if (String(edu).includes('&')) {
const temp = String(edu).replace('&', 'and');
tempEducation.push(temp);
} else {
tempEducation.push(edu);
}
});
setActiveEducation(tempEducation);
}
if (activeSubject) {
activeSubject.forEach((sub) => {
if (String(sub).includes('&')) {
const temp = String(sub).replace('&', 'and');
tempSubject.push(temp);
} else {
tempSubject.push(sub);
}
});
setActiveSubject(tempSubject);
}
if (activeAuthorTag) {
activeAuthorTag.forEach((sub) => {
if (String(sub).includes('&')) {
const temp = String(sub).replace('&', 'and');
tempTag.push(temp);
} else {
tempTag.push(sub);
}
});
setActiveAuthorTag(tempTag);
}
// eslint-disable-next-line max-len
if (!fromTeam) {
// eslint-disable-next-line max-len
history.push(
`/org/${
currentOrganization?.domain
}/search?q=${searchInput.trim()}&type=${searchType}&grade=${tempSubject}&education=${tempEducation}&authorTag=${tempTag}&h5p=${activeType}&author=${authorName}`
);
}
}
}
}}
type="search"
placeholder="Search"
/>
<div className="form-group">
<div className="radio-btns">
{true && (
<label>
<input
name="type"
onChange={(e) => {
setSearchType(e.target.value);
}}
value="private"
checked={searchType === 'private'}
type="radio"
/>
<span>My Projects</span>
</label>
)}
{true && (
<label>
<input
name="type"
onChange={(e) => {
setSearchType(e.target.value);
}}
value="public"
checked={searchType === 'public'}
type="radio"
/>
<span>All Shared Projects</span>
</label>
)}
{true && (
<label>
<input
name="type"
onChange={(e) => {
setSearchType(e.target.value);
}}
value="orgSearch"
checked={searchType === 'orgSearch'}
type="radio"
/>
<span>All Shared Projects In My Org</span>
</label>
)}
</div>
</div>
{permission?.Organization?.includes('organization:view-user') && searchType !== 'private' && <div className="author-label">Author</div>}
<div
className="form-group"
style={{
display: permission?.Organization?.includes('organization:view-user') && searchType !== 'private' ? 'block' : 'none',
}}
>
<input
placeholder="Enter author name"
className="authorName"
value={authorName}
onChange={({ target }) => {
if (target.value) {
SetAuthor(target.value);
} else {
SetAuthor('');
}
}}
/>
</div>
<div
className="src-btn"
onClick={async () => {
Setfromdate(undefined);
Settodate(undefined);
setActiveTab(fromTeam ? 'projects' : 'total');
if (!searchInput.trim() && searchType !== 'orgSearch') {
Swal.fire('Search field is required.');
} else if (searchInput.length > 255) {
Swal.fire('Character limit should be less than 255.');
} else if (!searchType) {
Swal.fire('Search type is required. Click one of the radio buttons.');
} else {
Swal.fire({
title: 'Searching...', // add html attribute if you want or remove
html: 'We are fetching results for you!',
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
let dataSend;
if (searchType === 'orgSearch') {
dataSend = {
phrase: searchInput.trim(),
subjectArray: activeSubject,
gradeArray: activeEducation,
authorTagsArray: activeAuthorTag,
standardArray: activeType,
author: authorName || undefined,
fromDate: fromdate || undefined,
toDate: todate || undefined,
type: searchType,
from: 0,
size: 20,
};
} else {
dataSend = {
phrase: searchInput.trim(),
subjectArray: activeSubject,
author: authorName || undefined,
fromDate: fromdate || undefined,
toDate: todate || undefined,
gradeArray: activeEducation,
authorTagsArray: activeAuthorTag,
standardArray: activeType,
type: searchType,
from: 0,
size: 20,
};
}
const result = await dispatch(simpleSearchAction(dataSend));
setTotalCount(result.meta?.total);
const tempEducation = [];
const tempSubject = [];
const tempTag = [];
if (activeEducation) {
activeEducation.forEach((edu) => {
if (String(edu).includes('&')) {
const temp = String(edu).replace('&', 'and');
tempEducation.push(temp);
} else {
tempEducation.push(edu);
}
});
setActiveEducation(tempEducation);
}
if (activeSubject) {
activeSubject.forEach((sub) => {
if (String(sub).includes('&')) {
const temp = String(sub).replace('&', 'and');
tempSubject.push(temp);
} else {
tempSubject.push(sub);
}
});
setActiveSubject(tempSubject);
}
if (activeAuthorTag) {
activeAuthorTag.forEach((sub) => {
if (String(sub).includes('&')) {
const temp = String(sub).replace('&', 'and');
tempTag.push(temp);
} else {
tempTag.push(sub);
}
});
setActiveAuthorTag(tempSubject);
}
if (!fromTeam) {
// eslint-disable-next-line max-len
history.push(
`/org/${
currentOrganization?.domain
}/search?q=${searchInput.trim()}&type=${searchType}&grade=${tempSubject}&education=${tempEducation}&authorTag=${tempTag}&h5p=${activeType}&author=${authorName}`
);
}
}
// setModalShow(true);
}}
>
<FontAwesomeIcon icon="search" />
Search
</div>
</div>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
</div>
<div className="refine-search">
<div className="headline">Refine your search</div>
<Accordion defaultActiveKey="0">
<Card>
<Accordion.Toggle
as={Card.Header}
eventKey="0"
onClick={() =>
setToggleStates({
...toggleStates,
type: false,
education: false,
authorTag: false,
subject: !toggleStates.subject,
})
}
>
Subject
<FontAwesomeIcon className="ml-2" icon={toggleStates.subject ? 'chevron-up' : 'chevron-down'} />
</Accordion.Toggle>
<Accordion.Collapse eventKey="0">
<Card.Body>
{subjects.length !== 0 && subjects?.data.map((data) => (
<div
className="list-item-keys"
key={data.id}
value={data.id}
onClick={() => {
if (activeSubject.includes(data.id)) {
if (data.subject === 'Career & Technical Education') {
setActiveSubject(
activeSubject.filter((index) => {
if (index === 'Career & Technical Education' || index === 'Career and Technical Education') {
return false;
}
return true;
})
);
} else {
setActiveSubject(activeSubject.filter((index) => index !== data.id));
}
} else {
setActiveSubject([...activeSubject, data.id]);
}
}}
>
{activeSubject.includes(data.id) ? (
<FontAwesomeIcon icon="check-square" />
) : (
<FontAwesomeIcon icon="square" />
)}
<span>{data.name}</span>
</div>
))}
</Card.Body>
</Accordion.Collapse>
</Card>
<Card>
<Accordion.Toggle
as={Card.Header}
eventKey="1"
onClick={() =>
setToggleStates({
...toggleStates,
type: false,
subject: false,
authorTag: false,
education: !toggleStates.education,
})
}
>
Education Level
<FontAwesomeIcon className="ml-2" icon={toggleStates.education ? 'chevron-up' : 'chevron-down'} />
</Accordion.Toggle>
<Accordion.Collapse eventKey="1">
<Card.Body>
{educationLevels.length !== 0 && educationLevels.data.map((data) => (
<div
className="list-item-keys"
key={data.id}
value={data.id}
onClick={() => {
if (activeEducation.includes(data.id)) {
if (data.id === 'College & Beyond') {
setActiveEducation(
activeEducation.filter((index) => {
if (index === 'College & Beyond' || index === 'College and Beyond') {
return false;
}
return true;
})
);
} else {
setActiveEducation(activeEducation.filter((index) => index !== data.id));
}
} else {
setActiveEducation([...activeEducation, data.id]);
}
}}
>
{activeEducation.includes(data.id) ? (
<FontAwesomeIcon icon="check-square" />
) : (
<FontAwesomeIcon icon="square" />
)}
<span>{data.name}</span>
</div>
))}
</Card.Body>
</Accordion.Collapse>
</Card>
<Card>
<Accordion.Toggle
as={Card.Header}
eventKey="2"
onClick={() =>
setToggleStates({
...toggleStates,
type: false,
subject: false,
education: false,
authorTag: !toggleStates.authorTag,
})
}
>
Author Tags
<FontAwesomeIcon className="ml-2" icon={toggleStates.authorTag ? 'chevron-up' : 'chevron-down'} />
</Accordion.Toggle>
<Accordion.Collapse eventKey="2">
<Card.Body>
{authorTags.length !== 0 && authorTags.data.map((data) => (
<div
className="list-item-keys"
key={data.id}
value={data.id}
onClick={() => {
if (activeAuthorTag.includes(data.id)) {
if (data.name === 'College & Beyond') {
setActiveAuthorTag(
activeAuthorTag.filter((index) => {
if (index === 'College & Beyond' || index === 'College and Beyond') {
return false;
}
return true;
})
);
} else {
setActiveAuthorTag(activeAuthorTag.filter((index) => index !== data.id));
}
} else {
setActiveAuthorTag([...activeAuthorTag, data.id]);
}
}}
>
{activeAuthorTag.includes(data.id) ? (
<FontAwesomeIcon icon="check-square" />
) : (
<FontAwesomeIcon icon="square" />
)}
<span>{data.name}</span>
</div>
))}
</Card.Body>
</Accordion.Collapse>
</Card>
<Card>
<Accordion.Toggle
as={Card.Header}
eventKey="3"
onClick={() =>
setToggleStates({
...toggleStates,
subject: false,
education: false,
authorTag: false,
type: !toggleStates.type,
})
}
>
Type of Activity
<FontAwesomeIcon className="ml-2" icon={toggleStates.type ? 'chevron-up' : 'chevron-down'} />
</Accordion.Toggle>
<Accordion.Collapse eventKey="3">
<Card.Body
style={{
'max-height': '300px',
'overflow-y': 'auto',
}}
>
{activityTypes.length !== 0 && activityTypes?.map((data) => (
<div
className="list-item-keys"
key={data.id}
value={data.h5pLib}
onClick={() => {
if (activeType.includes(data.h5pLib)) {
// eslint-disable-next-line eqeqeq
setActiveType(activeType.filter((index) => index != data.h5pLib));
} else {
setActiveType([...activeType, data.h5pLib]);
}
}}
>
{activeType.includes(data.h5pLib) ? <FontAwesomeIcon icon="check-square" /> : <FontAwesomeIcon icon="square" />}
<span>{data.title}</span>
</div>
))}
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
</div>
</div>
<div className="right-search" id="right-search-branding-style">
<Tabs
activeKey={activetab}
id="uncontrolled-tab-example"
onSelect={async (e) => {
if (!searchInput && searchType !== 'orgSearch') {
Swal.fire('Search field is required.');
} else {
setActiveTab(e);
if (e === 'total') {
let searchData;
if (searchType === 'orgSearch') {
searchData = {
phrase: searchQueries.trim() || searchInput,
from: 0,
size: 20,
type: searchType,
author: authorName || undefined,
fromDate: fromdate || undefined,
toDate: todate || undefined,
subjectArray: activeSubject,
gradeArray: activeEducation,
authorTagsArray: activeAuthorTag,
standardArray: activeType,
};
} else {
searchData = {
phrase: searchQueries.trim() || searchInput,
from: 0,
size: 20,
author: authorName || undefined,
fromDate: fromdate || undefined,
toDate: todate || undefined,
type: searchType,
subjectArray: activeSubject,
gradeArray: activeEducation,
authorTagsArray: activeAuthorTag,
standardArray: activeType,
};
}
Swal.fire({
title: 'Loading...', // add html attribute if you want or remove
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
const resultModel = await dispatch(simpleSearchAction(searchData));
Swal.close();
setTotalCount(resultModel.meta[e]);
setActiveModel(e);
setActivePage(1);
} else {
let searchData;
if (searchType === 'orgSearch') {
searchData = {
phrase: searchQueries.trim() || searchInput,
from: 0,
size: 20,
author: authorName || undefined,
fromDate: fromdate || undefined,
toDate: todate || undefined,
model: e,
type: searchType,
subjectArray: activeSubject,
gradeArray: activeEducation,
authorTagsArray: activeAuthorTag,
standardArray: activeType,
};
} else {
searchData = {
phrase: searchQueries.trim() || searchInput,
from: 0,
size: 20,
model: e,
author: authorName || undefined,
fromDate: fromdate || undefined,
toDate: todate || undefined,
type: searchType,
subjectArray: activeSubject,
gradeArray: activeEducation,
authorTagsArray: activeAuthorTag,
standardArray: activeType,
};
}
Swal.fire({
title: 'Loading...', // add html attribute if you want or remove
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
const resultModel = await dispatch(simpleSearchAction(searchData));
Swal.close();
setTotalCount(resultModel.meta[e]);
setActiveModel(e);
setActivePage(1);
}
}
}}
>
{!fromTeam && (
<Tab eventKey="total" title={!!search && !!meta.total ? `all (${meta.total})` : 'all (0)'}>
<div className="results_search">
{!!search && search.length > 0 ? (
search.map((res) => (
<div className="box">
<div className="imgbox">
{res.thumb_url ? (
<div
style={{
backgroundImage: res.thumb_url.includes('pexels.com') ? `url(${res.thumb_url})` : `url(${global.config.resourceUrl}${res.thumb_url})`,
}}
/>
) : (
<div
style={{
// eslint-disable-next-line max-len
backgroundImage:
'https://images.pexels.com/photos/593158/pexels-photo-593158.jpeg?auto=compress&cs=tinysrgb&dpr=1&fit=crop&h=200&w=280',
}}
/>
)}
{/* <h5>CALCULUS</h5> */}
</div>
<div className="contentbox">
<div className="search-content">
<a
href={
res.model === 'Activity'
? // eslint-disable-next-line max-len
`/activity/${res.id}/preview`
: res.model === 'Playlist'
? `/playlist/${res.id}/preview/lti`
: `/project/${res.id}/preview`
}
target="_blank"
rel="noreferrer"
>
<h2>{res.title || res.name}</h2>
</a>
<ul>
{res.user && (
<li>
by <span>{res.user.first_name}</span>
</li>
)}
<li>
by <span>{res?.team_name ? `(T) ${res?.team_name}` : res.user.first_name}</span>
</li>
{/* <li>
Member Rating{" "}
<span className="type">Project</span>
</li> */}
{res.model === 'Project' && permission?.Project?.includes('project:favorite') && (
<div
className={`btn-fav ${res.favored}`}
onClick={(e) => {
if (e.target.classList.contains('true')) {
e.target.classList.remove('true');
e.target.classList.add('false');
} else {
e.target.classList.add('true');
}
dispatch(addProjectFav(res.id));
}}
>
<FontAwesomeIcon
className="mr-2"
icon="star"
style={{
pointerEvents: 'none',
}}
/>{' '}
Favorite
</div>
)}
</ul>
<p>{res.description}</p>
</div>
{(permission?.Project?.includes('project:clone') || permission?.Project?.includes('project:publish')) && res.model === 'Project' && (
<Dropdown className="playlist-dropdown check">
<Dropdown.Toggle>
<FontAwesomeIcon icon="ellipsis-v" />
</Dropdown.Toggle>
<Dropdown.Menu>
{permission?.Project?.includes('project:clone') && (
<Dropdown.Item
onClick={() => {
Swal.fire({
html: `You have selected <strong>${res.title}</strong> ${res.model}<br>Do you want to continue ?`,
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Ok',
}).then((result) => {
if (result.value) {
cloneProject(res.id);
}
});
}}
>
<FontAwesomeIcon className="mr-2" icon="clone" />
Duplicate
</Dropdown.Item>
)}
{permission?.Project?.includes('project:publish') && (
<li
className="dropdown-submenu send"
style={{
display: projectVisibilityLMS[0] || currentOrganization?.gcr_project_visibility ? 'block' : 'none',
}}
>
<a tabIndex="-1">
<FontAwesomeIcon icon="newspaper" className="mr-2" />
Publish
</a>
<ul className="dropdown-menu check">
{currentOrganization?.gcr_project_visibility && (
// eslint-disable-next-line react/jsx-indent
<li
onClick={() => {
setShow(true);
getProjectId(res.id);
setSelectedProjectId(res.id);
dispatch(googleShare(false));
}}
>
<a>Google Classroom</a>
</li>
)}
{allLms.shareVendors &&
allLms.shareVendors.map(
(data) =>
data?.project_visibility && (
<li>
<a
onClick={async () => {
const allPlaylist = await dispatch(lmsPlaylist(res.id));
if (allPlaylist) {
dispatch(
getProjectCourseFromLMS(data.lms_name.toLowerCase(), data.id, res.id, allPlaylist.playlists, data.lms_url)
);
}
}}
>
{data.site_name}
</a>
</li>
)
)}
</ul>
</li>
)}
</Dropdown.Menu>
</Dropdown>
)}
</div>
{permission?.Playlist?.includes('playlist:duplicate') && res.model === 'Playlist' && (
<Dropdown className="playlist-dropdown check">
<Dropdown.Toggle>
<FontAwesomeIcon icon="ellipsis-v" />
</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item
onClick={() => {
setModalShow(true);
setClone(res);
}}
>
<FontAwesomeIcon className="mr-2" icon="clone" />
Duplicate
</Dropdown.Item>
{permission?.Playlist?.includes('playlist:publish') && (
<ShareLink
playlistId={res.id}
projectId={res.project_id}
setProjectId={setProjectId}
handleShow={handleShow}
gcr_playlist_visibility={currentOrganization.gcr_playlist_visibility}
setProjectPlaylistId={setProjectPlaylistId}
/>
)}
</Dropdown.Menu>
</Dropdown>
)}
{permission?.Activity?.includes('activity:duplicate') && res.model === 'Activity' && (
<Dropdown className="playlist-dropdown check">
<Dropdown.Toggle>
<FontAwesomeIcon icon="ellipsis-v" />
</Dropdown.Toggle>
<Dropdown.Menu>
<>
<Dropdown.Item
onClick={() => {
setModalShow(true);
setClone(res);
}}
>
<FontAwesomeIcon className="mr-2" icon="clone" />
Duplicate
</Dropdown.Item>
{permission?.Activity?.includes('activity:share') && allLms?.length !== 0 && (
<li
className="dropdown-submenu send"
style={{
display: activityVisibilityLMS.includes(true) && safariMontageActivity.includes(true) ? 'block' : 'none',
}}
>
<a tabIndex="-1" className="dropdown-item">
<FontAwesomeIcon icon="newspaper" className="mr-2" />
Publish
</a>
<ul className="dropdown-menu check">
{allLms?.shareVendors.map((data) =>
data.lms_name !== 'safarimontage' ? null : (
<>
{data?.activity_visibility && (
<li>
<a
onClick={() => {
dispatch(loadSafariMontagePublishToolAction(res.project_id, res.playlist_id, res.id, data.id));
}}
>
{data.site_name}
</a>
</li>
)}
</>
)
)}
<Modal
dialogClassName="safari-modal"
show={safariMontagePublishTool}
onHide={() => dispatch(closeSafariMontageToolAction())}
aria-labelledby="example-modal-sizes-title-lg"
>
<Modal.Header closeButton>
<Modal.Title id="example-modal-sizes-title-lg">Safari Montage</Modal.Title>
</Modal.Header>
<Modal.Body>
<iframe title="Safari Montage" src={`data:text/html;charset=utf-8,${safariMontagePublishTool}`} />
</Modal.Body>
</Modal>
</ul>
</li>
)}
</>
</Dropdown.Menu>
</Dropdown>
)}
</div>
))
) : (
<div className="box">No result found !</div>
)}
</div>
</Tab>
)}
<Tab eventKey="projects" title={!!search && !!meta.projects ? `project (${meta.projects})` : 'project (0)'}>
<div className="results_search">
{!!search && search.length > 0 ? (
search.map((res) => (
<>
{res.model === 'Project' && (
<div className="box">
<div className="imgbox">
{res.thumb_url ? (
<div
style={{
backgroundImage: res.thumb_url.includes('pexels.com') ? `url(${res.thumb_url})` : `url(${global.config.resourceUrl}${res.thumb_url})`,
}}
/>
) : (
<div
style={{
// eslint-disable-next-line max-len
backgroundImage:
'https://images.pexels.com/photos/593158/pexels-photo-593158.jpeg?auto=compress&cs=tinysrgb&dpr=1&fit=crop&h=200&w=280',
}}
/>
)}
{/* <h5>CALCULUS</h5> */}
</div>
<div className="contentbox">
<div className="search-content">
<a
href={
res.model === 'Activity'
? `/activity/${res.id}/preview`
: res.model === 'Playlist'
? `/playlist/${res.id}/preview/lti`
: `/project/${res.id}/preview`
}
target="_blank"
rel="noreferrer"
>
<h2>{res.title || res.name}</h2>
</a>
<ul>
{res.user && (
<li>
by <span>{res?.team_name ? `(T) ${res?.team_name}` : res.user.first_name}</span>
</li>
)}
<li>
Type <span className="type">{res.model}</span>
</li>
{/* <li>
Member Rating{" "}
<span className="type">Project</span>
</li> */}
{permission?.Project?.includes('project:favorite') && (
<div
className={`btn-fav ${res.favored}`}
onClick={(e) => {
if (e.target.classList.contains(' true')) {
e.target.classList.remove('true');
} else {
e.target.classList.add('true');
}
dispatch(addProjectFav(res.id));
}}
>
<FontAwesomeIcon className="mr-2" icon="star" />
Favorite
</div>
)}
</ul>
<p>{res.description}</p>
</div>
{(permission?.Project?.includes('project:clone') || permission?.Project?.includes('project:publish')) && (
<Dropdown className="playlist-dropdown check">
<Dropdown.Toggle>
<FontAwesomeIcon icon="ellipsis-v" />
</Dropdown.Toggle>
<Dropdown.Menu>
{permission?.Project?.includes('project:clone') && (
<Dropdown.Item
onClick={() => {
Swal.fire({
html: `You have selected <strong>${res.title}</strong> ${res.model}<br>Do you want to continue ?`,
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Ok',
}).then((result) => {
if (result.value) {
cloneProject(res.id);
}
});
}}
>
<FontAwesomeIcon className="mr-2" icon="clone" />
Duplicate
</Dropdown.Item>
)}
{permission?.Project?.includes('project:publish') && (
<li
className="dropdown-submenu send"
style={{
display: projectVisibilityLMS[0] || currentOrganization?.gcr_project_visibility ? 'block' : 'none',
}}
>
<a tabIndex="-1">
<FontAwesomeIcon icon="newspaper" className="mr-2" />
Publish
</a>
<ul className="dropdown-menu check">
{currentOrganization.gcr_project_visibility && (
<li
onClick={() => {
setShow(true);
getProjectId(res.id);
setSelectedProjectId(res.id);
dispatch(googleShare(false));
}}
>
<a>Google Classroom</a>
</li>
)}
{allLms.shareVendors &&
allLms.shareVendors.map(
(data) =>
data.project_visibility && (
<li>
<a
onClick={async () => {
const allPlaylist = await dispatch(lmsPlaylist(res.id));
if (allPlaylist) {
dispatch(
getProjectCourseFromLMS(data.lms_name.toLowerCase(), data.id, res.id, allPlaylist.playlists, data.lms_url)
);
}
}}
>
{data.site_name}
</a>
</li>
)
)}
</ul>
</li>
)}
{fromTeam && (
<Dropdown.Item
onClick={() => {
if (selectProject.length === 0 && fromTeam) {
setSelectProject([res.id]);
} else if (selectProject[0] === res.id && fromTeam) {
setSelectProject([]);
} else {
Swal.fire({
icon: 'warning',
title: 'Action Prohibited',
text: 'You are only allowed to select 1 project.',
});
}
}}
>
<img src={teamicon} alt="teams_logo" className="teams-logo" />
{selectProject.includes(res.id) ? 'Remove from ' : 'Add to '}
team
</Dropdown.Item>
)}
</Dropdown.Menu>
</Dropdown>
)}
</div>
</div>
)}
</>
))
) : (
<div className="box">No result found !</div>
)}
</div>
</Tab>
{!fromTeam && (
<Tab eventKey="playlists" title={!!search && !!meta.playlists ? `playlist (${meta.playlists})` : 'playlist (0)'}>
<div className="results_search">
{!!search && search.length > 0 ? (
search.map((res) => (
<>
{res.model === 'Playlist' && (
<div className="box">
<div className="imgbox">
{res.thumb_url ? (
<div
style={{
backgroundImage: res.thumb_url.includes('pexels.com') ? `url(${res.thumb_url})` : `url(${global.config.resourceUrl}${res.thumb_url})`,
}}
/>
) : (
<div
style={{
// eslint-disable-next-line max-len
backgroundImage:
'https://images.pexels.com/photos/593158/pexels-photo-593158.jpeg?auto=compress&cs=tinysrgb&dpr=1&fit=crop&h=200&w=280',
}}
/>
)}
{/* <h5>CALCULUS</h5> */}
</div>
<div className="contentbox">
<div className="search-content">
<a
href={
res.model === 'Activity'
? // eslint-disable-next-line max-len
`/activity/${res.id}/preview`
: res.model === 'Playlist'
? `/playlist/${res.id}/preview/lti`
: `/project/${res.id}/preview`
}
target="_blank"
rel="noreferrer"
>
<h2>{res.title || res.name}</h2>
</a>
<ul>
{res.user && (
<li>
by <span>{res.user.first_name}</span>
</li>
)}
<li>
Type <span className="type">{res.model}</span>
</li>
{/* <li>
Member Rating{" "}
<span className="type">Project</span>
</li> */}
</ul>
<p>{res.description}</p>
</div>
{permission?.Playlist?.includes('playlist:duplicate') && (
<Dropdown className="playlist-dropdown check">
<Dropdown.Toggle>
<FontAwesomeIcon icon="ellipsis-v" />
</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item
onClick={() => {
setModalShow(true);
setClone(res);
}}
>
<FontAwesomeIcon className="mr-2" icon="clone" />
Duplicate
</Dropdown.Item>
{permission?.Playlist?.includes('playlist:publish') && (
<ShareLink
playlistId={res.id}
projectId={res.project_id}
setProjectId={setSelectedProjectId}
handleShow={handleShow}
gcr_playlist_visibility={currentOrganization.gcr_playlist_visibility}
setProjectPlaylistId={setSelectedProjectPlaylistId}
/>
)}
</Dropdown.Menu>
</Dropdown>
)}
</div>
</div>
)}
</>
))
) : (
<div className="box">No result found !</div>
)}
</div>
</Tab>
)}
{!fromTeam && (
<Tab eventKey="activities" title={!!search && !!meta.activities ? `activity (${meta.activities})` : 'activity (0)'}>
<div className="content">
<div className="results_search">
{!!search && search.length > 0 ? (
search.map((res) => (
<>
{res.model === 'Activity' && (
<div className="box">
<div className="imgbox">
{res.thumb_url ? (
<div
style={{
backgroundImage: res.thumb_url.includes('pexels.com')
? `url(${res.thumb_url})`
: `url(${global.config.resourceUrl}${res.thumb_url})`,
}}
/>
) : (
<div
style={{
// eslint-disable-next-line max-len
backgroundImage:
'https://images.pexels.com/photos/593158/pexels-photo-593158.jpeg?auto=compress&cs=tinysrgb&dpr=1&fit=crop&h=200&w=280',
}}
/>
)}
{/* <h5>CALCULUS</h5> */}
</div>
<div className="contentbox">
<div className="search-content">
<a
href={
res.model === 'Activity'
? `/activity/${res.id}/preview`
: res.model === 'Playlist'
? `/playlist/${res.id}/preview/lti`
: `/project/${res.id}/preview`
}
target="_blank"
rel="noreferrer"
>
<h2>{res.title || res.name}</h2>
</a>
<ul>
{res.user && (
<li>
by <span>{res.user.first_name}</span>
</li>
)}
<li>
Type <span className="type">{res.model}</span>
</li>
{/* <li>
Member Rating{" "}
<span className="type">Project</span>
</li> */}
</ul>
<p>{res.description}</p>
</div>
{permission?.Activity?.includes('activity:duplicate') && res.model === 'Activity' && (
<Dropdown className="playlist-dropdown check">
<Dropdown.Toggle>
<FontAwesomeIcon icon="ellipsis-v" />
</Dropdown.Toggle>
<Dropdown.Menu>
<>
<Dropdown.Item
onClick={() => {
setModalShow(true);
setClone(res);
}}
>
<FontAwesomeIcon className="mr-2" icon="clone" />
Duplicate
</Dropdown.Item>
{permission?.Activity?.includes('activity:share') && allLms?.length !== 0 && (
<li
className="dropdown-submenu send"
style={{
display: activityVisibilityLMS.includes(true) && safariMontageActivity.includes(true) ? 'block' : 'none',
}}
>
<a tabIndex="-1" className="dropdown-item">
<FontAwesomeIcon icon="newspaper" className="mr-2" />
Publish
</a>
<ul className="dropdown-menu check">
{allLms?.shareVendors.map((data) => {
if (data.lms_name !== 'safarimontage') return false;
return (
data?.activity_visibility && (
<li>
<a
onClick={() => {
dispatch(loadSafariMontagePublishToolAction(res.project_id, res.playlist_id, res.id, data.id));
}}
>
{data.site_name}
</a>
</li>
)
);
})}
<Modal
dialogClassName="safari-modal"
show={safariMontagePublishTool}
onHide={() => dispatch(closeSafariMontageToolAction())}
aria-labelledby="example-modal-sizes-title-lg"
>
<Modal.Header closeButton>
<Modal.Title id="example-modal-sizes-title-lg">Safari Montage</Modal.Title>
</Modal.Header>
<Modal.Body>
<iframe title="Safari Montage" src={`data:text/html;charset=utf-8,${safariMontagePublishTool}`} />
</Modal.Body>
</Modal>
</ul>
</li>
)}
</>
</Dropdown.Menu>
</Dropdown>
)}
</div>
</div>
)}
</>
))
) : (
<div className="box">No result found !</div>
)}
</div>
</div>
</Tab>
)}
</Tabs>
{totalCount > 20 && (
<Pagination
activePage={activePage}
itemsCountPerPage={20}
totalItemsCount={totalCount > 10000 ? 10000 : totalCount}
pageRangeDisplayed={8}
onChange={async (e) => {
setActivePage(e);
if (activeModel === 'total') {
const searchData = {
phrase: searchQueries.trim(),
from: e * 20 - 20,
size: 20,
type: searchType,
subjectArray: activeSubject || undefined,
gradeArray: activeEducation || undefined,
authorTagsArray: activeAuthorTag || undefined,
standardArray: activeType || undefined,
author: authorName || undefined,
};
Swal.fire({
title: 'Loading...',
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
await dispatch(simpleSearchAction(searchData));
Swal.close();
} else {
const searchData = {
phrase: searchQueries.trim(),
from: e * 20 - 20,
size: 20,
type: searchType,
model: activeModel,
subjectArray: activeSubject || undefined,
gradeArray: activeEducation || undefined,
authorTagsArray: activeAuthorTag || undefined,
standardArray: activeType || undefined,
author: authorName || undefined,
};
Swal.fire({
title: 'Loading...',
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
},
});
await dispatch(simpleSearchAction(searchData));
Swal.close();
}
}}
itemClass="page-item"
linkClass="page-link"
/>
)}
</div>
</div>
</div>
) : (
<Alert variant="danger">You are not authorized to view this page!</Alert>
)}
</div>
</div>
<GoogleModel
projectId={selectedProjectId}
playlistId={selectedProjectPlaylistId}
activityId={0}
show={show} // {props.show}
onHide={() => {
setShow(false);
}}
/>
</div>
<Footer />
</>
);
}
Example #15
Source File: mygroups.js From SpotifyParty with MIT License | 4 votes |
render() {
return (
<div className="fullsize">
{ this.state.user !== null ?
<div className="fullsize">
<Accordion>
<Accordion.Toggle as={Card.Header} eventKey={1}>
Create Group
</Accordion.Toggle>
<Accordion.Collapse eventKey={1}>
<Card.Body>
<form onSubmit={this.handleAddGroupSubmit}>
<Form>
<Form.Group>
<Form.Control className="input" onChange={this.handleInputChange} name="newGroup" type="text" placeholder="Enter name" value={this.state.newGroup}/>
</Form.Group>
<Button className="btnAddPlaylist" variant="success" type="submit">
Create
</Button>
</Form>
</form>
</Card.Body>
</Accordion.Collapse>
</Accordion>
{ this.state.groups !== null ?
<Accordion defaultActiveKey="0">
{ this.state.groups.map((group, index) =>
{
return (
<Card>
<Accordion.Toggle as={"button"} className="btn btn-secondary" onClick={this.handleSelectedGroup} value={group.groupname} eventKey={index}>
{group.groupname}
</Accordion.Toggle>
<Accordion.Collapse eventKey={index}>
<Card.Body>
<h4>Members</h4>
<ul id="MemberList">
{group.members.map((member, i) => {
var displayName = member.split("@")[0];
return(<h6>{displayName}</h6>)
})
}
</ul>
<Accordion>
<Accordion.Toggle as={Button} eventKey={3}>
Add Member
</Accordion.Toggle>
<Accordion.Collapse eventKey={3}>
<Card.Body>
<form onSubmit={this.handleAddMemberSubmit}>
<Form role="form">
<Form.Group>
<Form.Control name="newMemberGroup" type="hidden" value={this.state.groups[index].groupname}/>
<Form.Control onChange={this.handleInputChange} name="newMember" type="email" placeholder="Enter email" value={this.state.newMember}/>
<Button className="btnAddPlaylist" variant="success" type="submit">
Add
</Button>
</Form.Group>
</Form>
</form>
</Card.Body>
</Accordion.Collapse>
</Accordion>
<h4 className="labelPlaylist">Playlists</h4>
<div id="fixedspacing">
<p></p>
</div>
<ToggleButtonGroup type="radio" name="playlists" vertical onChange={this.handleSelectedPlaylist}>
{group.playlists.map((playlist, i) => {
return(
<ToggleButton id="playlistbtns" value={[this.state.groups[index].playlists[i],this.state.groups[index].groupname]} >{playlist.name}</ToggleButton>
)
})
}
</ToggleButtonGroup>
<div id="fixedspacing">
<p></p>
</div>
<Accordion>
<Accordion.Toggle as={Button} eventKey={2}>
Create Playlist
</Accordion.Toggle>
<Accordion.Collapse eventKey={2}>
<Card.Body>
<form onSubmit={this.handleAddPlaylistSubmit}>
<Form role="form">
<Form.Group>
<Form.Control name="newPlaylistGroup" type="hidden" value={this.state.groups[index].groupname}/>
<Form.Control onChange={this.handleInputChange} name="newPlaylist" type="text" placeholder="Enter name" value={this.state.newPlaylist}/>
<Button className="btnAddPlaylist" variant="success" type="submit">
Create
</Button>
</Form.Group>
</Form>
</form>
</Card.Body>
</Accordion.Collapse>
</Accordion>
</Card.Body>
</Accordion.Collapse>
</Card>
)
})
}
</Accordion>
:
<div>
</div>
}
</div>
:
<h4>Not logged in</h4>
}
</div>
);
}